vpx_codec_decode возвращает true, но vpx_codec_get_frame не возвращает кадр

Я хочу сделать плеер, который может запускать файлы webm(vp8/vp9).

Я делаю плеер так, чтобы он каждый раз, когда находил кластер, отправлял кластер в декодер и помещал все кадры в память.

Происходит что-то странное, если я вызываю один и тот же кластер несколько раз, декодер "vpx_codec_get_frame()" перестает находить некоторые кадры, и если я повторяю этот процесс несколько раз, никакие кадры не декодируются из кластера, но каждый раз, прежде чем я пытаюсь декодировать кадр, который я вызываю «vpx_codec_decode()» и возвращает true, даже если vpx_codec_get_frame() возвращает нулевой указатель;

Также на процесс декодирования влияет то, сколько потоков я использую, например, я получаю разное количество кадров из кластера, если использую один поток против 8.

Я подозреваю, что, возможно, потоки не завершаются одновременно с появлением нового кадра буфера, что может вызвать проблему.

Кроме того, я тестирую свой проигрыватель на Mkv-видео, полученном путем слияния трех видео с помощью инструмента mkvmerge, мой проигрыватель должен открывать mkv-файл с несколькими дорожками и одновременно отображать все дорожки.

Вот код: Инициализировал декодер:

 VPXDecoder::VPXDecoder(const WebMDemuxer &demuxer, unsigned threads) :
    m_ctx(NULL),
    m_iter(NULL),
    m_delay(0),
    m_last_space(VPX_CS_UNKNOWN)
{
    if (threads > 8)
        threads = 8;
    else if (threads < 1)
        threads = 1;


    const vpx_codec_dec_cfg_t codecCfg = {
        threads,
        0,
        0
    };
    vpx_codec_iface_t *codecIface = NULL;

    switch (demuxer.getVideoCodec())
    {
        case WebMDemuxer::VIDEO_VP8:
            codecIface = vpx_codec_vp8_dx();
            break;
        case WebMDemuxer::VIDEO_VP9:
            codecIface = vpx_codec_vp9_dx();
            m_delay = threads - 1;
            break;
        default:
            return;
    }

    m_ctx = new vpx_codec_ctx_t;
    if (vpx_codec_dec_init(m_ctx, codecIface, &codecCfg, m_delay > 0 ? VPX_CODEC_USE_FRAME_THREADING : 0))
    {
        delete m_ctx;
        m_ctx = NULL;
    }

}

Вот код, который вызывает vpx_codec_decode():

bool VPXDecoder::decode(const WebMFrame &frame)
{
    m_iter = NULL;
    this->decodead = !vpx_codec_decode(m_ctx, frame.buffer, frame.bufferSize, NULL, 0);
    return  decodead;
}

И, наконец, где изображение должно быть декодировано:

VPXDecoder::IMAGE_ERROR VPXDecoder::getImage(Image &image)
{
    IMAGE_ERROR err = NO_FRAME;
    vpx_image_t *img = NULL;
    img = vpx_codec_get_frame(m_ctx, &m_iter);

    if (/*vpx_image_t *img = vpx_codec_get_frame(m_ctx, &m_iter)*/ img != NULL)
    {
        // It seems to be a common problem that UNKNOWN comes up a lot, yet FFMPEG is somehow getting accurate colour-space information.
        // After checking FFMPEG code, *they're* getting colour-space information, so I'm assuming something like this is going on.
        // It appears to work, at least.
        if (img->cs != VPX_CS_UNKNOWN)
            m_last_space = img->cs;
        if ((img->fmt & VPX_IMG_FMT_PLANAR) && !(img->fmt & (VPX_IMG_FMT_HAS_ALPHA | VPX_IMG_FMT_HIGHBITDEPTH)))
        {
            if (img->stride[0] && img->stride[1] && img->stride[2])
            {
                const int uPlane = !!(img->fmt & VPX_IMG_FMT_UV_FLIP) + 1;
                const int vPlane =  !(img->fmt & VPX_IMG_FMT_UV_FLIP) + 1;

                image.w = img->d_w;
                image.h = img->d_h;
                image.cs = m_last_space;
                image.chromaShiftW = img->x_chroma_shift;
                image.chromaShiftH = img->y_chroma_shift;

                image.planes[0] = img->planes[0];
                image.planes[1] = img->planes[uPlane];
                image.planes[2] = img->planes[vPlane];

                image.linesize[0] = img->stride[0];
                image.linesize[1] = img->stride[uPlane];
                image.linesize[2] = img->stride[vPlane];

                err = NO_ERROR;
            }
        }
        else
        {
            err = UNSUPPORTED_FRAME;
        }
    }
    return err;
}

В моем проекте я использую код из:

https://github.com/zaps166/libsimplewebm

Может ли кто-нибудь порекомендовать другой способ декодирования кадра vp8/9 или устранить проблему с моим кодом?


person Silviu Petrut    schedule 06.05.2020    source источник


Ответы (1)


Я нашел проблему, я строю свой плеер так, чтобы он запрашивал только один кластер за раз, но я не знал, что файлы webm должны иметь ключевой кадр в начале каждого кластера, поэтому решение состояло в том, чтобы сделать ключевой кадр в начало каждого кластера и используйте декодер оттуда.

person Silviu Petrut    schedule 09.09.2020