2015-11-29 75 views
3

我试图从几个文件复制到一个文件没有转码流的所有流。有些事情,你通常ffmpeg -i “file_with_audio.mp4” -i “file_with_video.mp4” -c copy -shortest file_with_audio_and_video.mp4FFMpeg复制流没有转码

这与ffmpeg工具做的是代码:

int ffmpegOpenInputFile(const char* filename, AVFormatContext **ic) { 

    int ret; 
    unsigned int i; 

    *ic = avformat_alloc_context(); 
    if (!(*ic)) 
     return -1; // Couldn't allocate input context 

    if((ret = avformat_open_input(ic, filename, NULL, NULL)) < 0) 
     return ret; // Couldn't open file 

    // Get format info (retrieve stream information) 
    if ((ret = avformat_find_stream_info(*ic, NULL)) < 0) 
     return ret; // Couldn't find stream information 

    for (int i = 0; i < (*ic)->nb_streams; i++) { 
     AVStream *stream; 
     AVCodecContext *codec_ctx; 
     stream = (*ic)->streams[i]; 
     codec_ctx = stream->codec; 
     /* Reencode video & audio and remux subtitles etc. */ 
     if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO 
      || codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { 
      /* Open decoder */ 
      ret = avcodec_open2(codec_ctx, 
           avcodec_find_decoder(codec_ctx->codec_id), NULL); 
      if (ret < 0) { 
       av_log(NULL, AV_LOG_ERROR, "Failed to open decoder for stream #%u\n", i); 
       return ret; 
      } 
     } 
    } 

    // Dump information about file onto standard error 
    av_dump_format(*ic, 0, filename, 0); 

    return 0; 
} 



int main(int argc, char *argv[]) { 

    const char *inputFilename1 = "/avfiles/video_input.mp4"; 
    const char *inputFilename2 = "/avfiles/audio_input.mp4"; 
    const char *filename = "/avfiles/out.mp4"; 

    int ret; 

    av_register_all(); 

    AVFormatContext *ic1 = nullptr; 
    AVFormatContext *ic2 = nullptr; 
    AVFormatContext *oc = nullptr; 

    if ((ret = ffmpegOpenInputFile(inputFilename1, &ic1)) < 0) 
     return ret; // and free resources and 

    if ((ret = ffmpegOpenInputFile(inputFilename2, &ic2)) < 0) 
     return ret; // and free resources and 

    AVOutputFormat *outfmt = av_guess_format(NULL, filename, NULL); 
    if (outfmt == NULL) 
     return -1; // Could not guess output format 

    avformat_alloc_output_context2(&oc, outfmt, NULL, filename); 
    if (!oc) 
     return AVERROR_UNKNOWN; // Could not create output context 

    // populate input streams from all input files 
    AVStream **input_streams = NULL; 
    int nb_input_streams = 0; 
    for (int i = 0; i < ic1->nb_streams; i++) { 
     input_streams = (AVStream **) grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, 
               nb_input_streams + 1); 
     input_streams[nb_input_streams - 1] = ic1->streams[i]; 
    } 
    for (int i = 0; i < ic2->nb_streams; i++) { 
     input_streams = (AVStream **) grow_array(input_streams, sizeof(*input_streams), &nb_input_streams, 
               nb_input_streams + 1); 
     input_streams[nb_input_streams - 1] = ic2->streams[i]; 
    } 

    for (int i = 0; i < nb_input_streams; i++) { 
     AVStream *ist = input_streams[i]; // could be named 'm_in_vid_strm' 

     // if output context has video codec support and current input stream is video 
     if (/*oc->video_codec_id*/ oc->oformat->video_codec != AV_CODEC_ID_NONE && ist != NULL 
            && ist->codec->codec_type == AVMEDIA_TYPE_VIDEO) { 

      AVCodec *out_vid_codec = avcodec_find_encoder(oc->oformat->video_codec); 
      if (NULL == out_vid_codec) 
       return -1; // Couldn't find video encoder 

      AVStream *m_out_vid_strm = avformat_new_stream(oc, out_vid_codec); 
      if (NULL == m_out_vid_strm) 
       return -1; // Couldn't output video stream 

      m_out_vid_strm->id = 0; // XXX: 

      ret = avcodec_copy_context(m_out_vid_strm->codec, ist->codec); 
      if (ret < 0) 
       return ret; // Failed to copy context 

     } 

     // if output context has audio codec support and current input stream is audio 
     if (/*oc->audio_codec_id*/ oc->oformat->audio_codec != AV_CODEC_ID_NONE && ist != NULL 
            && ist->codec->codec_type == AVMEDIA_TYPE_AUDIO) { 

      AVCodec *out_aud_codec = avcodec_find_encoder(oc->oformat->audio_codec); 
      if (nullptr == out_aud_codec) 
       return -1; // couldn't find audio codec 

      AVStream *m_out_aud_strm = avformat_new_stream(oc, out_aud_codec); 
      if (nullptr == m_out_aud_strm) 
       return -1; // couldn't allocate audio out stream 

      ret = avcodec_copy_context(m_out_aud_strm->codec, ist->codec); 
      if (ret < 0) 
       return ret; // couldn't copy context 

     } 
    } 

    // finally output header 
    if (!(oc->flags & AVFMT_NOFILE)) { 

     ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE); 
     if (ret < 0) 
      return ret; // Could not open output file 

     av_dump_format(oc, 0, filename, 1); 

     ret = avformat_write_header(oc, NULL); 
     if (ret < 0) 
      return ret; // Error occurred when opening output file 

    } 

    return 0; 

} 

