最近因为项目需求 ,需要播放网络视频 ,于是乎 研究了一番 ,说说我遇到的那些坑
现在市面上有几个比较主流好用的第三方框架
Vitamio ( 体积比较大,有商业化风险 github:https://github.com/yixia/VitamioBundle/)
ijkplayer(B站下开源的框架 体积大 配置环境比较麻烦 github:https://github.com/Bilibili/ijkplayer )
PLDroidPlayer(七牛根据ijkplayer二次开发的 定制简单 github:https://github.com/pili-engineering/PLDroidPlayer)
当然还有很多别的视频播放框架 因为我只找到这几个= =!
因为项目比较急,所以我用的比较简单的 PLDroidPlayer
首先把需要的jar包和jni文件拷到你的项目中
这个里面有很多控件,你们可以根据自己的需求来用指定的控件,我用的是PLVideoTextureView
<com.pili.pldroid.player.widget.PLVideoTextureView android:id="@+id/video" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" />... prompt'''
然后findviewbyid找到它
public class PLVideoTextureActivity extends AppCompatActivity {
private MediaController mMediaController; private PLVideoTextureView mVideoView; private Toast mToast = null; private String mVideoPath = null; private int mRotation = 0; private int mDisplayAspectRatio = PLVideoTextureView.ASPECT_RATIO_FIT_PARENT; //default
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_pl_video_texture);
mVideoView = (PLVideoTextureView) findViewById(R.id.VideoView);
View loadingView = findViewById(R.id.LoadingView);
mVideoView.setBufferingIndicator(loadingView);
mVideoPath = getIntent().getStringExtra("videoPath"); // If you want to fix display orientation such as landscape, you can use the code show as follow
//
// if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
// mVideoView.setPreviewOrientation(0);
// }
// else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// mVideoView.setPreviewOrientation(270);
// }
mVideoPath = getIntent().getStringExtra("videoPath");
AVOptions options = new AVOptions(); int isLiveStreaming = getIntent().getIntExtra("liveStreaming", 1); // the unit of timeout is ms
options.setInteger(AVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
options.setInteger(AVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000); // Some optimization with buffering mechanism when be set to 1
options.setInteger(AVOptions.KEY_LIVE_STREAMING, isLiveStreaming); if (isLiveStreaming == 1) {
options.setInteger(AVOptions.KEY_DELAY_OPTIMIZATION, 1);
} // 1 -> hw codec enable, 0 -> disable [recommended]
int codec = getIntent().getIntExtra("mediaCodec", 0);
options.setInteger(AVOptions.KEY_MEDIACODEC, codec); // whether start play automatically after prepared, default value is 1
options.setInteger(AVOptions.KEY_START_ON_PREPARED, 0);
mVideoView.setAVOptions(options); // You can mirror the display
// mVideoView.setMirror(true);
// You can also use a custom `MediaController` widget
mMediaController = new MediaController(this, false, isLiveStreaming == 1);
mVideoView.setMediaController(mMediaController);
mVideoView.setOnInfoListener(mOnInfoListener);// mVideoView.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
mVideoView.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
mVideoView.setOnCompletionListener(mOnCompletionListener);
mVideoView.setOnSeekCompleteListener(mOnSeekCompleteListener);
mVideoView.setOnErrorListener(mOnErrorListener);
mVideoView.setVideoPath(mVideoPath);
mVideoView.setDisplayAspectRatio(PLVideoView.ASPECT_RATIO_PAVED_PARENT);
mVideoView.setOnPreparedListener(mOnPreparedListener);
mVideoView.setOnVideoSizeChangedListener(new PLMediaPlayer.OnVideoSizeChangedListener() { @Override
public void onVideoSizeChanged(PLMediaPlayer plMediaPlayer, int width, int height) {
Logger.i("width:" + width + "---heightL:" + height); if (width > height) { //视频是横屏 旋转方向
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
});
mVideoView.setVideoPath(mVideoPath);
mVideoView.start();
} @Override
protected void onPause() { super.onPause();
mToast = null;
mVideoView.pause();
} @Override
protected void onResume() { super.onResume();
mVideoView.start();
} @Override
protected void onDestroy() { super.onDestroy();
mVideoView.stopPlayback();
} public void onClickRotate(View v) {
mRotation = (mRotation + 90) % 360;
mVideoView.setDisplayOrientation(mRotation);
} public void onClickSwitchScreen(View v) {
mDisplayAspectRatio = (mDisplayAspectRatio + 1) % 5;
mVideoView.setDisplayAspectRatio(mDisplayAspectRatio); switch (mVideoView.getDisplayAspectRatio()) { case PLVideoTextureView.ASPECT_RATIO_ORIGIN:
showToastTips("Origin mode"); break; case PLVideoTextureView.ASPECT_RATIO_FIT_PARENT:
showToastTips("Fit parent !"); break; case PLVideoTextureView.ASPECT_RATIO_PAVED_PARENT:
showToastTips("Paved parent !"); break; case PLVideoTextureView.ASPECT_RATIO_16_9:
showToastTips("16 : 9 !"); break; case PLVideoTextureView.ASPECT_RATIO_4_3:
showToastTips("4 : 3 !"); break; default: break;
}
} private PLMediaPlayer.OnErrorListener mOnErrorListener = new PLMediaPlayer.OnErrorListener() { @Override
public boolean onError(PLMediaPlayer mp, int errorCode) { switch (errorCode) { case PLMediaPlayer.ERROR_CODE_INVALID_URI:
showToastTips("Invalid URL !"); break; case PLMediaPlayer.ERROR_CODE_404_NOT_FOUND:
showToastTips("404 resource not found !"); break; case PLMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
showToastTips("Connection refused !"); break; case PLMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
showToastTips("Connection timeout !"); break; case PLMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
showToastTips("Empty playlist !"); break; case PLMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
showToastTips("Stream disconnected !"); break; case PLMediaPlayer.ERROR_CODE_IO_ERROR:
showToastTips("Network IO Error !"); break; case PLMediaPlayer.ERROR_CODE_UNAUTHORIZED:
showToastTips("Unauthorized Error !"); break; case PLMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
showToastTips("Prepare timeout !"); break; case PLMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
showToastTips("Read frame timeout !"); break; case PLMediaPlayer.MEDIA_ERROR_UNKNOWN: default:
showToastTips("unknown error !"); break;
} // Todo pls handle the error status here, retry or call finish()
finish(); // If you want to retry, do like this:
// mVideoView.setVideoPath(mVideoPath);
// mVideoView.start();
// Return true means the error has been handled
// If return false, then `onCompletion` will be called
return true;
}
}; private PLMediaPlayer.OnCompletionListener mOnCompletionListener = new PLMediaPlayer.OnCompletionListener() { @Override
public void onCompletion(PLMediaPlayer plMediaPlayer) {// finish();
showToast("视频播放完成");
}
}; private PLMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new PLMediaPlayer.OnBufferingUpdateListener() { @Override
public void onBufferingUpdate(PLMediaPlayer plMediaPlayer, int precent) {
}
}; private PLMediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener = new PLMediaPlayer.OnSeekCompleteListener() { @Override
public void onSeekComplete(PLMediaPlayer plMediaPlayer) {
Logger.d("onSeekComplete !");
}
}; private PLMediaPlayer.OnPreparedListener mOnPreparedListener = new PLMediaPlayer.OnPreparedListener() { @Override
public void onPrepared(PLMediaPlayer plMediaPlayer) {
}
}; private PLMediaPlayer.OnInfoListener mOnInfoListener = new PLMediaPlayer.OnInfoListener() { @Override
public boolean onInfo(PLMediaPlayer plMediaPlayer, int what, int extra) { switch (what) { case PLMediaPlayer.MEDIA_INFO_BUFFERING_START:
Logger.i("正在缓冲----"); //开始缓存,暂停播放
if (isPlaying()) {// stopPlayer();
if (mVideoView != null) {
mVideoView.pause();
}
needResume = true;
}
rl_loading.setVisibility(View.VISIBLE); break; case PLMediaPlayer.MEDIA_INFO_BUFFERING_END: case PLMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
Logger.i("缓冲完成----"); //缓存完成,继续播放
if (needResume)// startPlayer();
if (mVideoView != null) {
mVideoView.start();
}
rl_loading.setVisibility(View.GONE); break; case PLMediaPlayer.MEDIA_INFO_BUFFERING_BYTES_UPDATE: //显示 下载速度
Logger.e("download rate:" + extra); //mListener.onDownloadRateChanged(arg2);
break;
}
Logger.i("onInfo:" + what + "___" + extra); return false;
}
};
这样就完成了普通视频的播放和旋转视频播放
看似简单 其实隐藏着大问题 ,也就是我所说的大坑
现在我是这样判断角度的 当视频的宽度大于高度的 我就认为这是一个横屏的视频 ,也就是说假如这个视频是1330X720(我随便说的尺寸,只为举例)现在宽度大于高度了 那么这就是一个横屏的视频,但是我只要播放手机拍摄的视频就会发现视频被放大了 ,但是其实我录制视频的时候是竖着排的 ,可视播放的时候却给我横着过来了,然后我就去看这个手机拍摄视频的尺寸 现在一般录制视频最低都是1280X720 ,恰好符合我判断的逻辑 ,难道他真是横着的? 然后我就用系统自带的播放器打开 ,居然没有横过来 ,而是竖着播放的 ,可它是怎么知道这个方向呢?于是我在百度搜 ,确实可以获取到本地视频的角度,但是好像低版本好像不兼容,然后根据角度去判断 是否需要旋转,可是我这个是网络视频啊 ,网络视频怎么获取到视频角度啊 ? 我第一反应是 上传视频的时候把宽高角度传到服务器 ,然后获取的时候根据这个角度旋转 ,但是别人播放网络视频的时候也没有传角度过去啊 - - 然后我就在github上面问那个作者 ,结果他说
“onInfo: 10001, 90”, 收到这个消息后,使用 PLVideoTextureView 的 setDisplayOrientation 旋转显示的方向,后面会补充这个回调的接口和文档。
我晕 ,你这不说 谁知道啊 坑死啊 - -
然后我就修改了下代码
/** * 视频的方向 */private int mVideoRotation; private boolean needResume; private PLMediaPlayer.OnInfoListener mOnInfoListener = new PLMediaPlayer.OnInfoListener() { @Override public boolean onInfo(PLMediaPlayer plMediaPlayer, int what, int extra) { switch (what) { case PLMediaPlayer.MEDIA_INFO_BUFFERING_START: Logger.i("正在缓冲----"); //开始缓存,暂停播放 if (isPlaying()) {// stopPlayer(); if (mVideoView != null) { mVideoView.pause(); } needResume = true; } rl_loading.setVisibility(View.VISIBLE); break; case PLMediaPlayer.MEDIA_INFO_BUFFERING_END: case PLMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: Logger.i("缓冲完成----"); //缓存完成,继续播放 if (needResume)// startPlayer(); if (mVideoView != null) { mVideoView.start(); } rl_loading.setVisibility(View.GONE); break; case PLMediaPlayer.MEDIA_INFO_BUFFERING_BYTES_UPDATE: //显示 下载速度 Logger.e("download rate:" + extra); //mListener.onDownloadRateChanged(arg2); break; case 10001: //保存视频角度 mVideoRotation=extra; break; } Logger.i("onInfo:" + what + "___" + extra); return false; } };
然后在onVideoSizeChanged的回调里这样
mVideoView.setOnVideoSizeChangedListener(new PLMediaPlayer.OnVideoSizeChangedListener() { @Override public void onVideoSizeChanged(PLMediaPlayer plMediaPlayer, int width, int height) { Logger.i("width:" + width + "---heightL:" + height); if (width > height&&mVideoRotation==0) { //旋转方向 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } //如果视频角度是90度 if(mVideoRotation==90) { //旋转视频 mVideoView.setDisplayOrientation(270); } } });
共同学习,写下你的评论
评论加载中...
作者其他优质文章