【AVD】FFmpeg + MediaCodec 实现 Android 硬件解码,中间有个大坑

您所在的位置:网站首页 format怎么读 【AVD】FFmpeg + MediaCodec 实现 Android 硬件解码,中间有个大坑

【AVD】FFmpeg + MediaCodec 实现 Android 硬件解码,中间有个大坑

2023-06-26 18:27| 来源: 网络整理| 查看: 265

最近在做移动端音视频编解码,首先要实现的是移动端视频的解码功能。纯的 FFmpeg 方法在移动端也能实现,但是效率上的确要慢一些,1080p 的视频还好,但是上到 2k、4k,那个解码速度(以肉眼可见的速度解码一帧),就没法忍受了。因此要搞移动端硬件解码,以加速解码速度,同时释放部分 CPU 资源。

参考 FFmpeg 源码中 examples

参考 FFmpeg 官方源码中的 examples 的相关功能实现,来实现自己的程序设计,应该是最快的思路。但是,关于视频解码,FFmpeg 官方源码中,有 decode_video.c demuxing_decoding.c hw_decode.c,这三个解码相关的文件。

其实前两个文件的方案差不多,只不过第一个针对裸 h264 流,而第二个是针对带封装的视频文件。建议新手可以参考第二个方案。

至于第三个文件,hw_decode.c,看起来是一个硬件解码的 demo,当然,它的确也是(笑),然而,这里,我们却不能参考这个。参考这个文件,我们可以实现在 Linux 或者 Windows 平台上,利用 cuvid 或者 NVIDIA 、Intel 等硬件厂商实现的硬解码功能,实现硬件解码。但是,在 Android 平台使用 MediaCodec 的解码,却没有实现。

在尝试参考 hw_decode.c 实现 MediaCodec 硬解码的过程中,在 195 行 avcodec_get_hw_config 这一步失败,没有任何 config 列表可供选择。

因此,我们还是参考 demuxing_decoding.c 来实现 Android 平台 MediaCodec 硬解码。

Then,Why?MediaCodec 架构简析

因为 Android 是个平台,其硬件厂商多种多样,而 MediaCodec 并非是一个硬件厂商,因此它并不提供硬件编解码方案。实际上,MediaCodec 更像是一个中间层,通过 openMAX 继承硬件厂商的硬件编解码能力,最终,硬件厂商通过提供符合 openMAX 规范的硬件编解码库。因此,如果仿照 hw_encode.c 来实现,必然会在 avcodec_get_hw_config 这一层找不到合适的配置。

一处改动

那么,我们就完全可以参考 demuxing_decoding.c 来实现 Android 平台 MediaCodec 硬解码功能。其实,基本上全文拷贝到 Android native 代码中,即可使用,只需要改动一处。即 165 行的 dec = avcodec_find_decoder(st->codecpar->codec_id); 改为 dec = avcodec_find_decoder_by_name("h264_mediacodec"); 即可。

为了方便,我们只解码文件中的视频流,同时简化整个流程,基本上,完整代码如下:

static AVFrame *decode_frame = nullptr; int testFFmpegMediaCodec(bool sw) {string filename = "/sdcard/pav/hd.mp4";AVFormatContext *fmt_ctx_ = nullptr;int ret = 0;if (ret = avformat_open_input(&fmt_ctx_, filename.c_str(), nullptr, nullptr) LOGE("Failed to find stream information.");return -1;}int vst_idx = av_find_best_stream(fmt_ctx_, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, false);if (vst_idx LOGE("Failed to open avcodec. ret = %d", ret);return -1;}decode_frame = av_frame_alloc();if (!decode_frame) {LOGE("Failed to allocate frame.");return -1;}decode_frame->format = codec_context->pix_fmt;decode_frame->width = codec_context->width;decode_frame->height = codec_context->height;av_frame_get_buffer(decode_frame, 0);ret = av_image_alloc(video_dst_data, video_dst_linesize, decode_frame->width, decode_frame->height, (AVPixelFormat)decode_frame->format, 1);if (ret LOGD("We allocate %d for raw video buffer.", ret);}AVPacket pkt;av_init_packet(&pkt);pkt.data = nullptr;pkt.size = 0;while (av_read_frame(fmt_ctx_, &pkt) >= 0) {if (pkt.stream_index == vst_idx) {ret = avcodec_send_packet(codec_context, pkt);if (ret ret = avcodec_receive_frame(codec_context, decode_frame);if (ret ret = avcodec_receive_frame(codec_context, decode_frame);if (ret == 0) {// process with decode_frameav_frame_unref(decode_frame);continue;} else if (ret == AVERROR(EAGAIN)) {ret = av_read_frame(fmt_ctx_, &pkt);if (ret == AVERROR_EOF) return 0;if (pkt.stream_index != vst_idx) {av_packet_unref(&pkt); // 注意这一句,缺失将造成内存泄漏continue;}ret = avcodec_send_packet(codec_context, pkt);if (ret


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3