Декодированный H.264 дает различный размер кадра и контекста

Мы используем avcodec для декодирования H.264, и в некоторых случаях, после изменения разрешения, avcodec запутывается и дает два разных размера для декодированного кадра:

if (av_init_packet_dll)
    av_init_packet_dll(&avpkt);

avpkt.data  = pBuffer;
avpkt.size  = lBuffer;

//  Make sure the output frame has NULLs for the data lines
pAVFrame->data[0]   = NULL;
pAVFrame->data[1]   = NULL;
pAVFrame->data[2]   = NULL;
pAVFrame->data[3]   = NULL;

res = avcodec_decode_video2_dll(pCodecCtx, pAVFrame, &FrameFinished, &avpkt);

DEBUG_LOG("Decoded frame: %d, %d, resulting dimensions: context: %dx%d, frame: %dx%d\n", res, FrameFinished, pCodecCtx->width, pCodecCtx->height, pAVFrame->width, pAVFrame->height);

if (pCodecCtx->width != pAVFrame->width || pCodecCtx->height != pAVFrame->height) {
    OutputDebugStringA("Size mismatch, ignoring frame!\n");
    FrameFinished = 0;
}

if (FrameFinished == 0)
    OutputDebugStringA("Unfinished frame\n");

Это приводит к этому журналу (с некоторыми окружающими линиями):

[5392] Decoded frame: 18690, 1, resulting dimensions: context: 640x480, frame: 640x480
[5392] Set dimensions to 640x480 in DecodeFromMap
[5392] checking size 640x480 against 640x480
[5392] Drawing 640x480, 640x480, 640x480, 0x05DB0060, 0x05DFB5C0, 0x05E0E360, 0x280, to surface 0x03198100, 1280x800
[5392] Drawing 640x480, 640x480, 640x480, 0x05DB0060, 0x05DFB5C0, 0x05E0E360, 0x280, to surface 0x03198100, 1280x800
[5392] Delayed frames seen. Reenabling low delay requires a codec flush.
[5392] Reinit context to 1280x800, pix_fmt: yuvj420p
*[5392] Decoded frame: 54363, 1, resulting dimensions: context: 1280x800, frame: 640x480
[5392] Set dimensions to 1280x800 in DecodeFromMap
[5392] checking size 1280x800 against 640x480
[5392] Found adapter NVIDIA GeForce GTX 650 ({D7B71E3E-4C86-11CF-4E68-7E291CC2C435}) on monitor 00020003
[5392] Found adapter NVIDIA GeForce GTX 650 ({D7B71E3E-4C86-11CF-4E68-7E291CC2C435}) on monitor FA650589
[5392] Creating Direct3D interface on adapter 1 at 1280x800 window 0015050C
[5392] Direct3D created using hardware vertex processing on HAL.
[5392] Creating D3D surface of 1280x800
[5392] Result 0x00000000, got surface 0x03210C40
[5392] Drawing 1280x800, 1280x800, 640x480, 0x02E3B0A0, 0x02E86600, 0x02E993A0, 0x280, to surface 0x03210C40, 1280x800

Строка, в которой эти разрывы отмечены *, pAVFrame содержит старые размеры кадра, в то время как pCodecCtx содержит новые измерения. Когда код рисования, который пытается получить доступ к данным в виде изображения 1280x800, он сталкивается с нарушением доступа.

При уменьшении размера avcodec корректно переходит и устанавливает FrameFinished до 0 и уходит pAVFrame разрешение в 0x0.

Может кто-нибудь подумать, что является причиной этого, почему avcodec сообщает об успехе, но ничего не делает, и что я могу сделать, чтобы правильно решить эту проблему?

Пока проверка несоответствия защищает от этого.

Используемый avcodec собран из git-5cba529 Zeranoe.

FFmpeg version: 2015-03-31 git-5cba529
  libavutil      54. 21.100 / 54. 21.100
  libavcodec     56. 32.100 / 56. 32.100

1 ответ

Решение

AVCodecContext.width/height не обязательно будет идентичным AVFrame.width/height. Для любых практических целей используйте AVFrame.width/height.

AVCodecContext.width/height - это размер текущего состояния декодера, который может быть на несколько кадров впереди AVFrame, возвращаемого пользователю. Пример: предположим, что у вас есть последовательность отображения IBPBP в любом кодеке в стиле MPEG, который закодирован как IPBPB. Давайте предположим, что была масштабируемость, поэтому каждый кадр имеет разный размер. Когда P потребляется, он еще не возвращается, но вместо этого возвращается более ранний кадр. В этом примере, когда P1 декодируется, ничего не возвращается, когда B1 декодируется, оно возвращается (до P1), а когда P2 декодируется, P1 возвращается. Если каждый P имел разный размер, это означает, что когда вы декодируете P2, P1 возвращается пользователю, и, таким образом, AVCodecContext.w/h и AVFrame.w/h различаются (так как один отражает P2, а другой отражает P1). Другой пример, когда это происходит, - когда включена многопоточность на уровне кадра.

Во всех случаях полагайтесь на AVFrame.width / height и игнорируйте AVCodecContext.width/height.

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