真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Android音視頻深入十九使用ijkplayer做個視頻播放器(附源碼下載)

項目地址
https://github.com/979451341/Myijkplayer

創(chuàng)新互聯(lián)公司成立以來不斷整合自身及行業(yè)資源、不斷突破觀念以使企業(yè)策略得到完善和成熟,建立了一套“以技術(shù)為基點,以客戶需求中心、市場為導(dǎo)向”的快速反應(yīng)體系。對公司的主營項目,如中高端企業(yè)網(wǎng)站企劃 / 設(shè)計、行業(yè) / 企業(yè)門戶設(shè)計推廣、行業(yè)門戶平臺運營、手機APP定制開發(fā)手機網(wǎng)站制作、微信網(wǎng)站制作、軟件開發(fā)、德陽機房服務(wù)器托管等實行標(biāo)準(zhǔn)化操作,讓客戶可以直觀的預(yù)知到從創(chuàng)新互聯(lián)公司可以獲得的服務(wù)效果。

前段時候我覺得FFmpeg做個視頻播放器好難,雖然播放上沒問題,但暫停還有通過拖動進度條來設(shè)置播放進度,這些都即便做得到,可以那個延緩。。。。。

現(xiàn)在學(xué)習(xí)一下目前移動端最知名的視頻播放器的框架ijkplayer,這個框架他是基于FFmpeg、SDL、還有安卓原生API MediaCodec之類的。他是沒有播放界面的,這個需要我們?nèi)プ?,所以這個里我就做個基于ijkplayer的視頻播放器,隨便淺顯的說一下ijkplayer的源碼,關(guān)于ijkplayer的源碼以后會專門出一篇博客說一下。

1.首先了解一下ijkplayer咋用

我這里引入ijkplayer是通過添加依賴

implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'

implementation 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'

implementation 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'

然后說說ijkplayer是如何播放視頻的

ijkplayer每一次播放視頻都是通過創(chuàng)建Mediaplayer,然后賦值到一個接口類上,這里他創(chuàng)建的時候能夠挑選解碼的類型,是因為基于安卓原生API MediaCodec的話是硬解,速度快、兼容差,如果是基于FFmpeg則是軟解,速度慢、兼容好,不過這個兼容問題,因為我們在引入依賴的時候把各個處理器相應(yīng)的依賴,所以可以使用硬解,兼容問題基本都是手機處理器不同產(chǎn)生的。

    IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();
    ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);

// //開啟硬解碼
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
IMediaPlayer mMediaPlayer = null;
mMediaPlayer = ijkMediaPlayer;

關(guān)于IjkMediaPlayer的源碼我只貼出一個函數(shù)的,從下面幾個loadLibrary看出來,他還是基于FFmpeg、SDL底層實現(xiàn)的。

public static void loadLibrariesOnce(IjkLibLoader libLoader) {
    Class var1 = IjkMediaPlayer.class;
    synchronized(IjkMediaPlayer.class) {
        if(!mIsLibLoaded) {
            if(libLoader == null) {
                libLoader = sLocalLibLoader;
            }

            libLoader.loadLibrary("ijkffmpeg");
            libLoader.loadLibrary("ijksdl");
            libLoader.loadLibrary("ijkplayer");
            mIsLibLoaded = true;
        }

    }
}

好了,回到那個接口類的IMediaPlayer,源碼不多貼出來看一下,通過這些接口函數(shù)我們都可以知道這個ijkplayer如何使用我們都有了一個底,什么setDataSource、setDisplay,設(shè)置播放源、設(shè)置播放的屏幕信息。還有start、stop、pause,視頻播放的開始、停止、暫停,還有一大堆的接口,這些都是為了監(jiān)聽播放器的狀態(tài)

