title: "moov atom not found" when using av_interleaved_write_frame but not avio_write
body: <p>I am attempting to put together a class that can take arbitrary frames and construct a video from it using the ffmpeg 3.3.3 API. I've been struggling to find a good example for this as the examples still seem to be using deprecated functions, so I've attempted to patch this using the documentation in the headers and by referring to a few github repos that seem to be using the new version.</p>
  
  <p>If I use av_interleaved_write_frame to write the encoded packets to the output then ffprobe outputs the following:</p>
  
  <pre><code>[mov,mp4,m4a,3gp,3g2,mj2 @ 0000000002760120] moov atom not found0
  X:\Diagnostics.mp4: Invalid data found when processing input
  </code></pre>
  
  <p>ffplay is unable to play the file generated using this method.</p>
  
  <p>If I instead swap it out for a call to avio_write, ffprobe instead outputs:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>ffplay can <em>mostly</em> play this file until it gets towards the end, when it outputs:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>VLC cannot play files from either method. The second method's file displays a single black frame then hides the video output. The first does not display anything. Neither of them give a video duration.</p>
  
  <p>Does anyone have any ideas what's happening here? I assume my solution is close to working as I'm getting a good chunk of valid frames coming through.</p>
  
  <p>Code:</p>
  
  <pre><code>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&amp; Path, unsigned int Width, unsigned int Height, int Framerate, bool IsBGR )
  : Stream()
  , FrameIndex( 0 )
  {
      auto&amp; 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( &amp;InputStream::LogCallback );
      av_register_all();
      avformat_network_init();
  
      auto&amp; ID = *m_InternalData;
  
      av_init_packet( &amp;ID.Packet );
  
      int Result = avformat_alloc_output_context2( &amp;ID.FormatContext, nullptr, nullptr, ID.Path.c_str() );
      if( Result &lt; 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-&gt;time_base = av_inv_q(ID.Framerate);
  
      {
          AVCodecParameters* CodecParams = OutStream-&gt;codecpar;
  
          CodecParams-&gt;width = ID.Width;
          CodecParams-&gt;height = ID.Height;
          CodecParams-&gt;format = AV_PIX_FMT_YUV420P;
          CodecParams-&gt;codec_id = ID.CodecID;
          CodecParams-&gt;codec_type = AVMEDIA_TYPE_VIDEO;
          CodecParams-&gt;profile = FF_PROFILE_H264_MAIN;
          CodecParams-&gt;level = 40;
  
          Result = avcodec_parameters_to_context( ID.CodecContext, CodecParams );
          if( Result &lt; 0 )
          {
              STREAM_ERROR( EncoderCreationError );
          }
      }
  
      if( ID.IsVideo )
      {
          ID.CodecContext-&gt;width = ID.Width;
          ID.CodecContext-&gt;height = ID.Height;
          ID.CodecContext-&gt;sample_aspect_ratio = ID.AspectRatio;
          ID.CodecContext-&gt;time_base = av_inv_q(ID.Framerate);
  
          if( Encoder-&gt;pix_fmts )
          {
              ID.CodecContext-&gt;pix_fmt = Encoder-&gt;pix_fmts[0];
          }
          else
          {
              ID.CodecContext-&gt;pix_fmt = ID.PixelFormat;
          }
      }
      //Snip
  
      Result = avcodec_open2( ID.CodecContext, Encoder, nullptr );
      if( Result &lt; 0 )
      {
          STREAM_ERROR( EncoderCreationError );
      }
  
      Result = avcodec_parameters_from_context( OutStream-&gt;codecpar, ID.CodecContext );
      if( Result &lt; 0 )
      {
          STREAM_ERROR( EncoderCreationError );
      }
  
      if( ID.FormatContext-&gt;oformat-&gt;flags &amp; AVFMT_GLOBALHEADER )
      {
          ID.CodecContext-&gt;flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
      }
  
      OutStream-&gt;time_base = ID.CodecContext-&gt;time_base;
      OutStream-&gt;avg_frame_rate= av_inv_q(OutStream-&gt;time_base);
  
      if( !( ID.FormatContext-&gt;oformat-&gt;flags &amp; AVFMT_NOFILE ) )
      {
          Result = avio_open( &amp;ID.FormatContext-&gt;pb, ID.Path.c_str(), AVIO_FLAG_WRITE );
          if( Result &lt; 0 )
          {
              STREAM_ERROR( FileNotWriteable );
          }
      }
  
      Result = avformat_write_header( ID.FormatContext, nullptr );
      if( Result &lt; 0 )
      {
          STREAM_ERROR( WriteFailed );
      }
  
      ID.Output = std::make_unique&lt;FFMPEG::Frame&gt;( ID.CodecContext-&gt;width, ID.CodecContext-&gt;height, ID.CodecContext-&gt;pix_fmt );
  
      ID.ConversionContext = sws_getCachedContext(
          ID.ConversionContext,
          ID.Width,
          ID.Height,
          ID.PixelFormat,
          ID.CodecContext-&gt;width,
          ID.CodecContext-&gt;height,
          ID.CodecContext-&gt;pix_fmt,
          SWS_BICUBIC,
          NULL,
          NULL,
          NULL );
  
      return CameraStreamError::Success;
  }
  
  CameraStreamError OutputStream::WriteFrame( FFMPEG::Frame* Frame )
  {
      auto&amp; ID = *m_InternalData;
  
      ID.Output-&gt;Prepare();
  
      int OutputSliceSize = sws_scale( m_InternalData-&gt;ConversionContext, Frame-&gt;GetFrame()-&gt;data, Frame-&gt;GetFrame()-&gt;linesize, 0, Frame-&gt;GetHeight(), ID.Output-&gt;GetFrame()-&gt;data, ID.Output-&gt;GetFrame()-&gt;linesize );
  
      ID.Output-&gt;GetFrame()-&gt;pts = ID.CodecContext-&gt;frame_number;
  
      int Result = avcodec_send_frame( GetData().CodecContext, ID.Output-&gt;GetFrame() );
      if( Result == AVERROR(EAGAIN) )
      {
          CameraStreamError ResultErr = SendAll();
          if( ResultErr != CameraStreamError::Success )
          {
              return ResultErr;
          }
          Result = avcodec_send_frame( GetData().CodecContext, ID.Output-&gt;GetFrame() );
      }
  
      if( Result == 0 )
      {
          CameraStreamError ResultErr = SendAll();
          if( ResultErr != CameraStreamError::Success )
          {
              return ResultErr;
          }
      }
  
      FrameIndex++;
  
      return CameraStreamError::Success;
  }
  
  CameraStreamError OutputStream::SendAll( void )
  {
      auto&amp; ID = *m_InternalData;
  
      int Result;
      do 
      {
          AVPacket TempPacket = {};
          av_init_packet( &amp;TempPacket );
  
          Result = avcodec_receive_packet( GetData().CodecContext, &amp;TempPacket );
          if( Result == 0 )
          {
              av_packet_rescale_ts( &amp;TempPacket, ID.CodecContext-&gt;time_base, ID.FormatContext-&gt;streams[0]-&gt;time_base );
  
              TempPacket.stream_index = ID.FormatContext-&gt;streams[0]-&gt;index;
  
              //avio_write( ID.FormatContext-&gt;pb, TempPacket.data, TempPacket.size );
              Result = av_interleaved_write_frame( ID.FormatContext, &amp;TempPacket );
              if( Result &lt; 0 )
              {
                  STREAM_ERROR( WriteFailed );
              }
  
              av_packet_unref( &amp;TempPacket );
          }
          else if( Result != AVERROR(EAGAIN) )
          {
              continue;
          }
          else if( Result != AVERROR_EOF )
          {
              break;
          }
          else if( Result &lt; 0 )
          {
              STREAM_ERROR( WriteFailed );
          }
      } while ( Result == 0);
  
      return CameraStreamError::Success;
  }
  
  CameraStreamError OutputStream::CloseFile()
  {
      auto&amp; 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 &lt; 0 )
      {
          STREAM_ERROR( WriteFailed );
      }
  
      if( !(ID.FormatContext-&gt;oformat-&gt;flags&amp; AVFMT_NOFILE) )
      {
          Result = avio_close( ID.FormatContext-&gt;pb );
          if( Result &lt; 0 )
          {
              STREAM_ERROR( WriteFailed );
          }
      }
  
      return CameraStreamError::Success;
  }
  </code></pre>
  
  <p>Note I've simplified a few things and inlined a few bits that were elsewhere. I've also removed all the shutdown code as anything that happens after the file is closed is irrelevant.</p>
  
  <p>Full repo here: <a href="https://github.com/IanNorris/Witness" rel="nofollow noreferrer">https://github.com/IanNorris/Witness</a> If you clone this the issue is with the 'Diagnostics' output, the Output file is fine. There are two hardcoded paths to X:.</p>