FFmpeg

2013-05-27 9 views
8

के साथ ऑडियो और वीडियो फ़ाइलों से मुक्सिंग मैं सीख रहा हूं कि this उदाहरण से MP4 वीडियो कैसे बनाएं। समस्या यह है कि उदाहरण फ्लाई पर उत्पन्न कुछ डमी स्रोत डेटा से ऑडियो एन्कोडिंग प्रदर्शित करता है। मुझे फ़ाइल से ऑडियो एन्कोड करने की आवश्यकता है मैंने कई उदाहरणों की जांच की है और उनमें से अधिकतर एक ही या सिर्फ एक अलग ऑडियो एन्कोडिंग दिखाते हैं। मेरे परीक्षण और त्रुटि प्रक्रिया में मैं ऑडियो और वीडियो फ्रेम दोनों के लिए एक ही AVFormatContext का उपयोग कर रहा हूं। मुझे यकीन नहीं है कि यह सही काम है या मुझे 2 अलग-अलग संदर्भ हैं? अब तक मुझे वीडियो एन्कोडिंग ठीक है लेकिन ऑडियो स्ट्रीम विफल रहता है क्योंकि AVPacket सही ऑडियो स्ट्रीम इंडेक्स का पता नहीं लगा सकता है।FFmpeg

void open_audio(AVFormatContext *oc, AVCodec **codec, AVStream **st ,enum AVCodecID codec_id){ 

    // AVCodecContext *c; 
    int ret; 
    // c = st->codec; 

    *codec = avcodec_find_encoder(codec_id); 
    if (!(*codec)) { 
     fprintf(stderr, "Could not find encoder for '%s'\n",avcodec_get_name(codec_id)); 

    } 
    /* open it */ 



    if(avformat_open_input(&oc,_audioInName.c_str(),NULL,NULL) !=0){ 

     Msg::PrintErrorMsg("Error opening audio file"); 

    } 


    AVStream* audioStream = NULL; 

    // Find the audio stream (some container files can have multiple streams in them) 

    for (uint32_t i = 0; i < oc->nb_streams; ++i) 

    { 

     if (oc->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) 

     { 

      audioStream = oc->streams[i]; 

      break; 

     } 

    } 

    if (audioStream == NULL) 
    { 
     Msg::PrintErrorMsg("Could not find any audio stream in the file"); 

    } 
    *st =audioStream; 

    AVCodecContext *c = audioStream->codec; 
    c->codec = *codec;//avcodec_find_decoder(c->codec_id); 
    audioStream->id = 1; 
    c->sample_fmt = AV_SAMPLE_FMT_S16; 
    c->bit_rate = 64000; 
    c->sample_rate = 44100; 
    c->channels = 1; 

    if (oc->oformat->flags & AVFMT_GLOBALHEADER){ 
     c->flags |= CODEC_FLAG_GLOBAL_HEADER; 

    } 

    if (c->codec == NULL) 
    { 
     Msg::PrintErrorMsg("Couldn't find a proper decoder"); 

    } 

    ret = avcodec_open2(c, *codec, NULL); 
    if (ret < 0) { 

     Msg::PrintErrorMsg("Could not open audio codec\n"); 

    } 

} 

यहाँ "OC" एक ही वीडियो स्ट्रीम प्रारंभ करने के रूप में अच्छी तरह से इस्तेमाल संदर्भ है: यहाँ कैसे मैं सेटअप ऑडियो स्ट्रीम है।

void write_audio_frame(AVFormatContext *oc, AVStream *st){ 
    AVCodecContext *c; 
    AVPacket pkt = { 0 }; // data and size must be 0; 
    AVFrame *frame = avcodec_alloc_frame(); 
    int got_packet, ret; 
    av_init_packet(&pkt); 
    c = st->codec; 
    ///// 
    // get_audio_frame(samples, audio_input_frame_size, c->channels); 

    ////Read the packet: 
    while(av_read_frame(oc,&pkt) == 0){ 

     if(pkt.stream_index ==st->index){ 

     // Try to decode the packet into a frame 
     int frameFinished = 0; 
     avcodec_decode_audio4(c, frame, &frameFinished, &pkt); 

     // Some frames rely on multiple packets, so we have to make sure the frame is finished before 
     // we can use it 
     if (frameFinished){ 
      assert(frameFinished); 
      ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet); 
      if (ret < 0) { 
       Msg::PrintErrorMsg("Error encoding audio frame\n"); 

      } 
      if (!got_packet){ 
       printf("failed to aquire packet"); 
      } 
      pkt.stream_index = st->index; 
      /* Write the compressed frame to the media file. */ 
      ret = av_interleaved_write_frame(oc, &pkt); 
      if (ret != 0) { 

       Msg::PrintErrorMsg("Error while writing audio frame."); 
      } 

      } 
     } 

     } 
    } 
    av_free_packet(&pkt); 
    avcodec_free_frame(&frame); 
} 

बात मैं कभी नहीं इस बयान से पारित किया गया है::। "अगर (pkt.stream_index == st-> सूचकांक)" पैकेट धारा सूचकांक है

