天天看點

Android基礎學習總結(十六)——基于ijkplayer封裝支援簡單界面UI定制的視訊播放器前言簡介特性快速開始配置生命周期方法更多UI樣式的設定自定義視訊界面播放器PlayerView對象ijkplayer封裝的視訊播放資訊傳回碼監聽

前言

項目開發中遇到需要解析播放m3u8視訊流的情況,但是原生的PlayerView非常慢,使用起來複雜,不适合上手,這裡找到一款ijkplayer是Bilibili基于ffmpeg開發并開源的輕量級視訊播放器,支援播放本地網絡視訊,也支援流媒體播放。支援Android&iOS。

這裡感謝jjdxmashl基于ijkplayer封裝了支援簡單界面UI定制的視訊播放器,操作簡單實用,推薦大家使用。

簡介

目前項目是基于ijkplayer項目進行的播放器界面UI封裝。

是一個适用于 Android 的 RTMP 直播推流 SDK,可高度定制化和二次開發。特色是同時支援 H.264 軟編/硬編和 AAC 軟編/硬編。主要是支援RIMP、HLS、MP4、M4A等視訊格式的播放。

作者項目位址:http://www.github.com/jjdxmashl/jjdxm_ijkplayer

作者簡書位址:http://www.jianshu.com/p/6c938df18413

特性

  • 基于ijkplayer封裝的視訊播放器界面,支援 RTMP , HLS (http & https) , MP4,M4A 等;
  • 可根據需求去定制部分界面樣式;
  • 常用的手勢操作左邊上下亮度,右邊上下聲音,左右滑動播放進度調整;
  • 支援多種分辨率流的切換播放;
  • 播放出錯嘗試重連;
  • 界面裁剪顯示樣式;

快速開始

step1:導入依賴

該項目已經打包到jcenter中心了,可以通過compile指令直接依賴,在主程式目錄build.gradle中,添加以下代碼:

compile ‘com.dou361.ijkplayer:jjdxm-ijkplayer:’ 
           

step2:簡單的播放器實作

setContentView(R.layout.simple_player_view_player);
String url = "http://9890.vod.myqcloud.com/9890_9c1fa3e2aea011e59fc841df10c92278.f20.mp4";
player = new PlayerView(this)
        .setTitle("什麼")
        .setScaleType(PlayStateParams.fitparent)
        .hideMenu(true)
        .forbidTouch(false)
        .showThumbnail(new OnShowThumbnailListener() {
            @Override
            public void onShowThumbnail(ImageView ivThumbnail) {
                Glide.with(mContext)
                        .load("http://pic2.nipic.com/20090413/406638_125424003_2.jpg")
                        .placeholder(R.color.cl_default)
                        .error(R.color.cl_error)
                        .into(ivThumbnail);
            }
        })
        .setPlaySource(url)
        .startPlay();
           

step3:多種不同的分辨率流的播放器實作

在布局中使用simple_player_view_player.xml布局

<include
    layout="@layout/simple_player_view_player"
    android:layout_width="match_parent"
    android:layout_height="180dp"/>
           

代碼中建立一個播放器對象

/**播放資源*/
ist<VideoijkBean> list = new ArrayList<VideoijkBean>();
String url1 = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4";
String url2 = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f30.mp4";
VideoijkBean m1 = new VideoijkBean();
m1.setStream("标清");
m1.setUrl(url1);
VideoijkBean m2 = new VideoijkBean();
m2.setStream("高清");
m2.setUrl(url2);
list.add(m1);
list.add(m2);
/**播放器*/
player = new PlayerView(this)
            .setTitle("什麼")
            .setScaleType(PlayStateParams.fitparent)
            .hideMenu(true)
            .forbidTouch(false)
            .showThumbnail(new OnShowThumbnailListener() {
                @Override
                public void onShowThumbnail(ImageView ivThumbnail) {
                    /**加載前顯示的縮略圖*/
                    Glide.with(mContext)
                            .load("http://pic2.nipic.com/20090413/406638_125424003_2.jpg")
                            .placeholder(R.color.cl_default)
                            .error(R.color.cl_error)
                            .into(ivThumbnail);
                }
            })
            .setPlaySource(list)
            .startPlay();
           

配置生命周期方法

為了讓播放器同步Activity生命周期,建議以下方法都去配置,注釋的代碼,主要作用是播放時螢幕常亮和暫停其它媒體的播放。

