Объединение файлов с помощью ffmpeg C API

Я пытаюсь объединить два видеофайла вместе с ffmpeg, используя C. Я знаю, что для этого нужно:

<сильный>1. Откройте выходной контекст, поток и файл
2. Откройте видеофайл и скопируйте параметры кодека
3. Просто скопируйте видеофайл на выход и не закрывайте выход
4. Откройте второй файл и, используя те же параметры, скопируйте с разными точками (чтобы добавить, убедитесь, что он добавлен в конец файла, я думаю?) в выходной файл
5. Закройте выходной файл

Я видел этот пост: Как использовать libavformat для объединения 2 видеофайлов с одним и тем же кодеком (повторное мультиплексирование)? и попробовал код, однако большая его часть устарела, поэтому я попытался обновить его для себя. Вот мой код:

#include <stdlib.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/timestamp.h>
#include <inttypes.h>

int output(const char* in_filename, const char* out_filename) {
    int ret, i;
    int *streams_list = NULL;
    int number_of_streams = 0;
    AVFrame *frame;
    AVPacket packet;
    int last_pts = 0;
    int last_dts = 0;

    AVFormatContext* output_format_context = NULL;
    avformat_alloc_output_context2(&output_format_context, NULL, NULL, out_filename);
    if (!output_format_context) {
        printf("Could not create output context\n");
        return -1;
    }

    if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
        ret = avio_open(&output_format_context->pb, out_filename, AVIO_FLAG_WRITE);
        if (ret < 0) {
            printf("Could not open output file '%s'", out_filename);
            return -1;
        }
    }

    AVFormatContext* av_format_ctx = avformat_alloc_context();
    if (!av_format_ctx) {
        printf("Couldn't created AVFormatContext\n");
        return -1;
    }

    if (avformat_open_input(&av_format_ctx, in_filename, NULL, NULL) != 0) {
        printf("Couldn't open video file\n");
        return -1;
    }


    number_of_streams = av_format_ctx->nb_streams;
    streams_list = (int*) av_mallocz_array(number_of_streams, sizeof(*streams_list));


    int stream_index = 0;
    for (i = 0; i < av_format_ctx->nb_streams; i++) {
        AVStream *out_stream;
        AVStream *in_stream = av_format_ctx->streams[i];
        AVCodecParameters *in_codecpar = in_stream->codecpar;
        if (in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
            streams_list[i] = -1;
            continue;
        }
        streams_list[i] = stream_index++;
        out_stream = avformat_new_stream(output_format_context, NULL);
        if (!out_stream) {
            printf("Failed allocating output stream\n");
            return -1;
        }
        ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
        if (ret < 0) {
            printf("Failed to copy codec parameters\n");
            return -1;
        }
    }

    ret = avformat_write_header(output_format_context, NULL);
        if (ret < 0) {
            printf("Error occurred when opening output file\n");
            return -1;
        }
    av_dump_format(output_format_context, 0, out_filename, 1);
    avformat_close_input(&av_format_ctx);
 
    /*This is redundant I know*/

    for (int i = 0; i<2;i++) {

        AVFormatContext* av_format_ctx = avformat_alloc_context();
        if (!av_format_ctx) {
            printf("Couldn't created AVFormatContext\n");
            return -1;
        }

        if (avformat_open_input(&av_format_ctx, in_filename, NULL, NULL) != 0) {
            printf("Couldn't open video file\n");
            return -1;
        }

        number_of_streams = av_format_ctx->nb_streams;
        streams_list = (int*) av_mallocz_array(number_of_streams, sizeof(*streams_list));

        int stream_index = 0;
        for (i = 0; i < av_format_ctx->nb_streams; i++) {
            AVStream *in_stream = av_format_ctx->streams[i];
            AVCodecParameters *in_codecpar = in_stream->codecpar;
            if (in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
              streams_list[i] = -1;
              continue;
            }
            streams_list[i] = stream_index++;
        }

        frame = av_frame_alloc();
        av_init_packet(&packet);

        int n = 1;
        AVStream *in_stream, *out_stream;
        printf("seeked");
        int count = 0;
        int64_t pts, dts;
        while (1) {
            ret = av_read_frame(av_format_ctx, &packet);
            if (ret < 0) {
                break;
            }
            in_stream  = av_format_ctx->streams[packet.stream_index];
            if (packet.stream_index >= number_of_streams || streams_list[packet.stream_index] < 0) {
                av_packet_unref(&packet);
                continue;
            }
            packet.stream_index = streams_list[packet.stream_index];
            out_stream = output_format_context->streams[packet.stream_index];
            /* copy packet */
            packet.pts = last_pts + av_rescale_q_rnd(last_pts + packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
            packet.dts = last_dts + av_rescale_q_rnd(last_dts + packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
            packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
            packet.pos = -1;
            ret = av_interleaved_write_frame(output_format_context, &packet);
            count++;
            packet.flags |= AV_PKT_FLAG_KEY;
            pts = packet.pts;
            dts = packet.dts;
            packet.stream_index = 0;
            if (ret < 0) {
                printf("Error muxing packet\n");
                return -1;
                break;
            }
        av_packet_unref(&packet);
        }
        avformat_close_input(&av_format_ctx);
        last_pts += pts;
        last_dts += dts;
    }    
    av_write_trailer(output_format_context);

    /* close output */
    if (output_format_context && !(output_format_context->oformat->flags & AVFMT_NOFILE)) {
        avio_closep(&output_format_context->pb);
        avformat_free_context(output_format_context);
        av_freep(&streams_list);
    }
    if (ret < 0 && ret != AVERROR_EOF) {
        printf("Error occurred: \n");
        return -1;
    }

    return 0;
}

В случае успеха он должен дать мне тот же файл, только что зацикленный еще раз. Однако это не так, и я просто получаю входной файл сам по себе в качестве вывода. Мне кажется, что я перезаписываю что-то важное или неправильно подсчитываются баллы. Это должно быть просто, но я не могу понять, что происходит и как решить проблему. Если кто-то может помочь, я был бы очень благодарен. Заранее спасибо за любые ответы.

РЕДАКТИРОВАТЬ

Оказывается, break также вызывал разрыв цикла for. Однако теперь я получаю сообщение об ошибке Application provided invalid, non monotonically increasing dts to muxer in stream 0: 2660400 >= NOPTS


person C4RN4GE    schedule 30.07.2020    source источник