2016-11-18 4 views
0

Я использую следующий код для кодирования серии кадров в MKV или AVI файл с кодировкой FFV1:кодека: ffprobe на файл, закодированный с FFV1 кодеком сообщает «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 в коде.

UPDATE 1:

мне удалось установить правильные кадры в секунду, установив time_base свойство потока:

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

VLC играет выходной файл, но он показывает VLC логотип вместо видео, как будто в файле нет видеопотока.

UPDATE 2:

Вымытый код. Теперь, если я устанавливаю codecId = AV_CODEC_ID_MPEG2VIDEO, выходной файл действителен и воспроизводится как в VLC, так и в MPC-HC. Использование ffprobe на файл с кодировкой FFV1 дает следующий результат:

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

мне удалось создать правильный выходной файл, используя кодек 2.8.6. Я пытался использовать последнюю версию 3.x, но API кажется неустойчивым.