导读
众所周知,软解码虽然兼容性一流,但是却非常依赖CPU,所以性能消耗笔记大;硬解码使用内置的DSP芯片进行解码,性能高,但是兼容性一般。
虽说硬解码兼容性不太好,但是在实际开发中出于对性能的考虑我们依然会采用能硬解则硬解,不能硬解则软解兜底的方案。
我们知道安卓上可以使用MediaCodec进行硬解码,新版本FFmpeg内部也支持了MediaCodec硬解码,今天我们就使用FFMpeg在安卓上使用MediaCodec进行硬解码。
笔者测试的FFmpeg版本是最新的5.0.1,不同版本之间可以会有差异。
编译支持硬解码的FFmpeg
要编译支持硬解码的FFmpeg,在进行交叉编译时我们只需要打开以下几个属性即可:
--enable-hwaccels \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-decoder=hevc_mediacodec \
--enable-decoder=mpeg4_mediacodec \
--enable-hwaccel=h264_mediacodec \
使用FFMpeg进行硬解码
使用FFmpeg无论是硬解码还是软解码流程都是差不多的,对使用FFmpeg编解码API不熟悉的童鞋们可以回看之前发表的博客文章...
在FFmpeg源文件hwcontext.c
中我们可以看出mediacodec对应的type类型是AV_HWDEVICE_TYPE_MEDIACODEC
,这个AV_HWDEVICE_TYPE_MEDIACODEC
很重要, 在配置硬解码器时都是需要使用到这个type。
static const char *const hw_type_names[] = {
[AV_HWDEVICE_TYPE_CUDA] = "cuda",
[AV_HWDEVICE_TYPE_DRM] = "drm",
[AV_HWDEVICE_TYPE_DXVA2] = "dxva2",
[AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va",
[AV_HWDEVICE_TYPE_OPENCL] = "opencl",
[AV_HWDEVICE_TYPE_QSV] = "qsv",
[AV_HWDEVICE_TYPE_VAAPI] = "vaapi",
[AV_HWDEVICE_TYPE_VDPAU] = "vdpau",
[AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",
[AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",
[AV_HWDEVICE_TYPE_VULKAN] = "vulkan",
};
下面说说在FFMpeg配置硬解码器的大体步骤:
1、给FFMpeg设置虚拟机环境
首先在库加载函数JNI_OnLoad
中调用FFmpeg的函数av_jni_set_java_vm
,给FFMpeg设置虚拟机环境:
// 类库加载时自动调用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reversed) {
JNIEnv *env = NULL;
// 初始化JNIEnv
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_FALSE;
}
// 设置JavaVM,否则无法进行硬解码
av_jni_set_java_vm(vm, nullptr);
RegisterNativeMethods(env, "com/fly/ffmpeg/pra