FFMpeg没有转码复制流 [英] FFMpeg copy streams without transcode

查看:378
本文介绍了FFMpeg没有转码复制流的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将所有流从多个文件复制到一个文件中,而无需转码流。你通常使用 ffmpeg 实用程序通过 ffmpeg -ifile_with_audio.mp4-ifile_with_video.mp4-c copy -shortest file_with_audio_and_video.mp4

I'm trying to copy all streams from several files into one file without transcoding streams. Something you usually do with ffmpeg utility by ffmpeg -i "file_with_audio.mp4" -i "file_with_video.mp4" -c copy -shortest file_with_audio_and_video.mp4

这是代码:

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) ; 总是返回错误,我看到这个消息:

avformat_write_header(oc, NULL); always return error and I see this messages:

[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

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

Why the error with incompatible output codec happens? What is wrong in my code and how to make it work to copy all streams from all input files to output file?

推荐答案

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

The reason is because you didn't set the encoder's codec_tag correctly.

您应该设置正确的 codec_tag ,或将 codec_tag 设置为0,并离开muxer为您处理。

You should set the correct codec_tag, or set the codec_tag to 0 and leave the muxer to handle for you.

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

Following is a sample code how to do.

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

这篇关于FFMpeg没有转码复制流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