2017-10-08 8 views
1

ffmpeg 3.3.3 APIを使用して、任意のフレームを取り込んでビデオを構築できるクラスをまとめようとしています。私はこの例を見ても良い例を見つけようと苦労していますが、例はまだ非難されている関数を使用しているようです。ヘッダーのドキュメントを使ってパッチを当てようとしています。新しいバージョン。私は出力に符号化されたパケットを書き込むためにav_interleaved_write_frameを使用する場合はav_interleaved_write_frameを使用していてもavio_writeを使用していない場合はmoov atom not foundが表示される

はその後ffprobeは、次の出力:

[mov,mp4,m4a,3gp,3g2,mj2 @ 0000000002760120] moov atom not found0 
X:\Diagnostics.mp4: Invalid data found when processing input 

ffplayは、このメソッドを使用して生成されたファイルを再生することができません。

私が代わりにavio_writeの呼び出しのためにそれを交換した場合、ffprobeではなく、出力:

Input #0, h264, from 'X:\Diagnostics.mp4': 
    Duration: N/A, bitrate: N/A 
    Stream #0:0: Video: h264 (Main), yuv420p(progressive), 672x380 [SAR 1:1 DAR 168:95], 25 fps, 25 tbr, 1200k tbn, 50 tbc 

を、それは終わりに向かって迎えるまでに出力した場合ffplayはほとんどは、このファイルを再生することができます:

Input #0, h264, from 'X:\Diagnostics.mp4': 0KB sq= 0B f=0/0 
    Duration: N/A, bitrate: N/A 
    Stream #0:0: Video: h264 (Main), yuv420p(progressive), 672x380 [SAR 1:1 DAR 168:95], 25 fps, 25 tbr, 1200k tbn, 50 tbc 
[h264 @ 000000000254ef80] error while decoding MB 31 22, bytestream -65 
[h264 @ 000000000254ef80] concealing 102 DC, 102 AC, 102 MV errors in I frame 
    nan M-V: nan fd= 1 aq= 0KB vq= 0KB sq= 0B f=0/0 

VLCはどちらの方法でもファイルを再生できません。第2の方法のファイルは、単一の黒いフレームを表示し、ビデオ出力を隠す。最初は何も表示されません。どちらもビデオ期間を与えません。

ここで何が起こっているのでしょうか?私は有効なフレームの良い塊を取得しているので、私の解決策は近いと思います。

コード:

void main() 
{ 
    OutputStream Stream("Output.mp4", 672, 380, 25, true); 
    Stream.Initialize(); 

    int i = 100; 
    while(i--) 
    { 
     //... Generate a frame 

     Stream.WriteFrame(Frame); 
    } 
    Stream.CloseFile(); 
} 

OutputStream::OutputStream(const std::string& Path, unsigned int Width, unsigned int Height, int Framerate, bool IsBGR) 
: Stream() 
, FrameIndex(0) 
{ 
    auto& ID = *m_InternalData; 

    ID.Path = Path; 

    ID.Width = Width; 
    ID.Height= Height; 
    ID.Framerate.num = Framerate; 
    ID.Framerate.den = 1; 

    ID.PixelFormat = IsBGR ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_RGB24; 
    ID.CodecID = AV_CODEC_ID_H264; 
    ID.CodecTag = 0; 

    ID.AspectRatio.num = 1; 
    ID.AspectRatio.den = 1; 
} 

