Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 552
Febin Avatar asked Jul 11 '13 11:07

Febin


1 Answers

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);
like image 76
praks411 Avatar answered Sep 28 '22 16:09

praks411