不吃药的少年 2021-12-22 09:58 采纳率: 100%
浏览 148
已结题

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

问题遇到的现象和发生背景
    您好,看到你的帖子非常高兴,因为我遇到了和你一样的问题,我也是在ffmpeg 用mediacode硬解编译ndk工程,然后放在硬解出来的纹理给unity,然后avcodec_get_hw_config返回的config是nullptr.看到你的帖子之后,尝试按照https://ffmpeg.org/doxygen/3.4/demuxing_decoding_8c-example.html。然后还是在avcodec_open2失败了, 
问题相关代码,请勿粘贴截图
static int open_codec_context(int *stream_idx,
                              AVCodecContext **dec_ctx, AVFormatContext *fmt_ctx, enum AVMediaType type)
{
    int ret, stream_index;
    AVStream *st;
    AVCodec *dec = NULL;
    AVDictionary *opts = NULL;
    ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
    if (ret < 0) {
        LOGD("Could not find %s stream in input file '%s'\n", av_get_media_type_string(type));
        return ret;
    } else {
        stream_index = ret;
        st = fmt_ctx->streams[stream_index];
        /* find decoder for the stream */
        //dec = avcodec_find_decoder(st->codecpar->codec_id);
        dec = avcodec_find_decoder_by_name("h264_mediacodec");
        if (!dec) {
            LOGD("Failed to find %s codec\n", av_get_media_type_string(type));
            return AVERROR(EINVAL);
        }
        /* Allocate a codec context for the decoder */
        *dec_ctx = avcodec_alloc_context3(dec);
        if (!*dec_ctx) {
            LOGD("Failed to allocate the %s codec context\n",
                 av_get_media_type_string(type));
            return AVERROR(ENOMEM);
        }
        /* Copy codec parameters from input stream to output codec context */
        if ((ret = avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0) {
            LOGD("Failed to copy %s codec parameters to decoder context\n",
                 av_get_media_type_string(type));
            return ret;
        }
        /* Init the decoders, with or without reference counting */
        av_dict_set(&opts, "refcounted_frames", refcount ? "1" : "0", 0);
        if ((ret = avcodec_open2(*dec_ctx, dec, &opts)) < 0) {
            LOGD("Failed to open %d codec\n", ret);
            return ret;
        }
        *stream_idx = stream_index;
    }
    return 0;
}

static int decodeMainV2()
{
    AVFormatContext *input_ctx = NULL;
    int video_stream, ret;
    AVStream *video = NULL;
    AVCodecContext *decoder_ctx = NULL;
    AVCodec *decoder = NULL;
    AVPacket packet;
    enum AVHWDeviceType type;
    int i;
    av_register_all();

    const char *mediacodec = "mediacodec";

    type = av_hwdevice_find_type_by_name(mediacodec);
    if (type == AV_HWDEVICE_TYPE_NONE) {
        LOGD("Device type %s is not supported.\n", mediacodec);
        LOGD("Available device types:");
        while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)
            LOGD(" %s", av_hwdevice_get_type_name(type));
        LOGD("\n");
        return -1;
    }

    /* open the input file */
    if (avformat_open_input(&input_ctx, mp4_url, NULL, NULL) != 0) {
        LOGD("Cannot open input file '%s'\n", mp4_url);
        return -1;
    }

    if (avformat_find_stream_info(input_ctx, NULL) < 0) {
        LOGD("Cannot find input stream information.\n");
        return -1;
    }

    if(open_codec_context(&video_stream, &decoder_ctx, input_ctx, AVMEDIA_TYPE_VIDEO)>=0){
        LOGD("open_codec_context success");
    }else
        return -1;


    /* actual decoding and dump the raw data */
    while (ret >= 0 || ret == -11) {
        if ((ret = av_read_frame(input_ctx, &packet)) < 0)
            break;

        if (video_stream == packet.stream_index)
            ret = decode_write(decoder_ctx, &packet);

        av_packet_unref(&packet);
    }

    /* flush the decoder */
    packet.data = NULL;
    packet.size = 0;
    av_packet_unref(&packet);

    avcodec_free_context(&decoder_ctx);
    avformat_close_input(&input_ctx);
    av_buffer_unref(&hw_device_ctx);

    return 0;
}

运行结果及报错内容
      在avcodec_open2 failed
我的解答思路和尝试过的方法
      我有认为是我编的库的问题。我的ffmpeg库版本是4.3.3,我在网上找了一份32位的库,仍然是相同的结果,我想问一下你的ffmpeg的库的版本?如果方便的话能不能提供一下你的ffmpeg库(32位),不方便的话没事,我这儿也可以编译,我想确定不是库的问题。如果你在解决这个问题还有那些需要注意的地方也可以指点一下
我想要达到的结果
    我想在ndk跑通硬解
  • 写回答

1条回答 默认 最新

  • 深海Enoch 2021-12-22 10:26
    关注

    1,avcodec_open2 的返回值是什么?代表了什么样的错误?你可以使用 av_make_error_string 这个方法来获取错误原因,确定到底是什么原因导致的 avcodec_open2 失败。
    2,怀疑你的库有问题的话,可能是没开启 --enable-mediacodec 这个选项。 我用的 FFmpeg 库也是 32 位,版本貌似是 4.2.2,但这个不是问题的关键。问题的关键是你是否在编译时开启了合适的选项 --enable-mediacodec --enable-decoder=h264_mediacodec,这两个选项好像有一个无效的。
    3,即使 avcodec_open2 成功,整个 FFmpeg + MediaCodec 硬解码跑通,感觉效果也不会很理想。我的实验结果是,FFmpeg + MediaCodec 的硬解码结果很糟糕,1080P 的视频在很多情况下解码会出现花屏。所以我后来放弃了使用 FFmpeg + MediaCodec 的方法,转而使用纯 NDKMediaCodec 方法来实现 Android 平台硬解码,具体可参考我的文章https://blog.csdn.net/u014248312/article/details/121970559,里面有一个我的 NDKMediaCodecDemo(https://github.com/Enoch-Liu/NdkMediaCodecDemo) ,你可以参考实现。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 12月30日
  • 已采纳回答 12月22日
  • 创建了问题 12月22日

悬赏问题

  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改