Android平台FFmpeg 4.4无法初始化h264_mediacodec硬件解码
解决Android平台FFmpeg 4.4 MediaCodec硬件解码初始化失败问题
一、修复编译参数问题
- 立即移除
--enable-hwaccel=h264_mediacodec参数,FFmpeg中h264_mediacodec是独立解码器,不属于hwaccel模块,该参数完全无效,这就是编译警告的根源。 - 保留正确的编译参数:
--enable-jni \ --enable-mediacodec \ --enable-decoder=h264_mediacodec \
- 检查ffmpeg-android-maker脚本,确保自定义参数被正确传递到FFmpeg的configure流程,避免脚本覆盖或忽略这些配置。
二、代码层面修正
1. 手动指定MediaCodec解码器
当前用av_find_best_stream自动选解码器时,大概率会优先选择软件解码器(如h264),而非硬件解码器。需要主动尝试获取h264_mediacodec:
void Decoder::initDecoder() { AVCodecParameters* videoStreamCodecParams = m_videoStream->codecpar; // 优先尝试硬件解码器 m_decoder = avcodec_find_decoder_by_name("h264_mediacodec"); if (!m_decoder) { spdlog::warn("h264_mediacodec not found, falling back to software decoder"); // fallback到自动选择逻辑 int ret = av_find_best_stream(m_inputFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, &m_decoder, 0); if (ret < 0 || !m_decoder) { throw FFmpegException("Decoder: No available video decoder"); } } // 遍历硬件配置逻辑保留,后续补充设备初始化 for (size_t i = 0;; i++) { const AVCodecHWConfig* config = avcodec_get_hw_config(m_decoder, i); if (!config) { spdlog::error( "Decoder {} doesn't support device type {}. Use SW decoder...", m_decoder->name, av_hwdevice_get_type_name(m_deviceType) ); m_hwDecoderSupported = false; break; } if ( config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == m_deviceType ) { g_hwPixFmt = config->pix_fmt; m_hwDecoderSupported = true; break; } } // 补充硬件设备上下文初始化(关键步骤) if (m_hwDecoderSupported) { AVBufferRef* hw_device_ctx = nullptr; int ret = av_hwdevice_ctx_create(&hw_device_ctx, m_deviceType, nullptr, nullptr, 0); if (ret < 0) { spdlog::error("Failed to create MediaCodec device: {}", av_err2str(ret)); m_hwDecoderSupported = false; return; } // 分配并初始化解码器上下文 m_codecContext = avcodec_alloc_context3(m_decoder); if (!m_codecContext) { av_buffer_unref(&hw_device_ctx); throw FFmpegException("Failed to allocate codec context"); } // 复制流参数到解码器上下文 ret = avcodec_parameters_to_context(m_codecContext, videoStreamCodecParams); if (ret < 0) { avcodec_free_context(&m_codecContext); av_buffer_unref(&hw_device_ctx); throw FFmpegException(fmt::format("Copy codec params failed: {}", av_err2str(ret))); } // 关联硬件设备上下文到解码器 m_codecContext->hw_device_ctx = av_buffer_ref(hw_device_ctx); av_buffer_unref(&hw_device_ctx); // 打开解码器 ret = avcodec_open2(m_codecContext, m_decoder, nullptr); if (ret < 0) { spdlog::error("Open MediaCodec decoder failed: {}", av_err2str(ret)); m_hwDecoderSupported = false; avcodec_free_context(&m_codecContext); } } // 软件解码器的初始化逻辑(如果需要) if (!m_hwDecoderSupported) { m_codecContext = avcodec_alloc_context3(m_decoder); if (!m_codecContext) { throw FFmpegException("Failed to allocate codec context"); } int ret = avcodec_parameters_to_context(m_codecContext, videoStreamCodecParams); if (ret < 0) { avcodec_free_context(&m_codecContext); throw FFmpegException(fmt::format("Copy codec params failed: {}", av_err2str(ret))); } ret = avcodec_open2(m_codecContext, m_decoder, nullptr); if (ret < 0) { avcodec_free_context(&m_codecContext); throw FFmpegException(fmt::format("Open SW decoder failed: {}", av_err2str(ret))); } } }
2. 关键缺失点说明
原代码缺少AVCodecContext的创建和硬件设备上下文的关联逻辑,这是FFmpeg硬件解码的核心步骤——必须将MediaCodec设备上下文绑定到解码器上下文,才能启用硬件加速。
三、验证步骤
- 编译后,用输出的ffmpeg二进制执行
ffmpeg -decoders,确认列表中存在h264_mediacodec,验证编译是否生效。 - 在JNI代码中添加日志,打印
avcodec_find_decoder_by_name("h264_mediacodec")的地址,以及遍历avcodec_get_hw_config时的所有config->device_type和config->pix_fmt,排查硬件配置是否被正确识别。
内容的提问来源于stack exchange,提问作者Ramil Galin
相关产品推荐
相关产品推荐