@Override
protected void onPause() {
    super.onPause();
    if (player != null) {
        player.onPause();
    }
    /**demo的内容,恢複系統其它媒體的狀态*/
    //MediaUtils.muteAudioFocus(mContext, true);
}

@Override
protected void onResume() {
    super.onResume();
    if (player != null) {
        player.onResume();
    }
    /**demo的内容,暫停系統其它媒體的狀态*/
    MediaUtils.muteAudioFocus(mContext, false);
    /**demo的内容,激活裝置常亮狀态*/
    //if (wakeLock != null) {
    //    wakeLock.acquire();
    //}
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (player != null) {
        player.onDestroy();
    }
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (player != null) {
        player.onConfigurationChanged(newConfig);
    }
}

@Override
public void onBackPressed() {
    if (player != null && player.onBackPressed()) {
        return;
    }
    super.onBackPressed();
    /**demo的内容,恢複裝置亮度狀态*/
    //if (wakeLock != null) {
    //    wakeLock.release();
    //}
}
           

更多UI樣式的設定

1.視訊界面裁剪設定

可通過方法setScaleType(int type)去設定

  • PlayStateParams.fitParent:可能會剪裁,保持原視訊的大小,顯示在中心,當原視訊的大小超過view的大小超過部分裁剪處理
  • PlayStateParams.fillParent:可能會剪裁,等比例放大視訊,直到填滿View為止,超過View的部分作裁剪處理
  • PlayStateParams.wrapcontent:将視訊的内容完整居中顯示,如果視訊大于view,則按比例縮視訊直到完全顯示在view中
  • PlayStateParams.fitXY:不剪裁,非等比例拉伸畫面填滿整個View
  • PlayStateParams.f16_9:不剪裁,非等比例拉伸畫面到16:9,并完全顯示在View中
  • PlayStateParams.f4_3:不剪裁,非等比例拉伸畫面到4:3,并完全顯示在View中

2.播放器底部bar播放進度條樣式定制

預設的進度樣式是豎屏為上下樣式,即進度條在播放時長的上面,橫屏為左右樣式,即進度條在播放時長的中間。樣式定制主要是兩個方法搭配使用toggleProcessDurationOrientation方法和setProcessDurationOrientation方法,橫豎屏切換2中情況,和3種進度條樣式

/**上下樣式*/
PlayStateParams.PROCESS_PORTRAIT
/**左右樣式*/
PlayStateParams.PROCESS_LANDSCAPE
/**中間兩邊樣式*/
PlayStateParams.PROCESS_CENTER
           

總共有2的3次方中樣式,下面隻羅列幾種樣式

(1).橫豎屏都為上下樣式

player = new PlayerView(this) {
        @Override
        public PlayerView toggleProcessDurationOrientation() {
            return setProcessDurationOrientation(PlayStateParams.PROCESS_PORTRAIT);
        }
    }
            .setTitle("什麼")
            .setProcessDurationOrientation(PlayStateParams.PROCESS_PORTRAIT)
            .setScaleType(PlayStateParams.fitparent)
            .forbidTouch(false)
            .hideCenterPlayer(true)
            .setPlaySource(list)
            .startPlay();
           

(2).橫豎屏都為左右樣式

player = new PlayerView(this) {
        @Override
        public PlayerView toggleProcessDurationOrientation() {
            return setProcessDurationOrientation(PlayStateParams.PROCESS_LANDSCAPE);
        }
    }
            .setTitle("什麼")
            .setProcessDurationOrientation(PlayStateParams.PROCESS_LANDSCAPE)
            .setScaleType(PlayStateParams.fitparent)
            .forbidTouch(false)
            .hideCenterPlayer(true)
            .setPlaySource(list)
            .startPlay();
           

(3).橫屏為上下樣式豎屏為左右樣式

player = new PlayerView(this) {
        @Override
        public PlayerView toggleProcessDurationOrientation() {
            return setProcessDurationOrientation(getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE?PlayStateParams.PROCESS_LANDSCAPE:PlayStateParams.PROCESS_PORTRAIT);
        }
    }
            .setTitle("什麼")
            .setProcessDurationOrientation(PlayStateParams.PROCESS_LANDSCAPE)
            .setScaleType(PlayStateParams.fitparent)
            .forbidTouch(false)
            .hideCenterPlayer(true)
            .setPlaySource(list)
            .startPlay();
           

3.隐藏部分不想要的界面

