[FFmpeg-devel] [PATCH] '-longest' command-line argument realization

Michael N. Pritula pritula
Tue Feb 3 13:01:58 CET 2009


Hello.
I suggest patch to realize '-longest' key with following semantics:
All video and audio streams with needed encoding in output file will be 
same time length and this length will be equal to longest stream in 
output file. For every shorter audio stream it will be continued with 
silence, and for every shorter video stream it will be continued with 
last picture, encoded to this stream.
Waiting for your comments.
The patch (to revision 16967) (doubled in attachment):
--- ffmpeg.c.mplayerhq    2009-02-03 10:17:49.000000000 +0300
+++ ffmpeg.c.mplayerhq.mod    2009-02-03 10:29:12.000000000 +0300
@@ -192,6 +192,7 @@
static float audio_drift_threshold= 0.1;
static int copy_ts= 0;
static int opt_shortest = 0;
+static int opt_longest = 0;
static int video_global_header = 0;
static char *vstats_filename;
static FILE *vstats_file;
@@ -286,6 +287,7 @@
                                is not defined */
    int64_t       pts;       /* current pts */
    int is_start;            /* is 1 at the start and after a 
discontinuity */
+    AVFrame last_picture;
} AVInputStream;

typedef struct AVInputFile {
@@ -1260,6 +1262,7 @@
                        /* no picture yet */
                        goto discard_packet;
                    }
+                    ist->last_picture = picture;
                    if (ist->st->codec->time_base.num != 0) {
                        ist->next_pts += ((int64_t)AV_TIME_BASE *
                                          ist->st->codec->time_base.num) /
@@ -2177,6 +2180,115 @@
        }
    }

+    if (opt_longest) {
+        double opts_max = -1e100;
+        int istreams_needed[MAX_STREAMS];
+        int nb_istreams_needed = 0;
+        for(i=0;i<nb_ostreams;i++) {
+            double opts;
+            ost = ost_table[i];
+            if(ost->st->codec->codec_type == CODEC_TYPE_VIDEO)
+                opts = ost->sync_opts * av_q2d(ost->st->codec->time_base);
+            else
+                opts = ost->st->pts.val * av_q2d(ost->st->time_base);
+            if (opts > opts_max)
+                opts_max = opts;
+        }
+        for(i=0;i<nb_ostreams;i++) {
+            if ((ost_table[i]->st->codec->codec_type == 
CODEC_TYPE_VIDEO || ost_table[i]->st->codec->codec_type == 
CODEC_TYPE_AUDIO) && ost_table[i]->encoding_needed && 
ist_table[ost_table[i]->source_index]->decoding_needed) {
+                double opts, granularity;
+                ost = ost_table[i];
+                os = output_files[ost->file_index];
+                ist = ist_table[ost->source_index];
+                if(ost->st->codec->codec_type == CODEC_TYPE_VIDEO) {
+                    opts = ost->sync_opts * 
av_q2d(ost->st->codec->time_base);
+                    granularity = av_q2d(ost->st->codec->time_base);
+                } else {
+                    opts = ost->st->pts.val * av_q2d(ost->st->time_base);
+                    granularity = av_q2d(ost->st->time_base);
+                }
+                if (granularity < 0)
+                    granularity = 0;
+                if (opts + granularity / 2.0 < opts_max) {
+                    int j;
+                    for(j=0;j<nb_istreams_needed;j++)
+                        if (ost->source_index == istreams_needed[j])
+                            break;
+                    istreams_needed[j] = ost->source_index;
+                    if (j >= nb_istreams_needed)
+                        nb_istreams_needed = j + 1;
+                }
+            }
+        }
+        for(i=0;i<nb_istreams_needed;i++) {
+            int continue_flag = 0;
+            double input_granularity = 0;
+            ist = ist_table[istreams_needed[i]];
+            switch (ist->st->codec->codec_type) {
+            case CODEC_TYPE_VIDEO:
+                input_granularity = av_q2d(ist->st->codec->time_base);
+                break;
+            default:
+                input_granularity = av_q2d(ist->st->time_base);
+                break;
+            }
+            do {
+                int j;
+                continue_flag = 0;
+                for(j=0;j<nb_ostreams;j++) {
+                    if (ost_table[j]->encoding_needed && 
ost_table[j]->source_index == istreams_needed[i]) {
+                        double opts = 0;
+                        double granularity = 0;
+                        ost = ost_table[j];
+                        os = output_files[ost->file_index];
+                        switch (ost->st->codec->codec_type) {
+                        case CODEC_TYPE_AUDIO: {
+                            uint8_t *samples = NULL;
+                            int samples_size = 0;
+                            opts = ost->st->pts.val * 
av_q2d(ost->st->time_base);
+                            granularity = av_q2d(ost->st->time_base);
+                            while (opts + granularity / 2.0 < opts_max) {
+                                int count_to_write = 
(int)(av_get_bits_per_sample_format(ist->st->codec->sample_fmt) / 8 * 
ist->st->codec->channels * FFMAX(1, ist->st->codec->sample_rate * 
(opts_max-opts)));
+                                while (count_to_write > 0) {
+                                    int data_size = 
FFMIN(AVCODEC_MAX_AUDIO_FRAME_SIZE, count_to_write);
+                                    if (samples_size < data_size) {
+                                        if (samples)
+                                            av_free(samples);
+                                        samples_size = data_size;
+                                        samples = av_malloc(samples_size);
+                                        memset(samples, 0, samples_size);
+                                    }
+                                    do_audio_out(os, ost, ist, samples, 
data_size);
+                                    count_to_write -= data_size;
+                                }
+                                opts = ost->st->pts.val * 
av_q2d(ost->st->time_base);
+                            }
+                            if (samples)
+                                av_free(samples);
+                            break;
+                        }
+                        case CODEC_TYPE_VIDEO:
+                            opts = ost->sync_opts * 
av_q2d(ost->st->codec->time_base);
+                            granularity = 
av_q2d(ost->st->codec->time_base);
+                            if (opts < opts_max) {
+                                int frame_size = 0;
+                                do_video_out(os, ost, ist, 
&ist->last_picture, &frame_size);
+                                if (vstats_filename && frame_size)
+                                    do_video_stats(os, ost, frame_size);
+                                opts = ost->sync_opts * 
av_q2d(ost->st->codec->time_base);
+                                continue_flag = opts < opts_max;
+                            }
+                            break;
+                        }
+                    }
+                }
+                if (continue_flag) {
+                    ist->pts += input_granularity * AV_TIME_BASE;
+                }
+            } while (continue_flag);
+        }
+    }
+
    term_exit();

    /* write the trailer if needed and close file */
