title: FFMEG libavcodec decoder then re-encode video issue
body: <p>I'm trying to use libavcodec library in FFMpeg to decode then re-encode a h264 video.</p>
  
  <p>I have the decoding part working (rendes to an SDL window fine) but when I try to re-encode the frames I get bad data in the re-encoded videos samples.</p>
  
  <p>Here is a cut down code snippet of my encode logic.</p>
  
  <pre><code>EncodeResponse H264Codec::EncodeFrame(AVFrame* pFrame, StreamCodecContainer* pStreamCodecContainer, AVPacket* pPacket)
  {
      int result = 0;
  
      result = avcodec_send_frame(pStreamCodecContainer-&gt;pEncodingCodecContext, pFrame);
  
      if(result &lt; 0)
      {
          return EncodeResponse::Fail;
      }
  
      while (result &gt;= 0)
      {
          result = avcodec_receive_packet(pStreamCodecContainer-&gt;pEncodingCodecContext, pPacket);
  
          // If the encoder needs more frames to create a packed then return and wait for
          // method to be called again upon a new frame been present.
          // Else check if we have failed to encode for some reason.
          // Else a packet has successfully been returned, then write it to the file.
          if (result == AVERROR(EAGAIN) || result == AVERROR_EOF)
          {
              // Higher level logic, dedcodes next frame from source
              // video then calls this method again.
              return EncodeResponse::SendNextFrame;
          }
          else if (result &lt; 0)
          {
              return EncodeResponse::Fail;
          }
          else
          {
              // Prepare packet for muxing.
              if (pStreamCodecContainer-&gt;codecType == AVMEDIA_TYPE_VIDEO)
              {
                  av_packet_rescale_ts(m_pPacket, pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;time_base, 
                                       m_pDecodingFormatContext-&gt;streams[pStreamCodecContainer-&gt;streamIndex]-&gt;time_base);
              }
  
              m_pPacket-&gt;stream_index = pStreamCodecContainer-&gt;streamIndex;
  
              int result = av_interleaved_write_frame(m_pEncodingFormatContext, m_pPacket);
  
              av_packet_unref(m_pPacket);
          }
      }
  
      return EncodeResponse::EncoderEndOfFile;
  }
  </code></pre>
  
  <p>Strange behaviour I notice is that before I get the first packet from avcodec_receive_packet I have to send 50+ frames to avcodec_send_frame.</p>
  
  <p>I built a debug build of FFMpeg and stepping into the code I notice that AVERROR(EAGAIN) is returned by avcodec_receive_packet because of the following in x264encoder::encode in  encoder.c</p>
  
  <pre><code>    if( h-&gt;frames.i_input &lt;= h-&gt;frames.i_delay + 1 - h-&gt;i_thread_frames )
      {
          /* Nothing yet to encode, waiting for filling of buffers */
          pic_out-&gt;i_type = X264_TYPE_AUTO;
          return 0;
      }
  </code></pre>
  
  <p>For some reason my code-context (h) never has any frames. I have spent a long time trying to debug ffmpeg and to determine what I'm doing wrong. But have reached the limit of my video codec knowledge (which is little).</p>
  
  <p>I'm testing this with a video that has no audio to reduce complication.</p>
  
  <p>I have created a cut down version of my application and provided a self contained (with ffmpeg and SDL built dependencies) project. Hopefully this can help anyone-one willing to help me :).</p>
  
  <p>Project Link
  <a href="https://github.com/maxhap/video-codec" rel="nofollow noreferrer">https://github.com/maxhap/video-codec</a></p>
  
  <hr>
  
  <p>After looking into encoder initialisation I found that I have to set the codec AV_CODEC_FLAG_GLOBAL_HEADER before calling avcodec_open2</p>
  
  <p><code>pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  </code></p>
  
  <p>This change led to the re-encoded moov box looking much heathier (used MP4Box.js to parse it). However, the video still does not play correctly, the output video has grey frames at the start when played in VLC and won't play in other players.</p>
  
  <p>I have since tried creating an encoding context via the sample code, rather than using my decoding codec parameters. This led to fixing the bad/data or encoding issue. However, my DTS times are scaling to huge numbers</p>
  
  <p>Here is my new codec init</p>
  
  <pre><code>if (pStreamCodecContainer-&gt;codecType == AVMEDIA_TYPE_VIDEO) 
  {
      pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;height = pStreamCodecContainer-&gt;pDecodingCodecContext-&gt;height;
      pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;width = pStreamCodecContainer-&gt;pDecodingCodecContext-&gt;width;
      pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;sample_aspect_ratio = pStreamCodecContainer-&gt;pDecodingCodecContext-&gt;sample_aspect_ratio;
  
      /* take first format from list of supported formats */
      if (pStreamCodecContainer-&gt;pEncodingCodec-&gt;pix_fmts)
      {
          pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;pix_fmt = pStreamCodecContainer-&gt;pEncodingCodec-&gt;pix_fmts[0];
      }
      else
      {
          pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;pix_fmt = pStreamCodecContainer-&gt;pDecodingCodecContext-&gt;pix_fmt;
      }
  
      /* video time_base can be set to whatever is handy and supported by encoder */      
      pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;time_base = av_inv_q(pStreamCodecContainer-&gt;pDecodingCodecContext-&gt;framerate);
      pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;sample_aspect_ratio = pStreamCodecContainer-&gt;pDecodingCodecContext-&gt;sample_aspect_ratio;
  }
  else 
  {
      pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;channel_layout = pStreamCodecContainer-&gt;pDecodingCodecContext-&gt;channel_layout;
      pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;channels = 
          av_get_channel_layout_nb_channels(pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;channel_layout);
  
      /* take first format from list of supported formats */
      pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;sample_fmt = pStreamCodecContainer-&gt;pEncodingCodec-&gt;sample_fmts[0];
      pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;time_base = AVRational{ 1, pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;sample_rate };
  }
  </code></pre>
  
  <p>Any ideas why my DTS time is re-scaling incorrectly?</p>
  
  <hr>
  
  <p>I managed to fix the DTS scalling by using the time_base value directly from the decoding streams.</p>
  
  <p>So</p>
  
  <pre><code>pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;time_base = m_pDecodingFormatContext-&gt;streams[pStreamCodecContainer-&gt;streamIndex]-&gt;time_base
  </code></pre>
  
  <p>Instead of</p>
  
  <pre><code>pStreamCodecContainer-&gt;pEncodingCodecContext-&gt;time_base = av_inv_q(pStreamCodecContainer-&gt;pDecodingCodecContext-&gt;framerate);
  </code></pre>
  
  <p>I will create an answer based on all my finding.</p>