2013-05-27 3 views
8

this 예제에서 MP4 비디오를 만드는 법을 배우고 있습니다.이 예제는 fly에서 생성 된 더미 소스 데이터의 오디오 인코딩을 보여줍니다. 파일에서 오디오를 인코딩해야합니다. . 나는 많은 예제를 확인했으며 그 중 대부분은 동일하거나 별도의 오디오 인코딩을 보여줍니다. 내 시행 착오 과정에서 오디오 및 비디오 frames.I에 대해 동일한 AVFormatContext 사용하고 있습니다. 나는 옳은 일인지, 아니면 두 별도의 컨텍스트가 있어야합니까? 지금까지 비디오 인코딩 괜찮아요 있지만 오디오 스트림 있어요 AVPacket이 올바른 오디오 스트림 인덱스를 찾을 수 없으므로 실패합니다. 여기FFmpeg로 오디오와 비디오 파일을 Muxing

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-이> 색인)이"패킷 스트림 인덱스입니다. 아무도 내가 잘못한 곳을 지적 할 수 있습니까?

업데이트 : 인코딩을위한 입력 오디오 스트림을 열 관리 않았다 그러나 나는 오디오를 인코딩 할 수 및 비디오 내가 PTS와 DTS는 아마도 문제의 원인입니다 무엇을보고 하나의 output.From에 스트림

현재 muxing.c 예제를 기반으로 pts를 계산하지만 오디오에서는 전혀 작동하지 않습니다. 여기

내가 그것을 사용하는 방법이다 : 나는 audio_pts가 video_pts에 도달 결코 오디오 인코딩 루프에서 생각하면, 어떻게 든

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

을 항상 0입니다 :

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. 

그래서 기본적으로 내가 같은 질문을 다시 한 번 묻습니다 : 외부 파일에서 오디오를 가져 오는 경우 muxing을 수행하는 방법?

Btw, 아래의 대답은 오디오 및 비디오 스트림이 동일한 파일에서 오는 것으로 가정하기 때문에 도움이되지 않지만 내 경우에는 오디오 만 외부 소스에서 가져옵니다.

답변

7

두 개의 별도 컨텍스트가 필요없는 동일한 컨텍스트를 만들 수 있습니다. 비디오와 오디오를 모두 인코딩하는 경우. 그런 다음 먼저 비디오 스트림을 만든 다음 오디오 스트림을 만들어야합니다. 그러나 오디오 만 인코딩하려는 경우 오디오 스트림 만 만들어야합니다. 트랜스 코딩 할 때 (즉, 컨테이너 형식을 변경할 때) 일반적으로 (pkt.stream_index == st-> index)가 필요합니다. 당신은 비디오 파일에서 프레임을 읽고 다른 파일에 쓸 수 있으므로 프레임이 오디오 스트림인지 비디오 스트림인지를 알아야합니다. 그러나 오디오 패킷을 디코딩하는 경우 av_interleaved_write를 수행하기 전에 오디오 패킷에 적절한 스트림 인덱스를 설정해야합니다.

코드에서 적절한 인코딩에 필요한 오디오 패킷의 pts 및 dts를 설정하지 않습니다.

언젠가 전에 비슷한 프로그램을 작성 했으므로 참조 용으로 살펴볼 수 있습니다.

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

내가 설정 점을, 그냥 넣어하지 않은 그러게, 내가 필요한 것은 추가하는 것입니다했다 오디오는 인코딩 중입니다. 오디오는 AAC 미디어 파일에서 가져옵니다.이 예제에서는 많은 감사를 표합니다. 시도해 본 모든 내용이 작동하지 않을 때까지 체크 아웃 할 것입니다. –

+0

FFMPEG 예제에서 볼 수 있듯이 인코딩 전에 avcodec_open2()를 통해 오디오 및 비디오 코덱을 열지 않아야합니까? –

+0

인코딩을 위해 예전에 avcodec_open2()를 호출해야합니다. 제 경우에는 스트림 복사본을 사용하고 있었기 때문에 사용하지 않았습니다. 그러나 당신은해야 할 것입니다. – praks411

1

AVBlocks 라이브러리 (example)를 사용할 수 있습니다. 동일한 문제를 해결하기 위해 예제 코드를 사용했습니다.올바른 일을 위해

뿐만 아니라 .aac입니다과 좀 StreamType의 변화 : * 및 StreamSubType :: *

관련 문제