CameraStreamError OutputStream::Initialize() 
{ 
    av_log_set_callback(&InputStream::LogCallback); 
    av_register_all(); 
    avformat_network_init(); 

    auto& ID = *m_InternalData; 

    av_init_packet(&ID.Packet); 

    int Result = avformat_alloc_output_context2(&ID.FormatContext, nullptr, nullptr, ID.Path.c_str()); 
    if(Result < 0 || !ID.FormatContext) 
    { 
     STREAM_ERROR(UnknownError); 
    } 

    AVCodec* Encoder = avcodec_find_encoder(ID.CodecID); 

    if(!Encoder) 
    { 
     STREAM_ERROR(NoH264Support); 
    } 

    AVStream* OutStream = avformat_new_stream(ID.FormatContext, Encoder); 
    if(!OutStream) 
    { 
     STREAM_ERROR(UnknownError); 
    } 

    ID.CodecContext = avcodec_alloc_context3(Encoder); 
    if(!ID.CodecContext) 
    { 
     STREAM_ERROR(NoH264Support); 
    } 

    ID.CodecContext->time_base = av_inv_q(ID.Framerate); 

    { 
     AVCodecParameters* CodecParams = OutStream->codecpar; 

     CodecParams->width = ID.Width; 
     CodecParams->height = ID.Height; 
     CodecParams->format = AV_PIX_FMT_YUV420P; 
     CodecParams->codec_id = ID.CodecID; 
     CodecParams->codec_type = AVMEDIA_TYPE_VIDEO; 
     CodecParams->profile = FF_PROFILE_H264_MAIN; 
     CodecParams->level = 40; 

     Result = avcodec_parameters_to_context(ID.CodecContext, CodecParams); 
     if(Result < 0) 
     { 
      STREAM_ERROR(EncoderCreationError); 
     } 
    } 

    if(ID.IsVideo) 
    { 
     ID.CodecContext->width = ID.Width; 
     ID.CodecContext->height = ID.Height; 
     ID.CodecContext->sample_aspect_ratio = ID.AspectRatio; 
     ID.CodecContext->time_base = av_inv_q(ID.Framerate); 

     if(Encoder->pix_fmts) 
     { 
      ID.CodecContext->pix_fmt = Encoder->pix_fmts[0]; 
     } 
     else 
     { 
      ID.CodecContext->pix_fmt = ID.PixelFormat; 
     } 
    } 
    //Snip 

    Result = avcodec_open2(ID.CodecContext, Encoder, nullptr); 
    if(Result < 0) 
    { 
     STREAM_ERROR(EncoderCreationError); 
    } 

    Result = avcodec_parameters_from_context(OutStream->codecpar, ID.CodecContext); 
    if(Result < 0) 
    { 
     STREAM_ERROR(EncoderCreationError); 
    } 

    if(ID.FormatContext->oformat->flags & AVFMT_GLOBALHEADER) 
    { 
     ID.CodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; 
    } 

    OutStream->time_base = ID.CodecContext->time_base; 
    OutStream->avg_frame_rate= av_inv_q(OutStream->time_base); 

    if(!(ID.FormatContext->oformat->flags & AVFMT_NOFILE)) 
    { 
     Result = avio_open(&ID.FormatContext->pb, ID.Path.c_str(), AVIO_FLAG_WRITE); 
     if(Result < 0) 
     { 
      STREAM_ERROR(FileNotWriteable); 
     } 
    } 

    Result = avformat_write_header(ID.FormatContext, nullptr); 
    if(Result < 0) 
    { 
     STREAM_ERROR(WriteFailed); 
    } 

    ID.Output = std::make_unique<FFMPEG::Frame>(ID.CodecContext->width, ID.CodecContext->height, ID.CodecContext->pix_fmt); 

    ID.ConversionContext = sws_getCachedContext(
     ID.ConversionContext, 
     ID.Width, 
     ID.Height, 
     ID.PixelFormat, 
     ID.CodecContext->width, 
     ID.CodecContext->height, 
     ID.CodecContext->pix_fmt, 
     SWS_BICUBIC, 
     NULL, 
     NULL, 
     NULL); 

    return CameraStreamError::Success; 
} 

CameraStreamError OutputStream::WriteFrame(FFMPEG::Frame* Frame) 
{ 
    auto& ID = *m_InternalData; 

    ID.Output->Prepare(); 

    int OutputSliceSize = sws_scale(m_InternalData->ConversionContext, Frame->GetFrame()->data, Frame->GetFrame()->linesize, 0, Frame->GetHeight(), ID.Output->GetFrame()->data, ID.Output->GetFrame()->linesize); 

    ID.Output->GetFrame()->pts = ID.CodecContext->frame_number; 

    int Result = avcodec_send_frame(GetData().CodecContext, ID.Output->GetFrame()); 
    if(Result == AVERROR(EAGAIN)) 
    { 
     CameraStreamError ResultErr = SendAll(); 
     if(ResultErr != CameraStreamError::Success) 
     { 
      return ResultErr; 
     } 
     Result = avcodec_send_frame(GetData().CodecContext, ID.Output->GetFrame()); 
    } 

    if(Result == 0) 
    { 
     CameraStreamError ResultErr = SendAll(); 
     if(ResultErr != CameraStreamError::Success) 
     { 
      return ResultErr; 
     } 
    } 

    FrameIndex++; 

    return CameraStreamError::Success; 
} 

