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

Michael N. Pritula pritula
Wed Feb 11 16:19:48 CET 2009


Michael Niedermayer wrote:
> for what is it good to lengthen streams to a common point?

Some players stop playing when one of the streams ended. Also this 
problem has been raised in FFmpeg-user mailing list: 
http://lists.mplayerhq.hu/pipermail/ffmpeg-user/2007-June/009625.html
And there are number of clips with different duration of streams. For 
example, clip with ending captions without any sound glued to ordinary 
clip with sound.
Here is a patch with satisfacted remarks:
--- ffmpeg.c.mplayerhq    2009-02-03 10:17:49.000000000 +0300
+++ ffmpeg.c    2009-02-11 17:47:07.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,111 @@
         }
     }
 
+    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);
+            }
+            opts_max = FFMAX(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);
+                }
+                granularity = FFMAX(0, granularity);
+                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) {
+                                        av_free(samples);
+                                        samples_size = data_size;
+                                        samples = av_mallocz(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);
+                            }
+                            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 +3902,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" },

--- Changelog.mplayerhq    2009-02-03 10:17:49.000000000 +0300
+++ Changelog    2009-02-11 17:58:35.000000000 +0300
@@ -146,6 +146,7 @@
 - hybrid WavPack support
 - R3D REDCODE demuxer
 - ALSA support for playback and record
+- '-longest' command line argument support
 
 version 0.4.9-pre1:
 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ffmpeg.longest.patch
Type: text/x-patch
Size: 7620 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090211/8af87c8c/attachment.bin>



More information about the ffmpeg-devel mailing list