android下使ffmpeg使用mediacodec硬解
1、准备工作
从ffmpeg官网下载(http://ffmpeg.org/)源码(版本最好>3.1),这里介绍只使用ffmpeg提供的基本编解码功能,不外加其它需要单独编译的第三方库,但依然很强大,可以满足一般正常的使用
2、准备好交叉编译工具链和编译脚本
在编译之前需要做一些修改,让生成的库可能让android可以识别,打开ffmpeg源码目录下的configure文件,找到下面这些宏定义
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'
改成下面这样即可
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
参考脚本,具体编译链可以换成自己电脑的,编译选项也可以按实际自己要求去修改
#!/bin/bash
NDK=/root/android/android-ndk-r10/platforms/android-9/arch-arm/
SYSROOT=$NDK/platforms/android-16/arch-arm/
TOOLCHAIN=/root/android/android-ndk-r10/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CPU=arm
PREFIX=/root/ffmpeg-3.x.x
ADDI_CFLAGS="-marm"
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-doc \
--disable-symver \
--enable-small \
--enable-memalign-hack \
--enable-jni \
--enable-mediacodec \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--enable-decoder=hevc_mediacodec \
--enable-decoder=mpeg4_mediacodec \
--enable-decoder=vp8_mediacodec \
--enable-decoder=vp9_mediacodec \
--enable-gpl \
--enable-nonfree \
--enable-version3 \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make -j8
make install
}
build_one
由于编解码库没作删减,编译时间可能要等一段时间,等待编译完成吧
编译成功后,ffmpeg将会包含硬解功能,但要使用硬解还差几步
3、如何在android中使用视频硬解
第一步:据官方文档介绍,需要在android的JNI_OnLoad()函数中调用
extern "C"{
#include <libavcodec/jni.h>
}
av_jni_set_java_vm(vm, NULL);//初始化ffmpeg的jni代码
第二步:当ffmpeg在获取到文件的流信息后,可以解析出视频所使用的解码器ID,根据这个解码器ID,将解码器直接换成"**_mediacode" 即可,如
switch (pVideoCtx->codec_id)
{
case AV_CODEC_ID_H264:
{
pCodec = avcodec_find_decoder_by_name("h264_mediacodec");
break;
}
case AV_CODEC_ID_MPEG4:
{
pCodec = avcodec_find_decoder_by_name("mpeg4_mediacodec");
break;
}
}
default:
break;
}
至此,ffmpeg的使用跟普通场合的使用已经没有差别了
第三步:据文档介绍,对安桌系统的版本也有要求,android自4.0推出mediacodec,但使用ffmpeg的mediacodec硬解要5.0以上的android才行,我在4.2和4.4的手机测试过,都不能硬解视频,最好找一个5.0以上的安卓设备测试
4、总结
安卓的mediacodec的硬解在ffmpeg这种方式的使用下,虽然可以硬解,但是感觉这种传输机制还是太过于浪费资源,毕竟jni要这么频繁的传输这么多的视频数据,期间不但要传输数据、还要做视频转码、显示等操作,如果是实时显示的话,还是不太现实,最好还是直接在安卓直接实现好