public interface IMediaPlayer {
。。。。。。

void setDisplay(SurfaceHolder var1);

void setDataSource(Context var1, Uri var2) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;

@TargetApi(14)
void setDataSource(Context var1, Uri var2, Map var3) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;

void setDataSource(FileDescriptor var1) throws IOException, IllegalArgumentException, IllegalStateException;

void setDataSource(String var1) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;

String getDataSource();

void prepareAsync() throws IllegalStateException;

void start() throws IllegalStateException;

void stop() throws IllegalStateException;

void pause() throws IllegalStateException;

void setScreenOnWhilePlaying(boolean var1);

int getVideoWidth();

int getVideoHeight();

boolean isPlaying();

void seekTo(long var1) throws IllegalStateException;

long getCurrentPosition();

long getDuration();

void release();

void reset();

void setVolume(float var1, float var2);

int getAudioSessionId();

MediaInfo getMediaInfo();

/** @deprecated */
@Deprecated
void setLogEnabled(boolean var1);

/** @deprecated */
@Deprecated
boolean isPlayable();

void setOnPreparedListener(IMediaPlayer.OnPreparedListener var1);

void setOnCompletionListener(IMediaPlayer.OnCompletionListener var1);

void setOnBufferingUpdateListener(IMediaPlayer.OnBufferingUpdateListener var1);

void setOnSeekCompleteListener(IMediaPlayer.OnSeekCompleteListener var1);

void setOnVideoSizeChangedListener(IMediaPlayer.OnVideoSizeChangedListener var1);

void setOnErrorListener(IMediaPlayer.OnErrorListener var1);

void setOnInfoListener(IMediaPlayer.OnInfoListener var1);

void setOnTimedTextListener(IMediaPlayer.OnTimedTextListener var1);

void setAudioStreamType(int var1);

/** @deprecated */
@Deprecated
void setKeepInBackground(boolean var1);

int getVideoSarNum();

int getVideoSarDen();

/** @deprecated */
@Deprecated
void setWakeMode(Context var1, int var2);

void setLooping(boolean var1);

boolean isLooping();

ITrackInfo[] getTrackInfo();

void setSurface(Surface var1);

void setDataSource(IMediaDataSource var1);

public interface OnTimedTextListener {
    void onTimedText(IMediaPlayer var1, IjkTimedText var2);
}

public interface OnInfoListener {
    boolean onInfo(IMediaPlayer var1, int var2, int var3);
}

public interface OnErrorListener {
    boolean onError(IMediaPlayer var1, int var2, int var3);
}

public interface OnVideoSizeChangedListener {
    void onVideoSizeChanged(IMediaPlayer var1, int var2, int var3, int var4, int var5);
}

public interface OnSeekCompleteListener {
    void onSeekComplete(IMediaPlayer var1);
}

public interface OnBufferingUpdateListener {
    void onBufferingUpdate(IMediaPlayer var1, int var2);
}

public interface OnCompletionListener {
    void onCompletion(IMediaPlayer var1);
}

public interface OnPreparedListener {
    void onPrepared(IMediaPlayer var1);
}

}

2.寫界面

全屏播放,潛入式

//正真的全屏,隱藏了狀態(tài)欄、AtionBar、導(dǎo)航欄
@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && Build.VERSION.SDK_INT >= 19) {
        View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }
}

然后上下兩個欄目,負責(zé)一些播放器的控制,頂部負責(zé)設(shè)置返回、設(shè)置按鈕,底部需要設(shè)置播放/暫停按鈕、播放進度條、停止按鈕





關(guān)于上下兩個欄目在用戶觀看視頻時需要隱藏,在用戶點擊屏幕則顯示兩個欄目,供用戶使用
這個則是需要通過計時器來完成記錄目前距離上一次用戶點擊屏幕的時間,如果視頻超過3秒,則隱藏欄目,如果點擊屏幕則恢復(fù),關(guān)于隱藏和恢復(fù)使用Animation來完成。

    timer = new Timer();
    timerTask = new TimerTask() {
        @Override
        public void run() {
            long t = System.currentTimeMillis();
            if (t - time > 3000 && menu_visible) {
                time = t;
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.move_bottom);
                        rl_bottom.startAnimation(animation);
                        Animation animation_top = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.move_top);
                        rl_top.startAnimation(animation_top);
                        menu_visible = false;
                    }
                });
            }

        }
    };

還需要加載框,這個在視頻加載完的接口回調(diào)里隱藏他

    

3.播放實現(xiàn)

這里我是使用了一個另一個博主封裝的ijkplayer的類

