Search code examples
ffmpegcopycodeclibav

FFMpeg - How to copy codec ( video and audio ) from 'mp4' container to 'ts' container


i have this ffmpeg command

ffmpeg -i c:\input.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb c:\output.ts.

The above command successfully converts input.mp4 to output.ts.

I need to implement the same functionality via code (using the ffmpeg library).

Does anybody know how to copy from one container to another without decoding and encoding?


Solution

  • If you are looking just for stream copy you can do this quite easily. You can refer following steps.

    //1. Do initialization using 
    
        av_register_all();
    
    // 2. Open input file using  
    
        avformat_open_input( &m_informat, filename.c_str(), 0, 0));
    
    //3. Find input stream info.
    
         if ((ret = avformat_find_stream_info(m_informat, 0))< 0)
            {
               av_strerror(ret,errbuf,sizeof(errbuf));
               PRINT_VAL("Not Able to find stream info:: ", errbuf)
               ret = -1;
               return ret;
            }
    
            for (unsigned int i = 0; i<m_informat->nb_streams; i++)
            {
               if(m_informat->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
               {
                  PRINT_MSG("Found Video Stream ")
                  m_in_vid_strm_idx = i;
                  m_in_vid_strm = m_informat->streams[i];
               }
    
            if(m_informat->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
            {
                m_in_aud_strm_idx = i;
                m_in_aud_strm = m_informat->streams[i];
             }
    
    
    // 4. Create ouputfile  and allocate output format.
    
       AVOutputFormat *outfmt = NULL;
       std::string outfile = std::string(filename) + "clip_out.ts";
            outfmt = av_guess_format(NULL,outfile.c_str(),NULL);
         if(outfmt == NULL)
            {
                ret = -1;
                return ret;
            }
            else
            {
                m_outformat = avformat_alloc_context();
                if(m_outformat)
                {
                    m_outformat->oformat = outfmt;
                    _snprintf(m_outformat->filename, 
                     sizeof(m_outformat->filename), "%s", outfile.c_str());    
                }
                else
                {
                    ret = -1;
                    return ret;
                }
            }
    
    //5. Add audio and video stream to output format.
    
            AVCodec *out_vid_codec,*out_aud_codec;
            out_vid_codec = out_aud_codec = NULL;
    
            if(outfmt->video_codec != AV_CODEC_ID_NONE && m_in_vid_strm != NULL)
            {
                out_vid_codec = avcodec_find_encoder(outfmt->video_codec);
                if(NULL == out_vid_codec)
                {
                    PRINT_MSG("Could Not Find Vid Encoder")
                    ret = -1;
                    return ret;
                }
                else
                {
                    PRINT_MSG("Found Out Vid Encoder ")
                    m_out_vid_strm = avformat_new_stream(m_outformat, out_vid_codec);
                    if(NULL == m_out_vid_strm)
                    {
                         PRINT_MSG("Failed to Allocate Output Vid Strm ")
                         ret = -1;
                         return ret;
                    }
                    else
                    {
                         PRINT_MSG("Allocated Video Stream ")
                         if(avcodec_copy_context(m_out_vid_strm->codec, 
                            m_informat->streams[m_in_vid_strm_idx]->codec) != 0)
                         {
                            PRINT_MSG("Failed to Copy Context ")
                            ret = -1;
                            return ret;
                         }
                         else
                         {
                            m_out_vid_strm->sample_aspect_ratio.den = 
                            m_out_vid_strm->codec->sample_aspect_ratio.den;
    
                            m_out_vid_strm->sample_aspect_ratio.num = 
                            m_in_vid_strm->codec->sample_aspect_ratio.num;
                            PRINT_MSG("Copied Context ")
                            m_out_vid_strm->codec->codec_id = m_in_vid_strm->codec->codec_id;
                            m_out_vid_strm->codec->time_base.num = 1;
                            m_out_vid_strm->codec->time_base.den = 
                            m_fps*(m_in_vid_strm->codec->ticks_per_frame);         
                            m_out_vid_strm->time_base.num = 1;
                            m_out_vid_strm->time_base.den = 1000;
                            m_out_vid_strm->r_frame_rate.num = m_fps;
                            m_out_vid_strm->r_frame_rate.den = 1;
                            m_out_vid_strm->avg_frame_rate.den = 1;
                            m_out_vid_strm->avg_frame_rate.num = m_fps;
                            m_out_vid_strm->duration = (m_out_end_time - m_out_start_time)*1000;
                         }
                       }
                    }
              }
    
            if(outfmt->audio_codec != AV_CODEC_ID_NONE && m_in_aud_strm != NULL)
            {
                out_aud_codec = avcodec_find_encoder(outfmt->audio_codec);
                if(NULL == out_aud_codec)
                {
                    PRINT_MSG("Could Not Find Out Aud Encoder ")
                    ret = -1;
                    return ret;
                }
                else
                {
                    PRINT_MSG("Found Out Aud Encoder ")
                    m_out_aud_strm = avformat_new_stream(m_outformat, out_aud_codec);
                    if(NULL == m_out_aud_strm)
                    {
                        PRINT_MSG("Failed to Allocate Out Vid Strm ")
                        ret = -1;
                        return ret;
                    }
                    else
                    {
                        if(avcodec_copy_context(m_out_aud_strm->codec, 
                           m_informat->streams[m_in_aud_strm_idx]->codec) != 0)
                        {
                            PRINT_MSG("Failed to Copy Context ")
                            ret = -1;
                            return ret;
                        }
                        else
                         {
                            PRINT_MSG("Copied Context ")
                            m_out_aud_strm->codec->codec_id = m_in_aud_strm->codec->codec_id;
                            m_out_aud_strm->codec->codec_tag = 0;
                            m_out_aud_strm->pts = m_in_aud_strm->pts;
                            m_out_aud_strm->duration = m_in_aud_strm->duration;
                            m_out_aud_strm->time_base.num = m_in_aud_strm->time_base.num;
                            m_out_aud_strm->time_base.den = m_in_aud_strm->time_base.den;
    
                        }
                    }
                 }
              }
     // 6. Finally output header.
          if (!(outfmt->flags & AVFMT_NOFILE)) 
              {
                if (avio_open2(&m_outformat->pb, outfile.c_str(), AVIO_FLAG_WRITE,NULL, NULL) < 0) 
                {
                        PRINT_VAL("Could Not Open File ", outfile)
                        ret = -1;
                        return ret;
                }
              }
                /* Write the stream header, if any. */
              if (avformat_write_header(m_outformat, NULL) < 0) 
              {
                    PRINT_VAL("Error Occurred While Writing Header ", outfile)
                    ret = -1;
                    return ret;
              }
              else
              {
                    PRINT_MSG("Written Output header ")
                    m_init_done = true;
              }
    
    // 7. Now in while loop read frame using av_read_frame and write to output format using 
    //  av_interleaved_write_frame(). You can use following loop
    
          while(av_read_frame(m_informat, &pkt) >= 0 && (m_num_frames-- > 0))
                {
                    if(pkt.stream_index == m_in_vid_strm_idx)
                    {
                        PRINT_VAL("ACTUAL VID Pkt PTS ",av_rescale_q(pkt.pts,m_in_vid_strm->time_base, m_in_vid_strm->codec->time_base))
                        PRINT_VAL("ACTUAL VID Pkt DTS ", av_rescale_q(pkt.dts, m_in_vid_strm->time_base, m_in_vid_strm->codec->time_base ))
                        av_init_packet(&outpkt);
                        if(pkt.pts != AV_NOPTS_VALUE)
                        {
                            if(last_vid_pts == vid_pts)
                            {
                                vid_pts++;
                                last_vid_pts = vid_pts;
                            }
                            outpkt.pts = vid_pts;   
                            PRINT_VAL("ReScaled VID Pts ", outpkt.pts)
                        }
                        else
                        {
                            outpkt.pts = AV_NOPTS_VALUE;
                        }
    
                        if(pkt.dts == AV_NOPTS_VALUE)
                        {
                            outpkt.dts = AV_NOPTS_VALUE;
                        }
                        else
                        {
                            outpkt.dts = vid_pts;
                            PRINT_VAL("ReScaled VID Dts ", outpkt.dts)
                            PRINT_MSG("=======================================")
                        }
    
                        outpkt.data = pkt.data;
                        outpkt.size = pkt.size;
                        outpkt.stream_index = pkt.stream_index;
                        outpkt.flags |= AV_PKT_FLAG_KEY;
                        last_vid_pts = vid_pts;
                        if(av_interleaved_write_frame(m_outformat, &outpkt) < 0)
                        {
                            PRINT_MSG("Failed Video Write ")
                        }
                        else
                        {
                            m_out_vid_strm->codec->frame_number++;
                        }
                        av_free_packet(&outpkt);
                        av_free_packet(&pkt);
                    }
                    else if(pkt.stream_index == m_in_aud_strm_idx)
                    {
                        PRINT_VAL("ACTUAL AUD Pkt PTS ", av_rescale_q(pkt.pts, m_in_aud_strm->time_base, m_in_aud_strm->codec->time_base))
                        PRINT_VAL("ACTUAL AUD Pkt DTS ", av_rescale_q(pkt.dts, m_in_aud_strm->time_base, m_in_aud_strm->codec->time_base))
                        //num_aud_pkt++;
                        av_init_packet(&outpkt);
                        if(pkt.pts != AV_NOPTS_VALUE)
                        {
                            outpkt.pts = aud_pts;
                            PRINT_VAL("ReScaled AUD PTS ", outpkt.pts)
                        }
                        else
                        {
                            outpkt.pts = AV_NOPTS_VALUE;
                        }
    
                        if(pkt.dts == AV_NOPTS_VALUE)
                        {
                            outpkt.dts = AV_NOPTS_VALUE;
                        }
                        else
                        {
                            outpkt.dts = aud_pts;
                            PRINT_VAL("ReScaled AUD DTS ", outpkt.dts)
                            PRINT_MSG("====================================")
                            if( outpkt.pts >= outpkt.dts)
                            {
                                outpkt.dts = outpkt.pts;
                            }
                            if(outpkt.dts == aud_dts)
                            {
                                outpkt.dts++;
                            }
                            if(outpkt.pts < outpkt.dts)
                            {
                                outpkt.pts = outpkt.dts;
                                aud_pts = outpkt.pts;
                            }
                        }
    
                        outpkt.data = pkt.data;
                        outpkt.size = pkt.size;
                        outpkt.stream_index = pkt.stream_index;
                        outpkt.flags |= AV_PKT_FLAG_KEY;
                        vid_pts = aud_pts;
                        aud_pts++;
                        if(av_interleaved_write_frame(m_outformat, &outpkt) < 0)
                        {
                            PRINT_MSG("Faile Audio Write ")
                        }
                        else
                        {
                            m_out_aud_strm->codec->frame_number++;
                        }
                        av_free_packet(&outpkt);
                        av_free_packet(&pkt);
                }
                else
                {
                    PRINT_MSG("Got Unknown Pkt ")
                    //num_unkwn_pkt++;
                }
                //num_total_pkt++;
            }
    
    //8. Finally write trailer and clean up everything
    
         av_write_trailer(m_outformat);
            av_free_packet(&outpkt);
            av_free_packet(&pkt);