avformat_write_header(oc, NULL);总是返回错误,我看到这个消息:

[mp4 @ 0x7f84ec900a00] Using AVStream.codec.time_base as a timebase hint to the muxer is deprecated. Set AVStream.time_base instead. 
[mp4 @ 0x7f84ec900a00] Tag avc1/0x31637661 incompatible with output codec id '28' ([33][0][0][0]) 

但输入和输出流匹配:

Input streams from 2 files: 
Stream #0:0(und): Video: h264 (High) (avc1/0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 2834 kb/s, 23.98 fps, 23.98 tbr, 90k tbn, 47.95 tbc (default) 
Stream #0:0(und): Audio: aac (LC) (mp4a/0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default) 

Output #0, mp4, to '/Users/alex/Workspace/_qt/tubisto/avfiles/out.mp4': 
    Stream #0:0: Video: h264 (libx264) (avc1/0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 2834 kb/s, 47.95 tbc 
    Stream #0:1: Audio: aac (libvo_aacenc) (mp4a/0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s 

为什么发生不兼容的输出编解码器错误? 我的代码有什么问题,以及如何使其将所有输入文件中的所有流复制到输出文件?

回答

2

原因是因为您没有正确设置编码器的codec_tag

您应该设置正确的codec_tag,或将codec_tag设置为0,并让混合器为您处理。

以下是一个示例代码如何操作。

AVFormatContext *ofmt_ctx; // todo 
AVCodec *oc; // todo 

AVStream *stream = avformat_new_stream(ofmt_ctx, oc); 

if (stream != NULL) { 
    // ... 
    unsigned int tag = 0; 
    // for ffmpeg new api 3.x 
    AVCodecParameters *parameters = stream->codecpar; 
    if (av_codec_get_tag2(ofmt_ctx->oformat->codec_tag, oc->id, &tag) == 0) { 
     av_log(NULL, AV_LOG_ERROR, "could not find codec tag for codec id %d, default to 0.\n", oc->id); 
    } 
    parameters->codec_tag = tag; 
    stream->codec = avcodec_alloc_context3(oc); 
    // more setting for stream->codec 
    avcodec_parameters_to_context(stream->codec, parameters); 

    // for old ffmpeg version 
    stream->codec->codec_tag = tag; 
    // ... 
} 
+0

你救了我......这是两天,我试图理解为什么我的“合并”的代码没有对MP4工作,设置标签上的目标参数做到了! – gabry