libavcodec:使用 FFV1 编解码器编码的文件的 ffprobe 报告 "read_quant_table error"

libavcodec: ffprobe on file encoded with FFV1 codec reports "read_quant_table error"

我正在使用以下代码将一系列帧编码为 FFV1 编码的 mkv 或 avi 文件:

   HRESULT Session::createContext(LPCSTR filename, UINT width, UINT height, UINT fps_num, UINT fps_den) {
    LOG("Exporting to file: ", filename);

    AVCodecID codecId = AV_CODEC_ID_FFV1;
    this->pixelFormat = AV_PIX_FMT_YUV420P;

    this->codec = avcodec_find_encoder(codecId);
    RET_IF_NULL(this->codec, "Could not create codec", E_FAIL);

    this->oformat = av_guess_format(NULL, filename, NULL);
    RET_IF_NULL(this->oformat, "Could not create format", E_FAIL);
    this->oformat->video_codec = codecId;
    this->width = width;
    this->height = height;
    this->codecContext = avcodec_alloc_context3(this->codec);
    RET_IF_NULL(this->codecContext, "Could not allocate context for the codec", E_FAIL);

    this->codecContext->codec = this->codec;
    this->codecContext->codec_id = codecId;

    this->codecContext->pix_fmt = pixelFormat;
    this->codecContext->width = this->width;
    this->codecContext->height = this->height;
    this->codecContext->time_base.num = fps_den;
    this->codecContext->time_base.den = fps_num;

    this->codecContext->gop_size = 1;


    RET_IF_FAILED_AV(avformat_alloc_output_context2(&fmtContext, this->oformat, NULL, NULL), "Could not allocate format context", E_FAIL);
    RET_IF_NULL(this->fmtContext, "Could not allocate format context", E_FAIL);

    this->fmtContext->oformat = this->oformat;
    this->fmtContext->video_codec_id = codecId;

    this->stream = avformat_new_stream(this->fmtContext, this->codec);
    RET_IF_NULL(this->stream, "Could not create new stream", E_FAIL);
    this->stream->time_base = this->codecContext->time_base;
    RET_IF_FAILED_AV(avcodec_parameters_from_context(this->stream->codecpar, this->codecContext), "Could not convert AVCodecContext to AVParameters", E_FAIL);

    if (this->fmtContext->oformat->flags & AVFMT_GLOBALHEADER)
    {
        this->codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
    }

    av_opt_set_int(this->codecContext->priv_data, "coder", 0, 0);
    av_opt_set_int(this->codecContext->priv_data, "context", 1, 0);
    av_opt_set_int(this->codecContext->priv_data, "slicecrc", 1, 0);
    //av_opt_set_int(this->codecContext->priv_data, "slicecrc", 1, 0);
    //av_opt_set_int(this->codecContext->priv_data, "pix_fmt", pixelFormat, 0);

    RET_IF_FAILED_AV(avcodec_open2(this->codecContext, this->codec, NULL), "Could not open codec", E_FAIL);
    RET_IF_FAILED_AV(avio_open(&this->fmtContext->pb, filename, AVIO_FLAG_WRITE), "Could not open output file", E_FAIL);
    RET_IF_NULL(this->fmtContext->pb, "Could not open output file", E_FAIL);
    RET_IF_FAILED_AV(avformat_write_header(this->fmtContext, NULL), "Could not write header", E_FAIL);

    frame = av_frame_alloc();
    RET_IF_NULL(frame, "Could not allocate frame", E_FAIL);
    frame->format = this->codecContext->pix_fmt;
    frame->width = width;
    frame->height = height;
    return S_OK;
}

HRESULT Session::writeFrame(IMFSample * pSample) {
    IMFMediaBuffer *mediaBuffer = NULL;
    BYTE *pDataNV12 = NULL;
    DWORD length;

    RET_IF_FAILED(pSample->ConvertToContiguousBuffer(&mediaBuffer), "Could not convert IMFSample to contagiuous buffer", E_FAIL);
    RET_IF_FAILED(mediaBuffer->GetCurrentLength(&length), "Could not get buffer length", E_FAIL);
    RET_IF_FAILED(mediaBuffer->Lock(&pDataNV12, NULL, NULL), "Could not lock the buffer", E_FAIL);
    BYTE *pDataYUV420P = new BYTE[length];
    this->convertNV12toYUV420P(pDataNV12, pDataYUV420P, this->width, this->height);
    RET_IF_FAILED(av_image_fill_arrays(frame->data, frame->linesize, pDataYUV420P, pixelFormat, this->width, this->height, 1), "Could not fill the frame with data from the buffer", E_FAIL);
    LOG_IF_FAILED(mediaBuffer->Unlock(), "Could not unlock the buffer");

    frame->pts = av_rescale_q(this->pts++, this->codecContext->time_base, this->stream->time_base);

    AVPacket pkt;

    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;

    RET_IF_FAILED_AV(avcodec_send_frame(this->codecContext, frame), "Could not send the frame to the encoder", E_FAIL);
    delete[] pDataYUV420P;
    if (SUCCEEDED(avcodec_receive_packet(this->codecContext, &pkt))) {
        RET_IF_FAILED_AV(av_interleaved_write_frame(this->fmtContext, &pkt), "Could not write the received packet.", E_FAIL);
    }

    av_packet_unref(&pkt);

    return S_OK;
}

