2 * copyright (c) 2007 Bobby Bingham
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 * @file libavfilter/vf_scale.c
27 #include "libswscale/swscale.h"
30 struct SwsContext
*sws
; ///< software scaler context
33 * New dimensions. Special values are:
34 * 0 = original width/height
35 * -1 = keep original aspect
39 int hsub
, vsub
; ///< chroma subsampling
40 int slice_y
; ///< top of current output slice
41 int slice_dir
; ///< detected slice direction order for the current frame
42 int input_is_pal
; ///< set to 1 if the input format is paletted
45 static av_cold
int init(AVFilterContext
*ctx
, const char *args
, void *opaque
)
47 ScaleContext
*scale
= ctx
->priv
;
50 sscanf(args
, "%d:%d", &scale
->w
, &scale
->h
);
52 /* sanity check params */
53 if (scale
->w
< -1 || scale
->h
< -1) {
54 av_log(ctx
, AV_LOG_ERROR
, "Size values less than -1 are not acceptable.\n");
57 if (scale
->w
== -1 && scale
->h
== -1)
58 scale
->w
= scale
->h
= 0;
63 static av_cold
void uninit(AVFilterContext
*ctx
)
65 ScaleContext
*scale
= ctx
->priv
;
66 sws_freeContext(scale
->sws
);
70 static int query_formats(AVFilterContext
*ctx
)
72 AVFilterFormats
*formats
;
75 formats
= avfilter_all_colorspaces();
76 avfilter_formats_ref(formats
, &ctx
->inputs
[0]->out_formats
);
78 if (ctx
->outputs
[0]) {
79 formats
= avfilter_all_colorspaces();
80 avfilter_formats_ref(formats
, &ctx
->outputs
[0]->in_formats
);
86 static int config_props(AVFilterLink
*outlink
)
88 AVFilterContext
*ctx
= outlink
->src
;
89 AVFilterLink
*inlink
= outlink
->src
->inputs
[0];
90 ScaleContext
*scale
= ctx
->priv
;
98 w
= av_rescale(h
, inlink
->w
, inlink
->h
);
100 h
= av_rescale(w
, inlink
->h
, inlink
->w
);
102 if (w
> INT_MAX
|| h
> INT_MAX
||
103 (h
* inlink
->w
) > INT_MAX
||
104 (w
* inlink
->h
) > INT_MAX
)
105 av_log(ctx
, AV_LOG_ERROR
, "Rescaled value for width or height is too big.\n");
110 /* TODO: make algorithm configurable */
111 scale
->sws
= sws_getContext(inlink
->w
, inlink
->h
, inlink
->format
,
112 outlink
->w
, outlink
->h
, outlink
->format
,
113 SWS_BILINEAR
, NULL
, NULL
, NULL
);
115 av_log(ctx
, AV_LOG_INFO
, "w:%d h:%d fmt:%s\n",
116 outlink
->w
, outlink
->h
, avcodec_get_pix_fmt_name(outlink
->format
));
118 avcodec_get_chroma_sub_sample(outlink
->format
, &scale
->hsub
, &scale
->vsub
);
120 scale
->input_is_pal
= inlink
->format
== PIX_FMT_PAL8
||
121 inlink
->format
== PIX_FMT_BGR4_BYTE
||
122 inlink
->format
== PIX_FMT_RGB4_BYTE
||
123 inlink
->format
== PIX_FMT_BGR8
||
124 inlink
->format
== PIX_FMT_RGB8
;
129 static void start_frame(AVFilterLink
*link
, AVFilterPicRef
*picref
)
131 ScaleContext
*scale
= link
->dst
->priv
;
132 AVFilterLink
*outlink
= link
->dst
->outputs
[0];
133 AVFilterPicRef
*outpicref
;
135 outpicref
= avfilter_get_video_buffer(outlink
, AV_PERM_WRITE
, outlink
->w
, outlink
->h
);
136 outpicref
->pts
= picref
->pts
;
137 outlink
->outpic
= outpicref
;
139 av_reduce(&outpicref
->pixel_aspect
.num
, &outpicref
->pixel_aspect
.den
,
140 (int64_t)picref
->pixel_aspect
.num
* outlink
->h
* link
->w
,
141 (int64_t)picref
->pixel_aspect
.den
* outlink
->w
* link
->h
,
144 scale
->slice_dir
= 0;
145 avfilter_start_frame(outlink
, avfilter_ref_pic(outpicref
, ~0));
148 static void draw_slice(AVFilterLink
*link
, int y
, int h
)
150 ScaleContext
*scale
= link
->dst
->priv
;
152 AVFilterPicRef
*cur_pic
= link
->cur_pic
;
155 if (!scale
->slice_dir
) {
156 if (y
!= 0 && y
+ h
!= link
->h
) {
157 av_log(scale
, AV_LOG_ERROR
, "Slices start in the middle!\n");
160 scale
->slice_dir
= y ?
-1 : 1;
161 scale
->slice_y
= y ? link
->dst
->outputs
[0]->h
: y
;
164 data
[0] = cur_pic
->data
[0] + y
* cur_pic
->linesize
[0];
165 data
[1] = scale
->input_is_pal ?
167 cur_pic
->data
[1] + (y
>>scale
->vsub
) * cur_pic
->linesize
[1];
168 data
[2] = cur_pic
->data
[2] + (y
>>scale
->vsub
) * cur_pic
->linesize
[2];
169 data
[3] = cur_pic
->data
[3] + y
* cur_pic
->linesize
[3];
171 out_h
= sws_scale(scale
->sws
, data
, cur_pic
->linesize
, y
, h
,
172 link
->dst
->outputs
[0]->outpic
->data
,
173 link
->dst
->outputs
[0]->outpic
->linesize
);
175 if (scale
->slice_dir
== -1)
176 scale
->slice_y
-= out_h
;
177 avfilter_draw_slice(link
->dst
->outputs
[0], scale
->slice_y
, out_h
);
178 if (scale
->slice_dir
== 1)
179 scale
->slice_y
+= out_h
;
182 AVFilter avfilter_vf_scale
= {
184 .description
= "Scale the input video to width:height size and/or convert the image format.",
189 .query_formats
= query_formats
,
191 .priv_size
= sizeof(ScaleContext
),
193 .inputs
= (AVFilterPad
[]) {{ .name
= "default",
194 .type
= CODEC_TYPE_VIDEO
,
195 .start_frame
= start_frame
,
196 .draw_slice
= draw_slice
,
197 .min_perms
= AV_PERM_READ
, },
199 .outputs
= (AVFilterPad
[]) {{ .name
= "default",
200 .type
= CODEC_TYPE_VIDEO
,
201 .config_props
= config_props
, },