तो मैं इस तरह ऑडियो फ्रेम लिखने के लिए कोशिश कर रहा हूँ ऑडियो स्ट्रीम इंडेक्स के बराबर कभी नहीं। कोई भी बता सकता है कि मैं कहां गलत हूं?

अद्यतन:

मैं एन्कोडिंग के लिए इनपुट ऑडियो स्ट्रीम को खोलने में कामयाब था, लेकिन मैं ऑडियो सांकेतिक शब्दों में बदलना नहीं कर सकते हैं और वीडियो एकल output.From में धाराओं मैं क्या देख सार्वजनिक टेलीफोन और डीटीएस शायद समस्या के स्रोत हैं वर्तमान में मैं muxing.c उदाहरण के आधार पर pts की गणना करता हूं लेकिन यह ऑडियो के लिए बिल्कुल काम नहीं करता है।

यहाँ कैसे मैं इसका उपयोग है: तो बुनियादी तौर पर मैं कर रहा हूँ

audio_pts = (double)audio_st->pts.val * audio_st->time_base.num/audio_st->time_base.den; is always zero because (double)audio_st->pts.val returns zero. 

:

while(frame_count < _streamDurationNBFrames-1){ 

     uint8_t *frameToWrite =_frames.front(); 


     // Compute current audio and video time. /// 

     if (audio_st){ 
      audio_pts = (double)audioIn_st->pts.val * audioIn_st->time_base.num/audioIn_st->time_base.den; 
     } 
     else{ 

      audio_pts = 0.0; 
     } 
     if (video_st){ 

      video_pts = (double)video_st->pts.val * video_st->time_base.num/ video_st->time_base.den; 

     }else{ 
      video_pts = 0.0; 
     } 


     if ((!audio_st || audio_pts >= _streamDuration) && (!video_st || video_pts >= _streamDuration)){ 

      break; 

     } 


     if (audio_st && audio_pts < video_pts) { 
      av_read_frame(informat, &pkt);//read audio from input stream 
      Msg::PrintMsg("Encode audio here..."); 

      //================== AUDIO ENCODE HERE 


      outpkt.data = pkt.data; 
      outpkt.size = pkt.size; 
      outpkt.stream_index = pkt.stream_index; 
      outpkt.flags |= AV_PKT_FLAG_KEY; 
      outpkt.pts = pkt.pts; 
      outpkt.dts =pkt.dts; 
      if(av_interleaved_write_frame(oc, &outpkt) < 0) 
      { 
      Msg::PrintErrorMsg("Fail Audio Write "); 
      } 
      else 
      { 
       audio_st->codec->frame_number++; 
      } 
      av_free_packet(&outpkt); 
      av_free_packet(&pkt); 



     }else{ 
      //================== VIDEO ENCODE HERE 

      write_video_frame(oc, video_st,frameToWrite); 

      frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base); 
     } 

     ///at last delete this frame: 
     _frames.pop(); 
     delete frameToWrite; ///deallocate the written frame! 
    } 

किसी तरह, एक बार मैं ऑडियो एन्कोडिंग पाश audio_pts video_pts कभी नहीं पहुँचता है और में हूँ हमेशा शून्य है एक ही प्रश्न फिर से पूछना: जब ऑडियो बाहरी फ़ाइल से आता है तो muxing कैसे करें?

बीटीडब्ल्यू, नीचे दिया गया जवाब मदद नहीं करता है क्योंकि यह लगता है कि ऑडियो और वीडियो स्ट्रीम दोनों एक ही फाइल से आते हैं, जबकि मेरे मामले में केवल ऑडियो बाहरी स्रोत से आता है।

उत्तर

7

आप एक ही संदर्भ के लिए आपको दो अलग संदर्भ की आवश्यकता नहीं है। यदि आप वीडियो और ऑडियो दोनों एन्कोडिंग कर रहे हैं। फिर आपको पहले वीडियो स्ट्रीम और फिर ऑडियो स्ट्रीम बनाने की आवश्यकता होगी। हालांकि अगर आप केवल ऑडियो को एन्कोड करना चाहते हैं तो आपको केवल ऑडियो स्ट्रीम बनाना होगा। अगर (pkt.stream_index == st-> अनुक्रमणिका) सामान्य रूप से आवश्यक होता है जब आप ट्रांसकोडिंग करते हैं i.e जब आप कंटेनर प्रारूप बदलते हैं। जिसमें आप एक वीडियो फ़ाइल से फ्रेम पढ़ सकते हैं और दूसरी फाइल को लिख सकते हैं, इसलिए आपको यह जानने की जरूरत है कि फ्रेम ऑडियो या वीडियो स्ट्रीम से है या नहीं। हालांकि यदि आप ऑडियो पैकेट को डीकोड कर रहे हैं तो आपको av_interleaved_write करने से पहले ऑडियो पैकेट में उचित स्ट्रीम इंडेक्स सेट करना होगा।

अपने कोड में आप ऑडियो पैकेट के पीटीएस और डीटीएस सेट नहीं कर रहे हैं जो उचित एन्कोडिंग के लिए आवश्यक हैं।

