0x0000 背景
- 项目需要引入直播功能,而Android原生的VideoView本身是不支持RTMP格式的流媒体播放的。
- 市面上的开源播放器还是挺好选择的,相比较于IjkPlayer,其他例如Vitamio、VLC的SDK无论使用便利性还是社区的支持都差得远,自己用ffmpeg写成本难以接受。
- 但是!IjkPlayer在Github上的README文档真心坑,完全按那个文档做连编译都过不了。。
0x0001 致谢
- 感谢Bilibili工程师的无私开源
- 本博文参照了:
Android Studio中如何将ijkplayer 0.6.3导入自己的项目中并使用
感谢hisonedumobile博主 - 转载请注明
作者和平北路
原文点击链接
0x0002 源码链接
Github:Bilibili/ijkplayer
0x0003 编译
- 安装homebrew、git、yasm
非核心内容,请自行百度或谷歌 - 配置Android SDK、NDK环境变量,在.bash_profile增加如下两行
export ANDROID_SDK=/your/sdk/path
export ANDROID_NDK=/your/ndk/path
- 下载源码
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
git checkout -B latest k0.7.8.1
- 初始化
./init-android.sh
- 编译ffmpeg
cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
- 编译IjkPlayer
cd ..
./compile-ijk.sh all
到此为止,完成了对源码的编译,ijkplayer-android的目录结构如图
工程结构
0x0004 配置
- 拷贝gradle文件
复制/android/ijkplayer/tools文件夹到工程根目录 - 在工程根目录下的build.gradle文件中增加配置
ext {
compileSdkVersion = 25
buildToolsVersion = "25.0.2"
targetSdkVersion = 25
versionCode = 700801
versionName = "0.7.8.1"
}
前三条和你的app module的build.gradle保持一致
后两条和IjkPlayer源码工程中的build.gradle保持一致
-
依赖关系
回到刚才我们编译成功的源码目录,如果将/android/ijkplayer作为一个新项目导入Android Studio,运行ijkplayer-example,是可以作为一个独立app run起来的
我们先把example加入工程:
File-New-Import Module-/android/ijkplayer/ijkplayer-example
当然我们希望能把IjkPlayer当做一个第三方库引入,而不是在example工程的基础上实现我们的需求,那么就需要搞清楚各个module的依赖关系:
各module依赖关系
说的直白一点,arm64等5个module一看命名大家就明白是基于不同CPU编译产出的so
为了简化依赖,我们把这几个module的so文件拷贝到example module下,同时删除这几个module,完成后的example目录结构如图
example目录结构 -
改造example module
现在的example module是作为application存在的,如果要作为library引入,要处理以下三点
调整example build.gradle
example增加gradle.properties -
加入依赖库
File-Project Structure-app-Dependencies-添加ijkplayer-example
依赖example module
0x0005 开发
IjkVideoView本身继承自FrameLayout,可以和普通的View一样在layout的xml文件中直接加入
对大多数人来说,平时怎么使用VideoView,现在就怎么使用IjkVideoView即可
0x0006 问题
- 如何让播放器填满IjkVideoView展示
改造SurfaceRenderView的onMeasure方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (this.getWidth() != 0) {
setMeasuredDimension(this.getWidth(), this.getHeight());
return;
}
int width = getDefaultSize(0, widthMeasureSpec);
int height = getDefaultSize(0, heightMeasureSpec);
setMeasuredDimension(width, height);
}
- 启动之后crash
java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
在AndroidManifest.xml中设置Activity的theme属性
<activity
android:name=".MainActivity"
android:theme="@style/Theme.AppCompat.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- 视频流截图(适用于api14+)
IjkVideoView改造setRender
public void setRender(int render) {
switch (render) {
case RENDER_NONE:
setRenderView(null);
break;
case RENDER_SURFACE_VIEW:
case RENDER_TEXTURE_VIEW: {
TextureRenderView renderView = new TextureRenderView(getContext());
if (mMediaPlayer != null) {
renderView.getSurfaceHolder().bindToMediaPlayer(mMediaPlayer);
renderView.setVideoSize(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight());
renderView.setVideoSampleAspectRatio(mMediaPlayer.getVideoSarNum(), mMediaPlayer.getVideoSarDen());
renderView.setAspectRatio(mCurrentAspectRatio);
}
setRenderView(renderView);
break;
}
default:
Log.e(TAG, String.format(Locale.getDefault(), "invalid render %d\n", render));
break;
}
}
增加一个public方法
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
public Bitmap getShortcut() {
if (mRenderView instanceof TextureRenderView) {
return ((TextureRenderView) mRenderView).getBitmap();
}
return null;
}
0x0007 后记
Android播放器的坑太多,慢慢踩,与君共勉
网友评论
删除example-AndroidManifest.xml-FileExplorerActivity的<intent-filter>标签内容
不过用开源项目最大的优点就是可以改造源码,进行定制化处理