[FFmpeg-devel] [PATCH] ffmpeg: redesign video resampling in case of mid-stream video size/format change

Stefano Sabatini stefano.sabatini-lala at poste.it
Sun Apr 17 12:13:45 CEST 2011


The new design supports video resolution/format change with and
without AVFILTER_CONFIG, thus avoiding the need for the
av_vsrc_buffer_add_frame2() hack.

When a change in video resolution/format is detected, a scaling
context is lazily initialized, and used for rescaling the input video
always to the same destination size/format.

Signed-off-by: Stefano Sabatini <stefano.sabatini-lala at poste.it>
---
 ffmpeg.c |  104 ++++++++++++++++++++++++++++---------------------------------
 1 files changed, 48 insertions(+), 56 deletions(-)

diff --git a/ffmpeg.c b/ffmpeg.c
index 7889309..5223deb 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -176,9 +176,8 @@ static int loop_output = AVFMT_NOOUTPUTLOOP;
 static int qp_hist = 0;
 #if CONFIG_AVFILTER
 static char *vfilters = NULL;
-#else
-static unsigned int sws_flags = SWS_BICUBIC;
 #endif
+static unsigned int sws_flags = SWS_BICUBIC;
 
 static int intra_only = 0;
 static int audio_sample_rate = 44100;
@@ -1132,13 +1131,28 @@ static void do_video_out(AVFormatContext *s,
                          int *frame_size)
 {
     int nb_frames, i, ret, resample_changed;
-    AVFrame *final_picture, *formatted_picture, *resampling_dst;
+    AVFrame *final_picture = in_picture;
     AVCodecContext *enc, *dec;
     double sync_ipts;
+    int dst_width, dst_height;
+    enum PixelFormat dst_pix_fmt;
+#if CONFIG_AVFILTER
+    AVFilterLink *inlink = ost->input_video_filter->outputs[0];
+#endif
 
     enc = ost->st->codec;
     dec = ist->st->codec;
 
+#if CONFIG_AVFILTER
+    dst_width   = inlink->w;
+    dst_height  = inlink->h;
+    dst_pix_fmt = inlink->format;
+#else
+    dst_width   = enc->width;
+    dst_height  = enc->height;
+    dst_pix_fmt = enc->pix_fmt;
+#endif
+
     sync_ipts = get_sync_ipts(ost) / av_q2d(enc->time_base);
 
     /* by default, we output a single frame */
@@ -1175,9 +1189,7 @@ static void do_video_out(AVFormatContext *s,
     if (nb_frames <= 0)
         return;
 
-    formatted_picture = in_picture;
-    final_picture = formatted_picture;
-    resampling_dst = &ost->pict_tmp;
+    ost->video_resample = dec->width != dst_width || dec->height != dst_height || dec->pix_fmt != dst_pix_fmt;
 
     resample_changed = ost->resample_width   != dec->width  ||
                        ost->resample_height  != dec->height ||
@@ -1189,34 +1201,39 @@ static void do_video_out(AVFormatContext *s,
                ist->file_index, ist->index,
                ost->resample_width, ost->resample_height, avcodec_get_pix_fmt_name(ost->resample_pix_fmt),
                dec->width         , dec->height         , avcodec_get_pix_fmt_name(dec->pix_fmt));
-        if(!ost->video_resample)
+        ost->resample_width   = dec->width;
+        ost->resample_height  = dec->height;
+        ost->resample_pix_fmt = dec->pix_fmt;
+    }
+
+    if (ost->video_resample && (!ost->img_resample_ctx || resample_changed)) {
+        if (ost->pict_tmp.data[0])
+            av_freep(&ost->pict_tmp.data[0]);
+        avcodec_get_frame_defaults(&ost->pict_tmp);
+        if (avpicture_alloc((AVPicture*)&ost->pict_tmp, dst_pix_fmt, dst_width, dst_height)) {
+            av_log(NULL, AV_LOG_ERROR, "Cannot allocate temp picture, check pix fmt\n");
+            ffmpeg_exit(1);
+        }
+
+        if (ost->img_resample_ctx) {
+            sws_freeContext(ost->img_resample_ctx);
+            ost->img_resample_ctx = NULL;
+        }
+        sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
+        ost->img_resample_ctx = sws_getContext(dec->width, dec->height, dec->pix_fmt,
+                                               dst_width , dst_height , dst_pix_fmt,
+                                               sws_flags, NULL, NULL, NULL);
+        if (!ost->img_resample_ctx) {
+            av_log(NULL, AV_LOG_ERROR, "Cannot get resampling context\n");
             ffmpeg_exit(1);
+        }
     }
 
-#if !CONFIG_AVFILTER
     if (ost->video_resample) {
+        sws_scale(ost->img_resample_ctx, in_picture->data, in_picture->linesize,
+                  0, ost->resample_height, ost->pict_tmp.data, ost->pict_tmp.linesize);
         final_picture = &ost->pict_tmp;
-        if (resample_changed) {
-            /* initialize a new scaler context */
-            sws_freeContext(ost->img_resample_ctx);
-            sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
-            ost->img_resample_ctx = sws_getContext(
-                ist->st->codec->width,
-                ist->st->codec->height,
-                ist->st->codec->pix_fmt,
-                ost->st->codec->width,
-                ost->st->codec->height,
-                ost->st->codec->pix_fmt,
-                sws_flags, NULL, NULL, NULL);
-            if (ost->img_resample_ctx == NULL) {
-                fprintf(stderr, "Cannot get resampling context\n");
-                ffmpeg_exit(1);
-            }
-        }
-        sws_scale(ost->img_resample_ctx, formatted_picture->data, formatted_picture->linesize,
-              0, ost->resample_height, resampling_dst->data, resampling_dst->linesize);
     }
-#endif
 
     /* duplicates frame if needed */
     for(i=0;i<nb_frames;i++) {
@@ -1631,10 +1648,7 @@ static int output_packet(AVInputStream *ist, int ist_index,
                     if (ist->st->sample_aspect_ratio.num) sar = ist->st->sample_aspect_ratio;
                     else                                  sar = ist->st->codec->sample_aspect_ratio;
                     // add it to be filtered
-                    av_vsrc_buffer_add_frame2(ost->input_video_filter, &picture,
-                                             ist->pts,
-                                             sar, ist->st->codec->width, ist->st->codec->height,
-                                             ist->st->codec->pix_fmt, "0:0"); //TODO user setable params
+                    av_vsrc_buffer_add_frame(ost->input_video_filter, &picture, ist->pts, sar);
                 }
             }
         }
