[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