कुछ समय पहले मैंने आपके जैसे एक समान कार्यक्रम को लिखा है, आप इसे अपने संदर्भ के लिए देख सकते हैं।

int VideoClipper::Init(const wxString& filename) 
{ 
    int ret = 0; 
    char errbuf[64]; 

    av_register_all(); 
    if ((ret = avformat_open_input(&m_informat, filename.mb_str(), 0, 0)) != 0) 
    { 
     av_strerror(ret,errbuf,sizeof(errbuf)); 
     PRINT_VAL("Not able to Open file;; ", errbuf) 
     ret = -1; 
     return ret; 
    } 
    else 
    { 
     PRINT_MSG("Opened File ") 
    } 

    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; 
    } 
    else 
    { 
     PRINT_MSG("Got stream Info ") 
    } 

    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) 
     { 
      PRINT_MSG("Found Audio Stream ") 
      m_in_aud_strm_idx = i; 
      m_in_aud_strm = m_informat->streams[i]; 
     } 
    } 

    if(m_in_aud_strm_idx == -1 && m_in_vid_strm_idx == -1) 
    { 
     ret = -1;  
    } 

    if(m_informat->duration == AV_NOPTS_VALUE) 
    { 
     if(m_in_vid_strm_idx != -1 && m_informat->streams[m_in_vid_strm_idx]) 
     { 
      if(m_informat->streams[m_in_vid_strm_idx]->duration != AV_NOPTS_VALUE) 
      { 
       //m_in_end_time = (m_informat->streams[m_in_vid_strm_idx]->duration)/(AV_TIME_BASE); 
       m_in_end_time = (m_informat->streams[m_in_vid_strm_idx]->duration)/(m_informat->streams[m_in_vid_strm_idx]->time_base.den/m_informat->streams[m_in_vid_strm_idx]->time_base.num); 

      } 

     } 
     else if(m_in_aud_strm_idx != -1 && m_informat->streams[m_in_aud_strm_idx]) 
     { 
      if(m_informat->streams[m_in_aud_strm_idx]->duration != AV_NOPTS_VALUE) 
      { 
       m_in_end_time = (m_informat->streams[m_in_aud_strm_idx]->duration)/(AV_TIME_BASE); 
      } 
     } 
    } 
    else 
    { 
     m_in_end_time = (m_informat->duration)/(AV_TIME_BASE); 
    } 

    if(m_in_vid_strm_idx != -1 && m_informat->streams[m_in_vid_strm_idx]) 
    { 
     if(m_informat->streams[m_in_vid_strm_idx]->r_frame_rate.num != AV_NOPTS_VALUE && m_informat->streams[m_in_vid_strm_idx]->r_frame_rate.den != 0) 
     { 
      m_fps = (m_informat->streams[m_in_vid_strm_idx]->r_frame_rate.num)/ (m_informat->streams[m_in_vid_strm_idx]->r_frame_rate.den); 
     } 
    } 
    else 
    { 
     m_fps = 25;  
    } 
    AVOutputFormat *outfmt = NULL; 
    std::string outfile = std::string(filename) + "clip_out.avi"; 
    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; 
     } 
    } 

    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; 

       } 
      } 
     } 
     } 

     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; 
     } 

    return ret; 
} 

int VideoClipper::GenerateClip(void) 
{ 
    AVPacket pkt, outpkt; 
    int aud_pts = 0, vid_pts = 0, aud_dts = 0, vid_dts = 0; 
    int last_vid_pts = 0; 
    if(m_good_clip) 
    { 
     SeekFrame(); 
     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++; 
    } 

    av_write_trailer(m_outformat); 
    av_free_packet(&outpkt); 
    av_free_packet(&pkt); 
    return 0;  
} 
    return -1; 
} 
+0

मैं सेट अंक करते हैं, बस इसे नहीं डाल दिया है here.Yeah, मैं क्या जरूरत है जोड़ने के लिए है बनाया वीडियो के लिए ऑडियो मैं एन्कोडिंग कर रहा हूं। ऑडियो एएसी मीडिया फाइल से आता है। इस उदाहरण के लिए बहुत कुछ धन्यवाद, मैं इसे तब तक देखूंगा जब तक मैंने कोशिश की कुछ भी काम नहीं किया। –

+0

क्या मुझे एन्कोडिंग से पहले avcodec_open2() के माध्यम से ऑडियो और वीडियो कोडेक्स नहीं खोलना चाहिए क्योंकि यह एफएफएमपीईजी उदाहरणों में दिखाया गया है? –

+0

हाँ एन्कोडिंग के लिए आपको पहले avcodec_open2() को कॉल करने की आवश्यकता होगी। मेरे मामले में मैं सिर्फ स्ट्रीम कॉपी कर रहा था इसलिए मैंने इसका उपयोग नहीं किया। लेकिन आपको करने की ज़रूरत होगी। – praks411

1

आप AVBlocks लाइब्रेरी (example) का उपयोग कर सकते हैं। मैंने एक ही समस्या को हल करने के लिए उदाहरण कोड का उपयोग किया।

सही काम के लिए न केवल .aac साथ मैं StreamType में कुछ बदलाव :: * और StreamSubType :: *

 संबंधित मुद्दे