Android基礎學習總結(十六)——基於ijkplayer封裝支援簡單介面UI定製的視訊播放器
前言
專案開發中遇到需要解析播放m3u8視訊流的情況,但是原生的PlayerView非常慢,使用起來複雜,不適合上手,這裡找到一款ijkplayer是Bilibili基於ffmpeg開發並開源的輕量級視訊播放器,支援播放本地網路視訊,也支援流媒體播放。支援Android&iOS。
這裡感謝jjdxmashl基於ijkplayer封裝了支援簡單介面UI定製的視訊播放器,操作簡單實用,推薦大家使用。
簡介
當前專案是基於ijkplayer專案進行的播放器介面UI封裝。
是一個適用於 Android 的 RTMP 直播推流 SDK,可高度定製化和二次開發。特色是同時支援 H.264 軟編/硬編和 AAC 軟編/硬編。主要是支援RIMP、HLS、MP4、M4A等視訊格式的播放。
作者專案地址:
作者簡書地址:http://www.jianshu.com/p/6c938df18413
特性
- 基於ijkplayer封裝的視訊播放器介面,支援 RTMP , HLS (http & https) , MP4,M4A 等;
- 可根據需求去定製部分介面樣式;
- 常用的手勢操作左邊上下亮度,右邊上下聲音,左右滑動播放進度調整;
- 支援多種解析度流的切換播放;
- 播放出錯嘗試重連;
- 介面裁剪顯示樣式;
快速開始
step1:匯入依賴
該專案已經打包到jcenter中心了,可以通過compile命令直接依賴,在主程式目錄build.gradle中,新增以下程式碼:
compile ‘com.dou361.ijkplayer:jjdxm-ijkplayer:1.0.0’
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.視訊移動流量是播放提醒
//設定2/3/4/5G和WiFi網路型別提示 true為進行2/3/4/5G網路型別提示 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 = 1;//未知資訊
int MEDIA_INFO_STARTED_AS_NEXT = 2;//播放下一條
int MEDIA_INFO_VIDEO_RENDERING_START = 3;//視訊開始整備中
int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;//視訊日誌跟蹤
int MEDIA_INFO_BUFFERING_START = 701;//開始緩衝中
int MEDIA_INFO_BUFFERING_END = 702;//緩衝結束
int MEDIA_INFO_NETWORK_BANDWIDTH = 703;//網路頻寬,網速方面
int MEDIA_INFO_BAD_INTERLEAVING = 800;//
int MEDIA_INFO_NOT_SEEKABLE = 801;//不可設定播放位置,直播方面
int MEDIA_INFO_METADATA_UPDATE = 802;//
int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;//不支援字幕
int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;//字幕超時
int MEDIA_INFO_VIDEO_INTERRUPT= -10000;//資料連線中斷
int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;//視訊方向改變
int MEDIA_INFO_AUDIO_RENDERING_START = 10002;//音訊開始整備中
int MEDIA_ERROR_UNKNOWN = 1;//未知錯誤
int MEDIA_ERROR_SERVER_DIED = 100;//服務掛掉
int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;//資料錯誤沒有有效的回收
int MEDIA_ERROR_IO = -1004;//IO錯誤
int MEDIA_ERROR_MALFORMED = -1007;
int MEDIA_ERROR_UNSUPPORTED = -1010;//資料不支援
int MEDIA_ERROR_TIMED_OUT = -110;//資料超時