[PATCH] added concatenation option
Geza Kovacs
gkovacs
Thu Apr 2 10:59:19 CEST 2009
---
ffmpeg.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 189 insertions(+), 0 deletions(-)
diff --git a/ffmpeg.c b/ffmpeg.c
index cb15120..15bb788 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -193,6 +193,7 @@ static char *vstats_filename;
static FILE *vstats_file;
static int opt_programid = 0;
static int copy_initial_nonkeyframes = 0;
+static int concatenate_video_files = 0;
static int rate_emu = 0;
@@ -1537,6 +1538,176 @@ static int stream_index_from_inputs(AVFormatContext **input_files,
return -1;
}
+/**
+ * check_same_settings checks that the input formats are identical, used internally by concatenation
+ * @param AVFormatContext **input_format_contexts list of input format contexts
+ * @param int num_input_files number of input files.
+ * @return returns 0 on success or -1 on failure
+ */
+static int check_same_settings(AVFormatContext **input_format_contexts, int num_input_files)
+{
+ int width;
+ char width_set = 0;
+ int height;
+ char height_set = 0;
+ int frame_rate_num;
+ int frame_rate_den;
+ char frame_rate_set = 0;
+ int i;
+ int j;
+ for (i = 0; i < num_input_files; ++i) {
+ for (j = 0; j < input_format_contexts[i]->nb_streams; ++j) {
+ if (avcodec_open(input_format_contexts[i]->streams[j]->codec, avcodec_find_decoder(input_format_contexts[i]->streams[j]->codec->codec_id)) < 0) {
+ fprintf(stderr, "Error: could not open codec for input file %s\n", input_format_contexts[i]->filename);
+ return -1;
+ }
+ if (!frame_rate_set) {
+ frame_rate_set = 1;
+ frame_rate_num = input_format_contexts[i]->streams[j]->r_frame_rate.num;
+ frame_rate_den = input_format_contexts[i]->streams[j]->r_frame_rate.den;
+ }
+ else if (input_format_contexts[i]->streams[j]->r_frame_rate.num != frame_rate_num || input_format_contexts[i]->streams[j]->r_frame_rate.den != frame_rate_den) {
+ fprintf(stderr, "Error: different frame rate for input file %s: %i/%i vs existing %i/%i\n", input_format_contexts[i]->filename, input_format_contexts[i]->streams[j]->r_frame_rate.num, input_format_contexts[i]->streams[j]->r_frame_rate.den, frame_rate_num, frame_rate_den);
+ return -1;
+ }
+ if (!width_set) {
+ width_set = 1;
+ width = input_format_contexts[i]->streams[j]->codec->width;
+ }
+ else if (input_format_contexts[i]->streams[j]->codec->width != width) {
+ fprintf(stderr, "Error: different width for input file %s: %i vs existing %i\n", input_format_contexts[i]->filename, input_format_contexts[i]->streams[j]->codec->width, width);
+ return -1;
+ }
+ if (!height_set) {
+ height_set = 1;
+ height = input_format_contexts[i]->streams[j]->codec->height;
+ }
+ else if (input_format_contexts[i]->streams[j]->codec->height != height) {
+ fprintf(stderr, "Error: different height for input file %s: %i vs existing %i\n", input_format_contexts[i]->filename, input_format_contexts[i]->streams[j]->codec->width, width);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * get_audio_codec retrives the CodecID of the audio stream
+ * @param AVFormatContext *input_format_context input format context
+ * @return returns audio CodecID on success or 0 on failure
+ */
+static int get_audio_codec(AVFormatContext *input_format_context)
+{
+ int i;
+ for (i = 0; i < input_format_context->nb_streams; ++i) {
+ if (input_format_context->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
+ return input_format_context->streams[i]->codec->codec_id;
+ }
+ }
+ return 0;
+}
+
+/**
+ * get_video_codec retrives the CodecID of the video stream
+ * @param AVFormatContext *input_format_context input format context
+ * @return returns video CodecID on success or 0 on failure
+ */
+static int get_video_codec(AVFormatContext *input_format_context)
+{
+ int i;
+ for (i = 0; i < input_format_context->nb_streams; ++i) {
+ if (input_format_context->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
+ return input_format_context->streams[i]->codec->codec_id;
+ }
+ }
+ return 0;
+}
+
+/**
+ * setup_output_file populates the AVFormatContext for the output file with appropriate values from input_format_context, used internally by concatenation
+ * @param AVFormatContext *output_format_context format context for output file
+ * @param AVFormatContext *input_format_context format context for input file, assumed to be of same format as desired output
+ * @return returns 0 on success
+ */
+static int setup_output_file(AVFormatContext *output_format_context, AVFormatContext *input_format_context)
+{
+ output_format_context->oformat->video_codec = get_video_codec(input_format_context);
+ output_format_context->oformat->audio_codec = get_audio_codec(output_format_context);
+ output_format_context->timestamp = input_format_context->timestamp;
+ output_format_context->start_time = input_format_context->start_time;
+ output_format_context->bit_rate = input_format_context->bit_rate;
+ int i;
+ for (i = 0; i < input_format_context->nb_streams; ++i) {
+ if (i >= output_format_context->nb_streams) {
+ output_format_context->streams[i] = av_new_stream(output_format_context, input_format_context->streams[i]->id);
+ }
+ if (!output_format_context->streams[i]) {
+ fprintf(stderr, "Error: Could not allocate stream %i in file %s\n", i, output_format_context->filename);
+ return -1;
+ }
+ output_format_context->streams[i]->id = input_format_context->streams[i]->id;
+ output_format_context->streams[i]->sample_aspect_ratio = input_format_context->streams[i]->sample_aspect_ratio;
+ AVCodec *codec = avcodec_find_encoder(input_format_context->streams[i]->codec->codec_id);
+ output_format_context->streams[i]->codec = avcodec_alloc_context();
+ output_format_context->streams[i]->codec->sample_aspect_ratio = output_format_context->streams[i]->sample_aspect_ratio;
+ output_format_context->streams[i]->codec->extradata = input_format_context->streams[i]->codec->extradata;
+ output_format_context->streams[i]->codec->extradata_size = input_format_context->streams[i]->codec->extradata_size;
+ output_format_context->streams[i]->codec->codec_type = input_format_context->streams[i]->codec->codec_type;
+ if (input_format_context->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
+ if(output_format_context->oformat->flags & AVFMT_GLOBALHEADER)
+ output_format_context->streams[i]->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ output_format_context->streams[i]->codec->pix_fmt = input_format_context->streams[i]->codec->pix_fmt;
+ output_format_context->streams[i]->codec->time_base = input_format_context->streams[i]->codec->time_base;
+ output_format_context->streams[i]->codec->width = input_format_context->streams[i]->codec->width;
+ output_format_context->streams[i]->codec->height = input_format_context->streams[i]->codec->height;
+ }
+ else if (input_format_context->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
+ output_format_context->streams[i]->codec->sample_rate = input_format_context->streams[i]->codec->sample_rate;
+ }
+ if (avcodec_open(output_format_context->streams[i]->codec, codec) < 0) {
+ fprintf(stderr, "Error: Could not open codec for stream %i in file %s\n", i, output_format_context->filename);
+ return -1;
+ }
+ }
+ if (av_write_header(output_format_context) != 0) {
+ fprintf(stderr, "Error: could not write header for %s\n", output_format_context->filename);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * write_frames_to_output reads frames from the input format contexts and writes them to the output format context
+ * @param AVFormatContext **input_format_contexts list of input format contexts
+ * @param int num_input_files number of input files
+ * @param AVFormatContext *output_format_context format context for the output file
+ * @return returns 0 on success
+ */
+static int write_frames_to_output(AVFormatContext **input_format_contexts, int num_input_files, AVFormatContext *output_format_context)
+{
+ AVPacket *packet = av_malloc(sizeof(AVPacket));
+ int64_t packet_pts;
+ int64_t packet_timestamp_offset = 0;
+ int i;
+ for (i = 0; i < num_input_files; ++i) {
+ av_get_packet(input_format_contexts[i]->pb, packet, 4096);
+ av_read_frame(input_format_contexts[i], packet);
+ while (av_read_frame(input_format_contexts[i], packet) == 0) {
+ packet->pts += packet_timestamp_offset;
+ packet->dts += packet_timestamp_offset;
+ packet_pts = packet->pts;
+ if (av_write_frame(output_format_context, packet) != 0) {
+ fprintf(stderr, "Error writing frame to %s from input file %s\n", output_format_context->filename, input_format_contexts[i]->filename);
+ return -1;
+ }
+ av_free_packet(packet);
+
+ }
+ packet_timestamp_offset += packet_pts;
+ }
+ return 0;
+}
+
/*
* The following code is the main loop of the file converter
*/
@@ -1546,6 +1717,23 @@ static int av_encode(AVFormatContext **output_files,
int nb_input_files,
AVStreamMap *stream_maps, int nb_stream_maps)
{
+ if (concatenate_video_files) {
+ printf("concatenating video files\n");
+ if (check_same_settings(input_files, nb_input_files) != 0) {
+ av_exit(1);
+ }
+ printf("file formats are the same\n");
+ if (setup_output_file(output_files[0], input_files[0]) != 0) {
+ av_exit(1);
+ }
+ printf("set up output file\n");
+ if (write_frames_to_output(input_files, nb_input_files, output_files[0]) != 0) {
+ av_exit(1);
+ }
+ av_write_trailer(output_files[0]);
+ printf("wrote frames to output\n");
+ return 0;
+ }
int ret = 0, i, j, k, n, nb_istreams = 0, nb_ostreams = 0;
AVFormatContext *is, *os;
AVCodecContext *codec, *icodec;
@@ -3826,6 +4014,7 @@ static const OptionDef options[] = {
{ "programid", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&opt_programid}, "desired program number", "" },
{ "xerror", OPT_BOOL, {(void*)&exit_on_error}, "exit on error", "error" },
{ "copyinkf", OPT_BOOL | OPT_EXPERT, {(void*)©_initial_nonkeyframes}, "copy initial non-keyframes" },
+ { "conc", OPT_BOOL, {(void*)&concatenate_video_files}, "concatenate video files", "concatenate" },
/* video options */
{ "b", OPT_FUNC2 | HAS_ARG | OPT_VIDEO, {(void*)opt_bitrate}, "set bitrate (in bits/s)", "bitrate" },
--
1.6.0.4
--=-Y3ZFR3xvyDetFOi0vx3n--
More information about the ffmpeg-devel
mailing list