title: FFmpeg C API - syncing video and audio
body: <p>I am trimming video and having a hard getting the audio to sync correctly. The code below is as close as I've gotten it work. I've tried both re-encoding and not re-encoding the output streams.</p>
  
  <p>The video trims correctly and is written to the output container. The audio stream also trims correctly, but is written to the front of the output container. For example if the trim length is 10s - the correct portion of audio plays for 10s and then the correct portion of video plays.</p>
  
  <pre><code>//////// audio stream ////////
  const AVStream *input_stream_audio = input_container-&gt;streams[audio_stream_index];
  const AVCodec *decoder_audio = avcodec_find_decoder(input_stream_audio-&gt;codec-&gt;codec_id);
  if(!decoder_audio) {
      cleanup(decoded_packet, output_container, decoded_frame);
      avformat_close_input(&amp;input_container);
      LOGE("=&gt; Audio decoder not found");
      return -1;
  }
  if(avcodec_open2(input_stream_audio-&gt;codec, decoder_audio, NULL) &lt; 0) {
      cleanup(decoded_packet, output_container, decoded_frame);
      avformat_close_input(&amp;input_container);
      LOGE("=&gt; Error opening audio decoder");
      return -1;
  }
  
  AVStream *output_stream_audio = avformat_new_stream(output_container, NULL);
  if(avcodec_copy_context(output_stream_audio-&gt;codec, input_stream_audio-&gt;codec) != 0){
      LOGE("=&gt; Failed to Copy audio Context ");
      return -1;
  }
  else {
      LOGI("=&gt; Copied audio context ");
      output_stream_audio-&gt;codec-&gt;codec_id = input_stream_audio-&gt;codec-&gt;codec_id;
      output_stream_audio-&gt;codec-&gt;codec_tag = 0;
      output_stream_audio-&gt;pts = input_stream_audio-&gt;pts;
      output_stream_audio-&gt;time_base.num = input_stream_audio-&gt;time_base.num;
      output_stream_audio-&gt;time_base.den = input_stream_audio-&gt;time_base.den;
  
  }
  
  if(avio_open(&amp;output_container-&gt;pb, output_file, AVIO_FLAG_WRITE) &lt; 0) {
      cleanup(decoded_packet, output_container, decoded_frame);
      avformat_close_input(&amp;input_container);
      LOGE("=&gt; Error opening output file");
      return -1;
  }
  
  // allocate frame for conversion
  decoded_frame = avcodec_alloc_frame();
  if(!decoded_frame) {
      cleanup(decoded_packet, output_container, decoded_frame);
      avformat_close_input(&amp;input_container);
      LOGE("=&gt; Error allocating frame");
      return -1;
  }
  
  av_dump_format(input_container, 0, input_file, 0);
  avformat_write_header(output_container, NULL);
  av_init_packet(&amp;decoded_packet);
  
  decoded_packet.data = NULL;
  decoded_packet.size = 0;
  int current_frame_num = 1;
  int current_frame_num_audio = 1;
  int got_frame, len;
  
  AVRational default_timebase;
  default_timebase.num = 1;
  default_timebase.den = AV_TIME_BASE;
  
  int64_t starttime_int64 = av_rescale_q((int64_t)( 12.0 * AV_TIME_BASE ), AV_TIME_BASE_Q, input_stream-&gt;time_base);
  int64_t endtime_int64 = av_rescale_q((int64_t)( 18.0 * AV_TIME_BASE ), AV_TIME_BASE_Q, input_stream-&gt;time_base);
  LOGI("=&gt; starttime_int64:     %" PRId64, starttime_int64);
  LOGI("=&gt; endtime_int64:       %" PRId64, endtime_int64);
  
  int64_t starttime_int64_audio = av_rescale_q((int64_t)( 12.0 * AV_TIME_BASE ), AV_TIME_BASE_Q, input_stream_audio-&gt;time_base);
  int64_t endtime_int64_audio = av_rescale_q((int64_t)( 18.0 * AV_TIME_BASE ), AV_TIME_BASE_Q, input_stream_audio-&gt;time_base);
  LOGI("=&gt; starttime_int64_audio:     %" PRId64, starttime_int64_audio);
  LOGI("=&gt; endtime_int64_audio:       %" PRId64, endtime_int64_audio);
  
  // loop input container and decode frames
  while(av_read_frame(input_container, &amp;decoded_packet)&gt;=0) {
      // video packets
      if (decoded_packet.stream_index == video_stream_index) {
          len = avcodec_decode_video2(input_stream-&gt;codec, decoded_frame, &amp;got_frame, &amp;decoded_packet);
          if(len &lt; 0) {
              cleanup(decoded_packet, output_container, decoded_frame);
              avformat_close_input(&amp;input_container);
              LOGE("=&gt; No frames to decode");
              return -1;
          }
          // this is the trim range we're looking for
          if(got_frame &amp;&amp; decoded_frame-&gt;pkt_pts &gt;= starttime_int64 &amp;&amp; decoded_frame-&gt;pkt_pts &lt;= endtime_int64) {
                  av_init_packet(&amp;encoded_packet);
                  encoded_packet.data =  NULL;
                  encoded_packet.size =  0;
  
                  ret = avcodec_encode_video2(output_stream-&gt;codec, &amp;encoded_packet, decoded_frame, &amp;got_frame);
                  if (ret &lt; 0) {
                      cleanup(decoded_packet, output_container, decoded_frame);
                      avformat_close_input(&amp;input_container);
                      LOGE("=&gt; Error encoding frames");
                      return ret;
                  }
                  if(got_frame) {
                      if (output_stream-&gt;codec-&gt;coded_frame-&gt;key_frame) {
                          encoded_packet.flags |= AV_PKT_FLAG_KEY;
                      }
  
                      encoded_packet.stream_index = output_stream-&gt;index;
                      encoded_packet.pts = av_rescale_q(current_frame_num, output_stream-&gt;codec-&gt;time_base, output_stream-&gt;time_base);
                      encoded_packet.dts = av_rescale_q(current_frame_num, output_stream-&gt;codec-&gt;time_base, output_stream-&gt;time_base);
  
                      ret = av_interleaved_write_frame(output_container, &amp;encoded_packet);
                      if (ret &lt; 0) {
                          cleanup(decoded_packet, output_container, decoded_frame);
                          avformat_close_input(&amp;input_container);
                          LOGE("=&gt; Error encoding frames");
                          return ret;
                      }
                      else {
                          current_frame_num +=1;
                      }
                  }
              av_free_packet(&amp;encoded_packet);
          }
      }
      // audio packets
      else if(decoded_packet.stream_index == audio_stream_index) {
          // this is the trim range we're looking for
          if(decoded_packet.pts &gt;= starttime_int64_audio &amp;&amp; decoded_packet.pts &lt;= endtime_int64_audio) {
              av_init_packet(&amp;encoded_packet);
  
              encoded_packet.data =  decoded_packet.data;
              encoded_packet.size =  decoded_packet.size;
              encoded_packet.stream_index = audio_stream_index;
              encoded_packet.pts = av_rescale_q(current_frame_num_audio, output_stream_audio-&gt;codec-&gt;time_base, output_stream_audio-&gt;time_base);
              encoded_packet.dts = av_rescale_q(current_frame_num_audio, output_stream_audio-&gt;codec-&gt;time_base, output_stream_audio-&gt;time_base);
  
              ret = av_interleaved_write_frame(output_container, &amp;encoded_packet);
              if (ret &lt; 0) {
                  cleanup(decoded_packet, output_container, decoded_frame);
                  avformat_close_input(&amp;input_container);
                  LOGE("=&gt; Error encoding frames");
                  return ret;
              }
              else {
                  current_frame_num_audio +=1;
              }
             av_free_packet(&amp;encoded_packet);
          }
      }
  }
  </code></pre>
  
  <p><strong>Edit</strong></p>
  
  <p>I have slight improvement on the initial code. The audio and video are still not perfectly synced, but the original problem of the audio playing first followed by the video is resolved. </p>
  
  <p>I'm now writing the decoded packet to the output container rather than re-encoding it. </p>
  
  <p>In the end though I have the same problem - the trimmed video's audio and video streams are not perfectly synced.</p>
  
  <pre><code>// audio packets
      else if(decoded_packet.stream_index == audio_stream_index) {
          // this is the trim range we're looking for
          if(decoded_packet.pts &gt;= starttime_int64_audio &amp;&amp; decoded_packet.pts &lt;= endtime_int64_audio) {
              ret = av_interleaved_write_frame(output_container, &amp;decoded_packet);
              if (ret &lt; 0) {
                  cleanup(decoded_packet, output_container, decoded_frame);
                  avformat_close_input(&amp;input_container);
                  LOGE("=&gt; Error writing audio frame (%s)", av_err2str(ret));
                  return ret;
              }
              else {
                  current_frame_num_audio +=1;
              }
          }
          else if(decoded_frame-&gt;pkt_pts &gt; endtime_int64_audio) {
              audio_copy_complete = true;
          }
      }
  </code></pre>