FFMPEG Corrupt output remuxing MP4 (Using API in C) -First file OK, 2nd file onwards is not - Stack Overflow

admin2025-04-24  2

I have a simple application written in C - it takes the video from a RTSP camera and just writes to disk in 1 minute segments. The first file created works fine, plays on anlmost anything. The Second file does not play. Programatically, The trace shows they are the same code flows, but I cant seem to find where the problem is to allow the 2nd file to be play exactly the same as the first.

There are frames in the 2nd file but they are random. The second file is created EXACTLY the same way as the first.

Any help from a guru would be greatly appreciated.

EDIT: FIX - The output duration needs to be set before the trailer is written.

int actual_duration = (int)difftime(time(NULL), start_time);

for (int i = 0; i < output_ctx->nb_streams; i++) {
    output_ctx->streams[i]->duration = actual_duration * AV_TIME_BASE;
}

output_ctx->duration = actual_duration * AV_TIME_BASE;
printf("DURATION = %d\r\n",output_ctx->duration);

// Set the start_time for the output context
output_ctx->start_time = 0;

av_write_trailer(output_ctx);

Code flow

   Open RTSP Stream 
A: Create File n context 
   Remux to file n 
   Wait for minute to change 
   Close File n context  
   increment n Goto A

Makefile

CC = gcc
CFLAGS = -Wall -g
LIBS = -lavformat -lavcodec -lavutil -lavdevice -lswscale -lavfilter -lavutil -lm -lz -lpthread

TARGET = rtsp_remux

all: $(TARGET)

$(TARGET): rtsp_remux.o
        $(CC) -o $(TARGET) rtsp_remux.o $(LIBS)

rtsp_remux.o: rtsp_remux.c
        $(CC) $(CFLAGS) -c rtsp_remux.c

clean:
        rm -f $(TARGET) rtsp_remux.o

.PHONY: all clean

rtsp_remux.c

#include <libavformat/avformat.h>
#include <libavutil/time.h>
#include <time.h>
#include <stdio.h>

#define OUTPUT_PREFIX "output"
#define OUTPUT_EXTENSION ".mp4"
#define MAX_FILES 4

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <RTSP URL>\n", argv[0]);
        return -1;
    }

    const char *rtsp_url = argv[1];
    AVFormatContext *input_ctx = NULL, *output_ctx = NULL;
    AVOutputFormat *output_fmt = NULL;
    AVPacket pkt;
    int ret, file_count = 0;
    char output_filename[1024];
    time_t current_time;
    struct tm *timeinfo;
    int rename_lock = 0;

    avformat_network_init();

    if ((ret = avformat_open_input(&input_ctx, rtsp_url, NULL, NULL)) < 0) {
        fprintf(stderr, "Could not open input file '%s'\n", rtsp_url);
        return -1;
    }

    if ((ret = avformat_find_stream_info(input_ctx, NULL)) < 0) {
        fprintf(stderr, "Failed to retrieve input stream information\n");
        return -1;
    }

    av_dump_format(input_ctx, 0, rtsp_url, 0);

    while (file_count < MAX_FILES) {
        snprintf(output_filename, sizeof(output_filename), "%s_%03d%s", OUTPUT_PREFIX, file_count, OUTPUT_EXTENSION);

        if ((ret = avformat_alloc_output_context2(&output_ctx, NULL, NULL, output_filename)) < 0) {
            fprintf(stderr, "Could not create output context\n");
            return -1;
        }

        output_fmt = output_ctx->oformat;

        for (int i = 0; i < input_ctx->nb_streams; i++) {
            AVStream *in_stream = input_ctx->streams[i];
            AVStream *out_stream = avformat_new_stream(output_ctx, NULL);
            if (!out_stream) {
                fprintf(stderr, "Failed allocating output stream\n");
                return -1;
            }

            if ((ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar)) < 0) {
                fprintf(stderr, "Failed to copy codec parameters\n");
                return -1;
            }
            out_stream->codecpar->codec_tag = 0;
        }

        if (!(output_fmt->flags & AVFMT_NOFILE)) {
            if ((ret = avio_open(&output_ctx->pb, output_filename, AVIO_FLAG_WRITE)) < 0) {
                fprintf(stderr, "Could not open output file '%s'\n", output_filename);
                return -1;
            }
        }

        if ((ret = avformat_write_header(output_ctx, NULL)) < 0) {
            fprintf(stderr, "Error occurred when opening output file\n");
            return -1;
        }

        while (1) {
            current_time = time(NULL);
            timeinfo = localtime(&current_time);

            if (timeinfo->tm_sec == 0 && !rename_lock) {
                rename_lock = 1;
                break;
            } else if (timeinfo->tm_sec != 0) {
                rename_lock = 0;
            }

            if ((ret = av_read_frame(input_ctx, &pkt)) < 0)
                break;

            AVStream *in_stream = input_ctx->streams[pkt.stream_index];
            AVStream *out_stream = output_ctx->streams[pkt.stream_index];

            pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
            pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
            pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
            pkt.pos = -1;

            if ((ret = av_interleaved_write_frame(output_ctx, &pkt)) < 0) {
                fprintf(stderr, "Error muxing packet\n");
                break;
            }

            av_packet_unref(&pkt);
        }

        av_write_trailer(output_ctx);

        if (!(output_fmt->flags & AVFMT_NOFILE))
            avio_closep(&output_ctx->pb);

        avformat_free_context(output_ctx);

        file_count++;
    }

    avformat_close_input(&input_ctx);
    avformat_network_deinit();

    return 0;
}

I have tried changing to pointers, freeing and different things. I was expecting the 2nd file created to behave identically to the first.

转载请注明原文地址:http://anycun.com/QandA/1745453834a90652.html