@@ -3794,6 +3906,7 @@
    { "vglobal", HAS_ARG | OPT_INT | OPT_EXPERT, 
{(void*)&video_global_header}, "video global header storage type", "" },
    { "copyts", OPT_BOOL | OPT_EXPERT, {(void*)&copy_ts}, "copy 
timestamps" },
    { "shortest", OPT_BOOL | OPT_EXPERT, {(void*)&opt_shortest}, "finish 
encoding within shortest input" }, //
+    { "longest", OPT_BOOL | OPT_EXPERT, {(void*)&opt_longest}, "append 
shorter streams to longest duration" },
    { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, 
{(void*)&dts_delta_threshold}, "timestamp discontinuity delta 
threshold", "threshold" },
    { "programid", HAS_ARG | OPT_INT | OPT_EXPERT, 
{(void*)&opt_programid}, "desired program number", "" },
    { "xerror", OPT_BOOL, {(void*)&exit_on_error}, "exit on error", 
"error" },

------------------------------------------------------------------------

--- ffmpeg.c.mplayerhq	2009-02-03 10:17:49.000000000 +0300
+++ ffmpeg.c.mplayerhq.mod	2009-02-03 10:29:12.000000000 +0300
@@ -192,6 +192,7 @@
 static float audio_drift_threshold= 0.1;
 static int copy_ts= 0;
 static int opt_shortest = 0;
+static int opt_longest = 0;
 static int video_global_header = 0;
 static char *vstats_filename;
 static FILE *vstats_file;
@@ -286,6 +287,7 @@
                                 is not defined */
     int64_t       pts;       /* current pts */
     int is_start;            /* is 1 at the start and after a discontinuity */
+    AVFrame last_picture;
 } AVInputStream;
 
 typedef struct AVInputFile {
@@ -1260,6 +1262,7 @@
                         /* no picture yet */
                         goto discard_packet;
                     }
+                    ist->last_picture = picture;
                     if (ist->st->codec->time_base.num != 0) {
                         ist->next_pts += ((int64_t)AV_TIME_BASE *
                                           ist->st->codec->time_base.num) /
@@ -2177,6 +2180,115 @@
         }
     }
 
+    if (opt_longest) {
+        double opts_max = -1e100;
+        int istreams_needed[MAX_STREAMS];
+        int nb_istreams_needed = 0;
+        for(i=0;i<nb_ostreams;i++) {
+            double opts;
+            ost = ost_table[i];
+            if(ost->st->codec->codec_type == CODEC_TYPE_VIDEO)
+                opts = ost->sync_opts * av_q2d(ost->st->codec->time_base);
+            else
+                opts = ost->st->pts.val * av_q2d(ost->st->time_base);
+            if (opts > opts_max)
+                opts_max = opts;
+        }
+        for(i=0;i<nb_ostreams;i++) {
+            if ((ost_table[i]->st->codec->codec_type == CODEC_TYPE_VIDEO || ost_table[i]->st->codec->codec_type == CODEC_TYPE_AUDIO) && ost_table[i]->encoding_needed && ist_table[ost_table[i]->source_index]->decoding_needed) {
+                double opts, granularity;
+                ost = ost_table[i];
+                os = output_files[ost->file_index];
+                ist = ist_table[ost->source_index];
+                if(ost->st->codec->codec_type == CODEC_TYPE_VIDEO) {
+                    opts = ost->sync_opts * av_q2d(ost->st->codec->time_base);
+                    granularity = av_q2d(ost->st->codec->time_base);
+                } else {
+                    opts = ost->st->pts.val * av_q2d(ost->st->time_base);
+                    granularity = av_q2d(ost->st->time_base);
+                }
+                if (granularity < 0)
+                    granularity = 0;
+                if (opts + granularity / 2.0 < opts_max) {
+                    int j;
+                    for(j=0;j<nb_istreams_needed;j++)
+                        if (ost->source_index == istreams_needed[j])
+                            break;
+                    istreams_needed[j] = ost->source_index;
+                    if (j >= nb_istreams_needed)
+                        nb_istreams_needed = j + 1;
+                }
+            }
+        }
+        for(i=0;i<nb_istreams_needed;i++) {
+            int continue_flag = 0;
+            double input_granularity = 0;
+            ist = ist_table[istreams_needed[i]];
+            switch (ist->st->codec->codec_type) {
+            case CODEC_TYPE_VIDEO:
+                input_granularity = av_q2d(ist->st->codec->time_base);
+                break;
+            default:
+                input_granularity = av_q2d(ist->st->time_base);
+                break;
+            }
+            do {
+                int j;
+                continue_flag = 0;
+                for(j=0;j<nb_ostreams;j++) {
+                    if (ost_table[j]->encoding_needed && ost_table[j]->source_index == istreams_needed[i]) {
+                        double opts = 0;
+                        double granularity = 0;
+                        ost = ost_table[j];
+                        os = output_files[ost->file_index];
+                        switch (ost->st->codec->codec_type) {
+                        case CODEC_TYPE_AUDIO: {
+                            uint8_t *samples = NULL;
+                            int samples_size = 0;
+                            opts = ost->st->pts.val * av_q2d(ost->st->time_base);
+                            granularity = av_q2d(ost->st->time_base);
+                            while (opts + granularity / 2.0 < opts_max) {
+                                int count_to_write = (int)(av_get_bits_per_sample_format(ist->st->codec->sample_fmt) / 8 * ist->st->codec->channels * FFMAX(1, ist->st->codec->sample_rate * (opts_max-opts)));
+                                while (count_to_write > 0) {
+                                    int data_size = FFMIN(AVCODEC_MAX_AUDIO_FRAME_SIZE, count_to_write);
+                                    if (samples_size < data_size) {
+                                        if (samples)
+                                            av_free(samples);
+                                        samples_size = data_size;
+                                        samples = av_malloc(samples_size);
+                                        memset(samples, 0, samples_size);
+                                    }
+                                    do_audio_out(os, ost, ist, samples, data_size);
+                                    count_to_write -= data_size;
+                                }
+                                opts = ost->st->pts.val * av_q2d(ost->st->time_base);
+                            }
+                            if (samples)
+                                av_free(samples);
+                            break;
+                        }
+                        case CODEC_TYPE_VIDEO:
+                            opts = ost->sync_opts * av_q2d(ost->st->codec->time_base);
+                            granularity = av_q2d(ost->st->codec->time_base);
+                            if (opts < opts_max) {
+                                int frame_size = 0;
+                                do_video_out(os, ost, ist, &ist->last_picture, &frame_size);
+                                if (vstats_filename && frame_size)
+                                    do_video_stats(os, ost, frame_size);
+                                opts = ost->sync_opts * av_q2d(ost->st->codec->time_base);
+                                continue_flag = opts < opts_max;
+                            }
+                            break;
+                        }
+                    }
+                }
+                if (continue_flag) {
+                    ist->pts += input_granularity * AV_TIME_BASE;
+                }
+            } while (continue_flag);
+        }
+    }
+
     term_exit();
 
     /* write the trailer if needed and close file */
@@ -3794,6 +3906,7 @@
     { "vglobal", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&video_global_header}, "video global header storage type", "" },
     { "copyts", OPT_BOOL | OPT_EXPERT, {(void*)&copy_ts}, "copy timestamps" },
     { "shortest", OPT_BOOL | OPT_EXPERT, {(void*)&opt_shortest}, "finish encoding within shortest input" }, //
+    { "longest", OPT_BOOL | OPT_EXPERT, {(void*)&opt_longest}, "append shorter streams to longest duration" },
     { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&dts_delta_threshold}, "timestamp discontinuity delta threshold", "threshold" },
     { "programid", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&opt_programid}, "desired program number", "" },
     { "xerror", OPT_BOOL, {(void*)&exit_on_error}, "exit on error", "error" },

-------------- next part --------------
A non-text attachment was scrubbed...
Name: ffmpeg.c.longest.patch
Type: text/x-patch
Size: 7545 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090203/ab3bcfff/attachment.bin>



More information about the ffmpeg-devel mailing list