//隐藏傳回鍵,true隐藏,false為顯示
PlayerView hideBack(boolean isHide)
//隐藏菜單鍵,true隐藏,false為顯示
PlayerView hideMenu(boolean isHide)
//隐藏分辨率按鈕,true隐藏,false為顯示
PlayerView hideSteam(boolean isHide)
//隐藏旋轉按鈕,true隐藏,false為顯示
PlayerView hideRotation(boolean isHide)
//隐藏全屏按鈕,true隐藏,false為顯示
PlayerView hideFullscreen(boolean isHide)
//隐藏中間播放按鈕,ture為隐藏,false為不做隐藏處理,但不是顯示
PlayerView hideCenterPlayer(boolean isHide)
           

4.視訊移動流量是播放提醒

//設定///G和WiFi網絡類型提示 true為進行///G網絡類型提示 false 不進行網絡類型提示
PlayerView setNetWorkTypeTie(boolean isGNetWork)
           

5.視訊加載前顯示縮略圖

player.showThumbnail(new OnShowThumbnailListener() {
                @Override
                public void onShowThumbnail(ImageView ivThumbnail) {
                    /**加載前顯示的縮略圖*/
                    Glide.with(mContext)
                            .load("http://pic2.nipic.com/20090413/406638_125424003_2.jpg")
                            .placeholder(R.color.cl_default)
                            .error(R.color.cl_error)
                            .into(ivThumbnail);
                }
            })
           

6.預設顯示上下操作欄bar

//設定是否禁止隐藏bar,true為一直顯示,false為點選可以隐藏或顯示
PlayerView setForbidHideControlPanl(boolean flag)
           

7.設定播放出錯後嘗試重連的方式和重連的時間

//設定自動重連的模式或者重連時間,isAuto true 出錯重連,false出錯不重連,connectTime重連的時間
setAutoReConnect(boolean isAuto, int connectTime)
           

8.視訊界面的旋轉

目前預設使用setPlayerRotation方法為90、270、0輪詢切換,如果需要指定角度旋轉可以使用setPlayerRotation方法

//旋轉角度
PlayerView setPlayerRotation()
//旋轉指定角度
PlayerView setPlayerRotation(int rotation)
           

自定義視訊界面

可以複制以下布局内容到自己的項目中,注意已有的id不能修改或删除,可以增加view,可以對以下布局内容調整顯示位置或者自行隐藏

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:id="@+id/app_video_box"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:orientation="vertical">


    <com.dou361.ijkplayer.widget.IjkVideoView
        android:id="@+id/video_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <LinearLayout
        android:id="@+id/ll_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/black"
        android:orientation="vertical">

        <!-- 封面顯示-->
        <ImageView
            android:id="@+id/iv_trumb"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:visibility="visible"/>
    </LinearLayout>

    <!--重新播放-->
    <LinearLayout
        android:id="@+id/app_video_replay"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#33000000"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone">
        <!-- 播放狀态-->
        <TextView
            android:id="@+id/app_video_status_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/small_problem"
            android:textColor="@android:color/white"
            android:textSize="14dp"/>

        <ImageView
            android:id="@+id/app_video_replay_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="8dp"
            android:src="@drawable/simple_player_circle_outline_white_36dp"/>
    </LinearLayout>
    <!-- 網絡提示-->
    <LinearLayout
        android:id="@+id/app_video_netTie"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#33000000"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:gravity="center"
            android:paddingLeft="8dp"
            android:paddingRight="8dp"
            android:text="您正在使用移動網絡播放視訊\n可能産生較高流量費用"
            android:textColor="@android:color/white"/>

        <TextView
            android:id="@+id/app_video_netTie_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/simple_player_btn"
            android:gravity="center"
            android:paddingLeft="8dp"
            android:paddingRight="8dp"
            android:text="繼續"
            android:textColor="@android:color/white"/>
    </LinearLayout>

    <!--加載中-->
    <LinearLayout
        android:id="@+id/app_video_loading"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone">

        <ProgressBar
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:indeterminateBehavior="repeat"
            android:indeterminateOnly="true"/>
        <TextView
            android:id="@+id/app_video_speed"
            android:layout_width="wrap_content"
            android:layout_marginTop="4dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:visibility="gone"
            android:text="188Kb/s"
            android:textColor="@android:color/white"/>
    </LinearLayout>

    <!-- 中間觸摸提示-->
    <include
        layout="@layout/simple_player_touch_gestures"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>

    <!-- 頂部欄-->
    <include layout="@layout/simple_player_topbar"/>
    <!-- 底部欄-->
    <include
        layout="@layout/simple_player_controlbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"/>

    <!--聲音亮度控制-->
    <LinearLayout
        android:id="@+id/simple_player_settings_container"
        android:layout_width="250dp"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:background="#80000000"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:visibility="visible">

        <LinearLayout
            android:id="@+id/simple_player_volume_controller_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal">

            <ImageView
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:src="@drawable/qcloud_player_icon_audio_vol_mute"/>

            <SeekBar
                android:id="@+id/simple_player_volume_controller"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="150dp"
                android:layout_height="wrap_content"/>

            <ImageView
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:src="@drawable/qcloud_player_icon_audio_vol"/>
        </LinearLayout>

        <LinearLayout
            android:id="@+id/simple_player_brightness_controller_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:gravity="center"
            android:orientation="horizontal">

            <ImageView
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:padding="5dp"
                android:src="@drawable/qcloud_player_icon_brightness"/>

            <SeekBar
                android:id="@+id/simple_player_brightness_controller"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="150dp"
                android:layout_height="wrap_content"/>

            <ImageView
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:src="@drawable/qcloud_player_icon_brightness"/>
        </LinearLayout>

    </LinearLayout>


    <!--分辨率選擇-->
    <LinearLayout
        android:id="@+id/simple_player_select_stream_container"
        android:layout_width="150dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:background="#80000000"
        android:gravity="center_vertical"
        android:visibility="gone">

        <ListView
            android:id="@+id/simple_player_select_streams_list"
            android:layout_width="150dp"
            android:layout_height="wrap_content"/>
    </LinearLayout>


    <ImageView
        android:id="@+id/play_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginTop="8dp"
        android:src="@drawable/simple_player_center_play"/>