@@ -2270,30 +2284,8 @@ static int transcode(AVFormatContext **output_files,
                 ost->video_resample = codec->width   != icodec->width  ||
                                       codec->height  != icodec->height ||
                                       codec->pix_fmt != icodec->pix_fmt;
-                if (ost->video_resample) {
-#if !CONFIG_AVFILTER
-                    avcodec_get_frame_defaults(&ost->pict_tmp);
-                    if(avpicture_alloc((AVPicture*)&ost->pict_tmp, codec->pix_fmt,
-                                         codec->width, codec->height)) {
-                        fprintf(stderr, "Cannot allocate temp picture, check pix fmt\n");
-                        ffmpeg_exit(1);
-                    }
-                    sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
-                    ost->img_resample_ctx = sws_getContext(
-                        icodec->width,
-                        icodec->height,
-                            icodec->pix_fmt,
-                            codec->width,
-                            codec->height,
-                            codec->pix_fmt,
-                            sws_flags, NULL, NULL, NULL);
-                    if (ost->img_resample_ctx == NULL) {
-                        fprintf(stderr, "Cannot get resampling context\n");
-                        ffmpeg_exit(1);
-                    }
-#endif
+                if (ost->video_resample)
                     codec->bits_per_raw_sample= frame_bits_per_raw_sample;
-                }
                 ost->resample_height = icodec->height;
                 ost->resample_width  = icodec->width;
                 ost->resample_pix_fmt= icodec->pix_fmt;
@@ -2785,7 +2777,7 @@ static int transcode(AVFormatContext **output_files,
                 av_freep(&ost->st->codec->subtitle_header);
                 av_free(ost->pict_tmp.data[0]);
                 av_free(ost->forced_kf_pts);
-                if (ost->video_resample)
+                if (ost->img_resample_ctx)
                     sws_freeContext(ost->img_resample_ctx);
                 if (ost->resample)
                     audio_resample_close(ost->resample);
-- 
1.7.2.3



More information about the ffmpeg-devel mailing list