本文主要是介绍IJKPlayer 编译与使用总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
IJKPlayer 是B站开源的超级好用的视频播放器,IJKPlayer Android和IOS都可用,还支持多种视频的硬解码。公司的项目采用Google MediaPlayer,播放器存在对视频格式和传输协议的支持不足问题。经过对主流开源播放器的对比,最终选择IJKPlayer。
开始编译
- 拉取ijkplayer源码
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
git checkout -B latest k0.8.8
- 初始化android
./init-android.sh
- 初始化openssl支持Https
./init-android-openssl.sh
注:如果出现NDK或者SDK找不到,可以执行一下source ~/.bash_profile
- 清除一波
cd android/contrib
./compile-openssl.sh clean
./compile-ffmpeg.sh clean
- 编译openssl
./compile-openssl.sh all
- 编译ffmpeg
这里的话看你需要,如果想编译所有版本的so库,就跟all,如果是特定 CPU架构就跟cpu架构,比如:./compile-ffmpeg.sh armv7a
编译特定需要的肯定是比全部耗时短~
./compile-ffmpeg.sh all
- 编译ijkplayer
加all默认编译所有架构的so库,不加默认只编译armv7a架构!
cd ..
./compile-ijk.sh all
编译成功后,会生成如下三个文件:
将so文件复制到项目的libs目录,如下图,并在build.gradle中加入如下代码:
sourceSets {main {jniLibs.srcDirs = ['libs']}}
注意:不同架构要单独创建相应的文件夹。
到此,编译一个支持HTTPS的ijkplayer就完成了
1、项目中需要对不同机型进行一些差异化处理,需要在Java层传机型信息到IJK so库
新增option参数
a. options_table.h
{"clienttype", "TV ClientType", OFFSET(clienttype), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D },
b. avformat.h
char clienttype[128];
2. 部分机型对硬解支持不够好,需要捕获异常并进行自动切换软解
新增硬解失败计数
a. ff_ffplay_def.h
int amediacodec_err_count;
b. ff_ffplay.c
// 2018/10/25 tyong
ffp->amediacodec_err_count = 0;
// 2018/10/29 tyong 获取clienttype
char clienttype[128];
AVDictionaryEntry *clt = NULL;
clt = av_dict_get(ffp->format_opts, "clienttype", clt, AV_DICT_IGNORE_SUFFIX);
if (NULL != clt) {
strcpy(clienttype, clt->value);
ALOGE("FFalconPlayer: clienttype=%s\n", clienttype);
}
// 2018/10/25 tyong
int width = st->codec->width;
int height = st->codec->height;
bool divx = false;
bool avc1 = false;
bool m2v1 = false;
char buf[256];
AVCodecContext *avctx = avcodec_alloc_context3(NULL);
if (avctx) {
if (avcodec_parameters_to_context(avctx, st->codecpar) < 0) {
avcodec_free_context(&avctx);
} else {
avcodec_string(buf, sizeof(buf), avctx, 0);
avcodec_free_context(&avctx);
// 判断是否为mpeg4 divx
if (NULL!=buf && (strstr(buf, "DIVX") || strstr(buf, "DX50"))) {
divx = true;
} else if (NULL!=buf && strstr(buf, "avc1")) {
avc1 = true;
} else if (NULL!=buf && strstr(buf, "m2v1")) {
m2v1 = true;
}
}
}
ALOGE("ffalconplayer: codec_id = %d, divx=%d, avc1=%d, mediacodec_avc=%d, width=%d, height=%d, codec_name=%s \n", codec_id, divx, avc1, ffp->mediacodec_avc, width, height, buf);
video_stream_count++;
if (codec_id == AV_CODEC_ID_H264) {
h264_stream_count++;
if (first_h264_stream < 0)
first_h264_stream = i;
if (avc1 && strstr(is->filename, "http://")) {
ret = -10000;
goto fail;
}
} else if (codec_id == AV_CODEC_ID_MJPEG) {
ALOGE("ffalconplayer: codec_id == AV_CODEC_ID_MJPEG\n");
ret = -10000;
goto fail;
} else if (codec_id == AV_CODEC_ID_MPEG1VIDEO) {
ALOGE("ffalconplayer: codec_id == AV_CODEC_ID_MPEG1VIDEO\n");
ret = -10000;
goto fail;
} else if (codec_id == AV_CODEC_ID_MPEG2VIDEO) {
ALOGE("ffalconplayer: codec_id == AV_CODEC_ID_MPEG2VIDEO\n");
if (m2v1) {
} else {
ret = -10000;
goto fail;
}
} else if (codec_id == AV_CODEC_ID_MPEG4) {
ALOGE("ffalconplayer: codec_id == AV_CODEC_ID_MPEG4\n");
if (divx) {
} else {
ret = -10000;
goto fail;
}
}
c. ffpipenode_android_mediacodec.vdec.c
// 2018/10/25 tyong 前5贞数据如果硬解失败,则转为软解
if (output_buffer_index == AMEDIACODEC__UNKNOWN_ERROR) {
ffp->amediacodec_err_count++;
ALOGE("[FFalconPlayer]: SDL_AMediaCodecFake_dequeueOutputBuffer = AMEDIACODEC__UNKNOWN_ERROR, ffp->amediacodec_err_count=%d\n", ffp->amediacodec_err_count);
if (3 <= ffp->amediacodec_err_count) {
ret = -1;
ffp_notify_msg2(ffp, FFP_MSG_ERROR, -50005);
goto fail;
}
} else {
ffp->amediacodec_err_count = 0;
}
- 总结
最初对IJKPLAYER的定位是全能播放器,完全替代Google MediaPlayer。实际开发中碰到一系列问题,需要IJKPLAYER+MediaPlayer=全能播放器。问题如下:
1、MediaPlayer兼容性比IJKPLAYER要好,主要原因是MediaPlayer针对指定机型做过适配,在色彩上都要优于IJKPLAYER;
2、部分机型不支持MediaCodec,需要直接使用MediaPlayer;
3、对硬解支持不稳定,导致IJKPLAYER硬解效果不如MediaPlayer好,特别是265、mpeg4;
这篇关于IJKPlayer 编译与使用总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!