說一下這個類的運行過程

一開始創(chuàng)建MediaPlayer做一些配置,賦值給一個接口類,并且暴露了接口

    IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();
    ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);

// //開啟硬解碼
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);

    mMediaPlayer = ijkMediaPlayer;

    if (listener != null) {
        mMediaPlayer.setOnPreparedListener(listener);
        mMediaPlayer.setOnInfoListener(listener);
        mMediaPlayer.setOnSeekCompleteListener(listener);
        mMediaPlayer.setOnBufferingUpdateListener(listener);
        mMediaPlayer.setOnErrorListener(listener);
    }

然后設(shè)置播放源,這個播放源能夠是本地視頻路徑、網(wǎng)絡(luò)視頻url、還可以是網(wǎng)絡(luò)RTMP推流url,還要講SurfaceView的配置信息給他

    try {
        mMediaPlayer.setDataSource(mPath);
    } catch (IOException e) {
        e.printStackTrace();
    }
    //給mediaPlayer設(shè)置視圖
    mMediaPlayer.setDisplay(surfaceView.getHolder());

    mMediaPlayer.prepareAsync();

想開始播放就調(diào)用IMediaPlayer的那些控制函數(shù)

public void start() {
    if (mMediaPlayer != null) {
        mMediaPlayer.start();
    }
}

還有關(guān)于activity的生命周期控制,其中native_profileEnd就相當(dāng)于很智能的暫停,當(dāng)屏幕回的時候就繼續(xù)播放視頻。

@Override
protected void onStop() {
    IjkMediaPlayer.native_profileEnd();
    handler.removeCallbacksAndMessages(null);
    super.onStop();

}

結(jié)束Activity的時候就停止播放視頻并釋放資源

@Override
protected void onDestroy() {
    if (ijkPlayer != null) {
        ijkPlayer.stop();
        ijkPlayer.release();
        ijkPlayer = null;
    }

    super.onDestroy();
}

最后還有播放進度,我這里是通過handler自己調(diào)用自己循環(huán)更新播放時間顯示和進度條

    handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REFRESH:
                    if (ijkPlayer.isPlaying()) {
                        refresh();
                        handler.sendEmptyMessageDelayed(MSG_REFRESH, 1000);
                    }

                    break;
            }

        }
    };

private void refresh() {
    long current = ijkPlayer.getCurrentPosition() / 1000;
    long duration = ijkPlayer.getDuration() / 1000;
    Log.v("zzw", current + " " + duration);
    long current_second = current % 60;
    long current_minute = current / 60;
    long total_second = duration % 60;
    long total_minute = duration / 60;
    String time = current_minute + ":" + current_second + "/" + total_minute + ":" + total_second;
    tvTime.setText(time);
    if(duration != 0){
        seekBar.setProgress((int) (current * 100 / duration));
    }

}

在用戶拖動進度條的時候取消handler發(fā)送消息,拖動結(jié)束再接續(xù)更新播放進度

    seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            //進度改變
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            //開始拖動

            handler.removeCallbacksAndMessages(null);

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            //停止拖動
            ijkPlayer.seekTo(ijkPlayer.getDuration() * seekBar.getProgress() / 100);
            handler.sendEmptyMessageDelayed(MSG_REFRESH, 100);
        }
    });

關(guān)于播放網(wǎng)絡(luò)視頻和網(wǎng)絡(luò)RTMP推流,播放本身沒問題就是不能獲取視頻時長和視頻當(dāng)前時間,不過暫停和停止還有效。

還有就是如果想要重新播放需要重新setVideoPath然后start

看看效果
本地視頻播放

播放RTMP推流

播放網(wǎng)絡(luò)視頻

ijkplayer的使用看起來是不是很簡單,但是還沒有實現(xiàn)小窗口和全屏之間的切換。。。。。。這兩天我再看看ijkplayer,再和各位說說
博客首發(fā)地址
http://blog.csdn.net/z979451341


當(dāng)前題目:Android音視頻深入十九使用ijkplayer做個視頻播放器(附源碼下載)
文章源于:http://weahome.cn/article/pdogdd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部