2016-11-18 45 views
0

我使用以下代碼來一系列的幀編碼爲與FFV1編碼的MKV或avi文件:libavcodec的:與FFV1編解碼器編碼文件ffprobe報告「read_quant_table錯誤」

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 

回答

0

我設法用libavccodec 2.8.6創建有效的輸出文件。我試圖使用最新的3.x版本,但API似乎不穩定。