CameraStreamError OutputStream::SendAll(void) 
{ 
    auto& ID = *m_InternalData; 

    int Result; 
    do 
    { 
     AVPacket TempPacket = {}; 
     av_init_packet(&TempPacket); 

     Result = avcodec_receive_packet(GetData().CodecContext, &TempPacket); 
     if(Result == 0) 
     { 
      av_packet_rescale_ts(&TempPacket, ID.CodecContext->time_base, ID.FormatContext->streams[0]->time_base); 

      TempPacket.stream_index = ID.FormatContext->streams[0]->index; 

      //avio_write(ID.FormatContext->pb, TempPacket.data, TempPacket.size); 
      Result = av_interleaved_write_frame(ID.FormatContext, &TempPacket); 
      if(Result < 0) 
      { 
       STREAM_ERROR(WriteFailed); 
      } 

      av_packet_unref(&TempPacket); 
     } 
     else if(Result != AVERROR(EAGAIN)) 
     { 
      continue; 
     } 
     else if(Result != AVERROR_EOF) 
     { 
      break; 
     } 
     else if(Result < 0) 
     { 
      STREAM_ERROR(WriteFailed); 
     } 
    } while (Result == 0); 

    return CameraStreamError::Success; 
} 

CameraStreamError OutputStream::CloseFile() 
{ 
    auto& ID = *m_InternalData; 

    while(true) 
    { 
     //Flush 
     int Result = avcodec_send_frame(ID.CodecContext, nullptr); 
     if(Result == 0) 
     { 
      CameraStreamError StrError = SendAll(); 
      if(StrError != CameraStreamError::Success) 
      { 
       return StrError; 
      } 
     } 
     else if(Result == AVERROR_EOF) 
     { 
      break; 
     } 
     else 
     { 
      STREAM_ERROR(WriteFailed); 
     } 
    } 

    int Result = av_write_trailer(ID.FormatContext); 
    if(Result < 0) 
    { 
     STREAM_ERROR(WriteFailed); 
    } 

    if(!(ID.FormatContext->oformat->flags& AVFMT_NOFILE)) 
    { 
     Result = avio_close(ID.FormatContext->pb); 
     if(Result < 0) 
     { 
      STREAM_ERROR(WriteFailed); 
     } 
    } 

    return CameraStreamError::Success; 
} 

注意私はいくつかのことを簡素化し、他の場所だった数ビットをインライン化しました。私はまた、ファイルが閉じられた後に起こる何かが無関係なので、すべてのシャットダウンコードを削除しました。

完全レポここに:https://github.com/IanNorris/Witnessこれを複製すると、問題は「診断」出力にあり、出力ファイルは問題ありません。 Xには2つのハードコードされたパスがあります。

答えて

3

avio_write()ファイルはMP4ファイルではなく、単純に圧縮されたH.264パケットを順番に並べたものです(AnnexB H.264とも呼ばれます)。

av_interleaved_frame_write()を使用してコンテナにファイルを書き込むには、すべての圧縮ビデオ/オーディオパケットの後にavformat_write_header() beforeとav_write_trailer()を呼び出す必要があります。これがなければ、ファイルにはグローバルヘッダー(MP4のmoovチャンクなど)が含まれず、外部アプリケーションからは有効なファイルとして認識されません。

さらに詳しい説明は、muxing documentationを参照してください。

+0

ありがとうございます!私は実際にこれらのコードを持っていましたが、あなたの答えは、それが呼び出されたことを確認させました。それは両方のファイルではなく、最初のファイルのみでした。これは、消失したデストラクタが原因です。今は期待どおりに動作します。 – icStatic

関連する問題