Невозможно инициализировать «h264_mediacodec» для ускоренного декодирования, FFMPEG, Android

Я пытаюсь создать ускоренное декодирование на Android через JNI и следую этому примеру, но, к сожалению, avcodec_get_hw_config возвращает nullptr.

Я также пробовал использовать avcodec_find_decoder_by_name("h264_mediacodec"), также возвращает nullptr.

Я собрал ffmpeg (версия 4.4), используя этот скрипт с флагами:

--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \

При настройке сборки я увидел в логах WARNING: Option --enable-hwaccel=h264_mediacodec did not match anything, что вообще странно. FFMPEG 4.4 должен поддерживать ускоренное декодирование с использованием медиакодека.

Обновлено: (предоставляя минимальный воспроизводимый пример)

В методе JNI я инициализирую входной контекст декодера и инициализирую декодер:

    void Decoder::initInputContext(
        const std::string& source,
        AVDictionary* options
    ) { // open input, and allocate format context
        if (
            avformat_open_input(
                &m_inputFormatContext,
                source.c_str(),
                NULL,
                options ? &options : nullptr
            ) < 0
        ) {
            throw FFmpegException(
                fmt::format("Decoder: Could not open source {}", source)
            );
        }
 
        // retrieve stream information
        if (avformat_find_stream_info(m_inputFormatContext, NULL) < 0) {
            throw FFmpegException(
                "Decoder: Could not find stream information"
            );
        }

        // get audio and video streams
        for (size_t i = 0; i < m_inputFormatContext->nb_streams; i++) {
            AVStream* inStream = m_inputFormatContext->streams[i];
            AVCodecParameters* inCodecpar = inStream->codecpar;
            if (
                inCodecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
                inCodecpar->codec_type != AVMEDIA_TYPE_VIDEO
            ) {
                continue;
            }

            if (inCodecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
                m_videoStreamIdx = i;
                m_videoStream = inStream;

                m_codecParams.videoCodecId = m_videoStream->codecpar->codec_id;
                m_codecParams.fps = static_cast<int>(av_q2d(m_videoStream->r_frame_rate) + 0.5);
                m_codecParams.clockrate = m_videoStream->time_base.den;

                spdlog::debug(
                    "Decoder: fps: {}, clockrate: {}",
                    m_codecParams.fps,
                    m_codecParams.clockrate
                )
                ;
            }

            if (inCodecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
                m_audioStreamIdx = i;
                m_audioStream = inStream;

                m_codecParams.audioCodecId = m_audioStream->codecpar->codec_id;
                m_codecParams.audioSamplerate = m_audioStream->codecpar->sample_rate;
                m_codecParams.audioChannels = m_audioStream->codecpar->channels;
                m_codecParams.audioProfile = m_audioStream->codecpar->profile;

                spdlog::debug(
                    "Decoder: audio samplerate: {}, audio channels: {}, x: {}",
                    m_codecParams.audioSamplerate,
                    m_codecParams.audioChannels,
                    m_audioStream->codecpar->channels
                )
                ;
            }
        }
    }

    void Decoder::initDecoder() {
        AVCodecParameters* videoStreamCodecParams = m_videoStream->codecpar;

        m_swsContext = sws_getContext(
                videoStreamCodecParams->width, videoStreamCodecParams->height, m_pixFormat,
                videoStreamCodecParams->width, videoStreamCodecParams->height, m_targetPixFormat,
                SWS_BICUBIC, nullptr, nullptr, nullptr);

        // find best video stream info and decoder
        int ret = av_find_best_stream(m_inputFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, &m_decoder, 0);
        if (ret < 0) {
            throw FFmpegException(
                    "Decoder: Cannot find a video stream in the input file"
            );
        }

        if (!m_decoder) {
            throw FFmpegException(
                    "Decoder: Can't find decoder"
            );
        }

        // search for supported HW decoder configuration
        for (size_t i = 0;; i++) {
            const AVCodecHWConfig* config = avcodec_get_hw_config(m_decoder, i);
            if (!config) {
                spdlog::error(
                    "Decoder {} does not support device type {}. "
                    "Will use SW decoder...",
                    m_decoder->name,
                    av_hwdevice_get_type_name(m_deviceType)
                );
                break;
            }

            if (
                config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
                config->device_type == m_deviceType
            ) {
                // set up pixel format for HW decoder
                g_hwPixFmt = config->pix_fmt;
                m_hwDecoderSupported = true;
                break;
            }
        }
    }

А у меня есть AVHWDeviceType m_deviceType{AV_HWDEVICE_TYPE_MEDIACODEC};

avcodec_get_hw_config возвращает nullptr.

Любая помощь приветствуется.

Вы обязаны опубликовать минимально воспроизводимый пример здесь, в рамках вашего вопроса, а не ссылку на какой-либо другой сайт.

Rob 22.02.2024 09:24
1
1
207
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я нашел этот пример, проследил, как он настраивает CMakeLists.txt и инициализирует декодер, и у меня это сработало.

Помимо того, что вы добавили, нам также нужно добавить --enable-hwaccels для компиляции ffmpeg для Android. Если ваша версия ffmpeg меньше 6.0, вам следует вызвать av_jni_set_java_vm, когда JNI_OnLoad. Надеюсь, я смогу вам помочь.

Другие вопросы по теме