</RelativeLayout>
           

播放器PlayerView對象

PlayerView(Activity activity)

//生命周期方法回調
PlayerView onPause()
PlayerView onResume()
PlayerView onDestroy()
PlayerView onConfigurationChanged(final Configuration newConfig)
boolean onBackPressed()
//顯示縮略圖
PlayerView showThumbnail(OnShowThumbnailListener onShowThumbnailListener)
//設定播放資訊監聽回調
PlayerView setOnInfoListener(IMediaPlayer.OnInfoListener onInfoListener)
//設定播放器中的傳回鍵監聽
PlayerView setPlayerBackListener(OnPlayerBackListener listener)
//設定控制台顯示隐藏監聽
PlayerView setOnControlPanelVisibilityChangListenter(OnControlPanelVisibilityChangeListener listener)
//百分比顯示切換
PlayerView toggleAspectRatio()
//設定播放區域拉伸類型
PlayerView setScaleType(int showType)
//旋轉角度
PlayerView setPlayerRotation()
//旋轉指定角度
PlayerView setPlayerRotation(int rotation)
//設定播放位址包括視訊清晰度清單對應位址清單
PlayerView setPlaySource(List<VideoijkBean> list)
//設定播放位址單個視訊VideoijkBean
PlayerView setPlaySource(VideoijkBean videoijkBean)
//設定播放位址單個視訊位址時帶流名稱
PlayerView setPlaySource(String stream, String url)
//設定播放位址單個視訊位址時
PlayerView setPlaySource(String url)
//自動播放
PlayerView autoPlay(String path)
//開始播放
PlayerView startPlay()
//設定視訊名稱
PlayerView setTitle(String title)
//選擇要播放的流
PlayerView switchStream(int index)
//暫停播放
PlayerView pausePlay()
//停止播放
PlayerView stopPlay()
//設定播放位置
PlayerView seekTo(int playtime)
//擷取目前播放位置
int getCurrentPosition()
//擷取視訊播放總時長
long getDuration()
//設定2/3/4/5G和WiFi網絡類型提示 true為進行2/3/4/5G網絡類型提示 false 不進行網絡類型提示
PlayerView setNetWorkTypeTie(boolean isGNetWork)
//是否僅僅為全屏
PlayerView setOnlyFullScreen(boolean isFull)
//設定是否禁止輕按兩下
PlayerView setForbidDoulbeUp(boolean flag)
//設定是否禁止隐藏bar
PlayerView setForbidHideControlPanl(boolean flag)
//目前播放的是否是直播
boolean isLive()
//是否禁止觸摸
PlayerView forbidTouch(boolean forbidTouch)
//隐藏所有狀态界面
PlayerView hideAllUI()
擷取頂部控制barview
View getTopBarView()
//擷取底部控制barview
View getBottonBarView()
//擷取旋轉view
ImageView getRationView()
//擷取傳回view
ImageView getBackView()
//擷取菜單view
ImageView getMenuView()
//擷取全屏按鈕view
ImageView getFullScreenView()
//擷取底部bar的播放view
ImageView getBarPlayerView()
//擷取中間的播放view
ImageView getPlayerView()
//隐藏傳回鍵,true隐藏,false為顯示
PlayerView hideBack(boolean isHide)
//隐藏菜單鍵,true隐藏,false為顯示
PlayerView hideMenu(boolean isHide)
//隐藏分辨率按鈕,true隐藏,false為顯示
PlayerView hideSteam(boolean isHide)
//隐藏旋轉按鈕,true隐藏,false為顯示
PlayerView hideRotation(boolean isHide)
//隐藏全屏按鈕,true隐藏,false為顯示
PlayerView hideFullscreen(boolean isHide)
//隐藏中間播放按鈕,ture為隐藏,false為不做隐藏處理,但不是顯示
PlayerView hideCenterPlayer(boolean isHide)
//顯示或隐藏操作面闆
PlayerView operatorPanl()
//全屏切換
PlayerView toggleFullScreen()
//設定自動重連的模式或者重連時間,isAuto true 出錯重連,false出錯不重連,connectTime重連的時間
setAutoReConnect(boolean isAuto, int connectTime)
//進度條和時長顯示的方向切換
PlayerView toggleProcessDurationOrientation()
//設定進度條和時長顯示的方向,預設為上下顯示,PlayStateParams.PROCESS_PORTRAIT為上下顯示PlayStateParams.PROCESS_LANDSCAPE為左右顯示PlayStateParams.PROCESS_CENTER為中間兩邊樣式
setProcessDurationOrientation(int portrait)
//顯示菜單設定
showMenu()
//擷取界面方向
int getScreenOrientation()
//顯示加載網速
PlayerView setShowSpeed(boolean isShow)
           

