[FFmpeg-devel] [PATCH] lavfi/movie: check for format change more carefully.

Nicolas George george at nsup.org
Wed Sep 30 17:35:55 CEST 2015


Fix the segfault in trac ticket #4884.

Signed-off-by: Nicolas George <george at nsup.org>
---
 doc/filters.texi        |  8 ++++++++
 libavfilter/src_movie.c | 50 +++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index a4d828e..9ad5db9 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -13953,6 +13953,14 @@ Default value is "1".
 
 Note that when the movie is looped the source timestamps are not
 changed, so it will generate non monotonically increasing timestamps.
+
+ at item allow_format_change
+Allow format change in the streams. Format changes are normally not
+supported in filters, but a few filters, scale for example unoficially
+support them. If this option is not enabled, changes in format will result
+in a filtering error; if it is enabled, the check is bypassed. If the next
+filter does not support format changes, the behaviour is undefined, a crash
+is possible; use with extreme care.
 @end table
 
 It allows overlaying a second video on top of the main input of
diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
index bbdcbc8..fc2e07d 100644
--- a/libavfilter/src_movie.c
+++ b/libavfilter/src_movie.c
@@ -59,6 +59,7 @@ typedef struct MovieContext {
     char *stream_specs; /**< user-provided list of streams, separated by + */
     int stream_index; /**< for compatibility */
     int loop_count;
+    int allow_format_change;
 
     AVFormatContext *format_ctx;
     int eof;
@@ -83,6 +84,7 @@ static const AVOption movie_options[]= {
     { "streams",      "set streams",             OFFSET(stream_specs), AV_OPT_TYPE_STRING, {.str =  0},  CHAR_MAX, CHAR_MAX, FLAGS },
     { "s",            "set streams",             OFFSET(stream_specs), AV_OPT_TYPE_STRING, {.str =  0},  CHAR_MAX, CHAR_MAX, FLAGS },
     { "loop",         "set loop count",          OFFSET(loop_count),   AV_OPT_TYPE_INT,    {.i64 =  1},  0,        INT_MAX, FLAGS },
+    { "allow_format_change", "allow format change", OFFSET(allow_format_change), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
     { NULL },
 };
 
@@ -539,14 +541,46 @@ static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
     ff_dlog(ctx, "movie_push_frame(): file:'%s' %s\n", movie->file_name,
             describe_frame_to_str((char[1024]){0}, 1024, frame, frame_type, outlink));
 
-    if (st->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
-        if (frame->format != outlink->format) {
-            av_log(ctx, AV_LOG_ERROR, "Format changed %s -> %s, discarding frame\n",
-                av_get_pix_fmt_name(outlink->format),
-                av_get_pix_fmt_name(frame->format)
-                );
-            av_frame_free(&frame);
-            return 0;
+    if (!movie->allow_format_change) {
+        switch (st->st->codec->codec_type) {
+
+        case AVMEDIA_TYPE_VIDEO:
+            if (frame->width  != outlink->w ||
+                frame->height != outlink->h ||
+                frame->format != outlink->format) {
+                av_log(ctx, AV_LOG_ERROR,
+                       "Format change: %dx%d/%s -> %dx%d/%s, not supported\n",
+                       outlink->w, outlink->h,
+                       av_get_pix_fmt_name(outlink->format),
+                       frame->width, frame->height,
+                       av_get_pix_fmt_name(frame->format));
+                av_frame_free(&frame);
+                return AVERROR_PATCHWELCOME;
+            }
+            break;
+
+        case AVMEDIA_TYPE_AUDIO:
+            if (frame->format                != outlink->format         ||
+                frame->sample_rate           != outlink->sample_rate    ||
+                frame->channel_layout        != outlink->channel_layout ||
+                av_frame_get_channels(frame) != outlink->channels       ) {
+                char l1[128], l2[128];
+                av_get_channel_layout_string(l1, sizeof(l1),
+                                             outlink->channels,
+                                             outlink->channel_layout);
+                av_get_channel_layout_string(l2, sizeof(l2),
+                                             av_frame_get_channels(frame),
+                                             frame->channel_layout);
+                av_log(ctx, AV_LOG_ERROR,
+                       "Format change: %dHz/%s/%s -> %dHz/%s/%s, not supported\n",
+                       outlink->sample_rate, l1,
+                       av_get_sample_fmt_name(outlink->format),
+                       frame->sample_rate, l2,
+                       av_get_sample_fmt_name(frame->format));
+                av_frame_free(&frame);
+                return AVERROR_PATCHWELCOME;
+            }
+            break;
         }
     }
     ret = ff_filter_frame(outlink, frame);
-- 
2.5.3



More information about the ffmpeg-devel mailing list