HRESULT Session::endSession() {
    LOG("Ending session...");

    LOG("Closing files...")
    LOG_IF_FAILED_AV(av_write_trailer(this->fmtContext), "Could not finalize the output file.");
    LOG_IF_FAILED_AV(avio_close(this->fmtContext->pb), "Could not close the output file.");
    LOG_IF_FAILED_AV(avcodec_close(this->codecContext), "Could not close the codec.");
    av_free(this->codecContext);
    LOG("Done.")
    return S_OK;
}

问题是生成的文件无法在 VLC 或 MPC-HC 中播放。但是,MPC-HC 在文件属性中报告以下信息:

General
Unique ID                      : 202978442142665779317960161865934977227 (0x98B439D9BE859109BD5EC00A62A238CB)
Complete name                  : T:\Test.mkv
Format                         : Matroska
Format version                 : Version 4 / Version 2
File size                      : 24.6 MiB
Duration                       : 147ms
Overall bit rate               : 1 401 Mbps
Writing application            : Lavf57.57.100
Writing library                : Lavf57.57.100

Video
ID                             : 1
Format                         : FFV1
Format version                 : Version 0
Codec ID                       : V_MS/VFW/FOURCC / FFV1
Duration                       : 147ms
Width                          : 1 280 pixels
Height                         : 720 pixels
Display aspect ratio           : 16:9
Frame rate mode                : Constant
Frame rate                     : 1 000.000 fps
Color space                    : YUV
Chroma subsampling             : 4:2:0
Bit depth                      : 8 bits
Compression mode               : Lossless
Default                        : Yes
Forced                         : No
DURATION                       : 00:00:00.147000000
coder_type                     : Golomb Rice

需要注意的是,它报告 1000 FPS,这很奇怪,因为我在代码中设置了 AVCodecContext::time_base

更新 1:

我设法通过设置流的 time_base 属性 来设置正确的 fps:

this->stream->time_base.den = fps_num;
this->stream->time_base.num = fps_den;

VLC 播放输出文件,但它显示 VLC 徽标而不是视频,就好像文件中没有视频流一样。

更新 2:

清理了代码。现在,如果我设置 codecId = AV_CODEC_ID_MPEG2VIDEO,则输出文件有效并且可以在 VLC 和 MPC-HC 中播放。在 FFV1 编码的文件上使用 ffprobe 会产生以下结果:

C:\root\apps\ffmpeg>ffprobe.exe t:\test.avi
ffprobe version 3.2 Copyright (c) 2007-2016 the FFmpeg developers
  built with gcc 5.4.0 (GCC)
  configuration: --disable-static --enable-shared --enable-gpl --enable-version3 --disable-w32threads --enable-dxva2 --enable-libmfx --enable-nvenc --enable-avisynth --enable-bzlib --enable-libebur128 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-lzma --enable-decklink --enable-zlib
  libavutil      55. 34.100 / 55. 34.100
  libavcodec     57. 64.100 / 57. 64.100
  libavformat    57. 56.100 / 57. 56.100
  libavdevice    57.  1.100 / 57.  1.100
  libavfilter     6. 65.100 /  6. 65.100
  libswscale      4.  2.100 /  4.  2.100
  libswresample   2.  3.100 /  2.  3.100
  libpostproc    54.  1.100 / 54.  1.100
[ffv1 @ 00000000006b83a0] read_quant_table error
Input #0, avi, from 't:\test.avi':
  Metadata:
    encoder         : Lavf57.56.100
  Duration: 00:00:04.94, start: 0.000000, bitrate: 107005 kb/s
    Stream #0:0: Video: ffv1 (FFV1 / 0x31564646), yuv420p, 1280x720, 107717 kb/s, 29.97 fps, 29.97 tbr, 29.97 tbn, 29.97 tbc

我设法使用 libavcodec 2.8.6 创建了有效的输出文件。我试图使用最新的 3.x 版本,但 API 似乎不稳定。