ijkplayer封裝的視訊播放資訊傳回碼監聽

通過setOnInfoListener去監聽

/*
 * Do not change these values without updating their counterparts in native
 */
int MEDIA_INFO_UNKNOWN = ;//未知資訊
int MEDIA_INFO_STARTED_AS_NEXT = ;//播放下一條
int MEDIA_INFO_VIDEO_RENDERING_START = ;//視訊開始整備中
int MEDIA_INFO_VIDEO_TRACK_LAGGING = ;//視訊日志跟蹤
int MEDIA_INFO_BUFFERING_START = ;//開始緩沖中
int MEDIA_INFO_BUFFERING_END = ;//緩沖結束
int MEDIA_INFO_NETWORK_BANDWIDTH = ;//網絡帶寬,網速方面
int MEDIA_INFO_BAD_INTERLEAVING = ;//
int MEDIA_INFO_NOT_SEEKABLE = ;//不可設定播放位置,直播方面
int MEDIA_INFO_METADATA_UPDATE = ;//
int MEDIA_INFO_TIMED_TEXT_ERROR = ;
int MEDIA_INFO_UNSUPPORTED_SUBTITLE = ;//不支援字幕
int MEDIA_INFO_SUBTITLE_TIMED_OUT = ;//字幕逾時

int MEDIA_INFO_VIDEO_INTERRUPT= -;//資料連接配接中斷
int MEDIA_INFO_VIDEO_ROTATION_CHANGED = ;//視訊方向改變
int MEDIA_INFO_AUDIO_RENDERING_START = ;//音頻開始整備中

int MEDIA_ERROR_UNKNOWN = ;//未知錯誤
int MEDIA_ERROR_SERVER_DIED = ;//服務挂掉
int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = ;//資料錯誤沒有有效的回收
int MEDIA_ERROR_IO = -;//IO錯誤
int MEDIA_ERROR_MALFORMED = -;
int MEDIA_ERROR_UNSUPPORTED = -;//資料不支援
int MEDIA_ERROR_TIMED_OUT = -;//資料逾時
           

參考自http://blog.csdn.net/jiujiedexiaoming/article/details/52319676