解码的 H.264 给出了不同的帧和上下文大小

Decoded H.264 gives different frame and context size

我们使用 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 由 Zeranoe 从 git-5cba529 构建。

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

AVCodecContext.width/height 不保证与 AVFrame.width/height 相同。出于任何实际目的,请使用 AVFrame.width/height.

AVCodecContext.width/height是解码器当前状态的大小,可能比返回给用户的AVFrame提前几帧。示例:假设您在任何 MPEG 样式编解码器中都有一个 IBPBP 显示序列,它被编码为 IPBPB。让我们假设存在可伸缩性,因此每个帧都有不同的大小。当 P 被消耗时,它还没有返回,而是返回了一个更早的帧。在这个例子中,当 P1 被解码时,什么都不返回,当 B1 被解码时,它被返回(在 P1 之前),当 P2 被解码时,P1 被返回。如果每个 P 都有不同的大小,这意味着当你解码 P2 时,P1 返回给用户,因此 AVCodecContext.w/h 和 AVFrame.w/h 是不同的(因为一个反映了 P2,但是另一个反映 P1)。发生这种情况的另一个例子是启用帧级多线程时。

在所有情况下,依赖 AVFrame.width/height,忽略 AVCodecContext.width/height.