Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2018-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / ffmpeg video rescaler filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/setup.h>
27 :
28 : #ifdef GPAC_HAS_FFMPEG
29 :
30 : #include "ff_common.h"
31 :
32 : typedef struct
33 : {
34 : //options
35 : GF_PropVec2i osize;
36 : u32 ofmt, scale;
37 : Double p1, p2;
38 : Bool ofr;
39 : u32 brightness, saturation, contrast;
40 : GF_PropIntList otable, itable;
41 : //internal data
42 : Bool initialized;
43 :
44 : GF_FilterPid *ipid, *opid;
45 : u32 w, h, stride, s_pfmt;
46 : GF_Fraction ar;
47 : Bool passthrough;
48 :
49 : struct SwsContext *swscaler;
50 :
51 : u32 dst_stride[5];
52 : u32 src_stride[5];
53 : u32 nb_planes, nb_src_planes, out_size, out_src_size, src_uv_height, dst_uv_height, ow, oh;
54 :
55 : u32 swap_idx_1, swap_idx_2;
56 : Bool fullrange;
57 : } GF_FFSWScaleCtx;
58 :
59 2976 : static GF_Err ffsws_process(GF_Filter *filter)
60 : {
61 : const char *data;
62 : u8 *output;
63 : u32 osize;
64 : s32 res;
65 : u8 *src_planes[5];
66 : u8 *dst_planes[5];
67 : GF_FilterPacket *dst_pck;
68 : GF_FilterFrameInterface *frame_ifce;
69 2976 : GF_FFSWScaleCtx *ctx = gf_filter_get_udta(filter);
70 : GF_FilterPacket *pck;
71 :
72 2976 : pck = gf_filter_pid_get_packet(ctx->ipid);
73 :
74 2976 : if (!pck) {
75 70 : if (gf_filter_pid_is_eos(ctx->ipid)) {
76 62 : gf_filter_pid_set_eos(ctx->opid);
77 62 : return GF_EOS;
78 : }
79 : return GF_OK;
80 : }
81 :
82 2906 : if (ctx->passthrough) {
83 173 : gf_filter_pck_forward(pck, ctx->opid);
84 173 : gf_filter_pid_drop_packet(ctx->ipid);
85 173 : return GF_OK;
86 : }
87 : //not yet configured
88 2733 : if (!ctx->ofmt && !ctx->ow && !ctx->oh)
89 : return GF_OK;
90 :
91 2733 : if (!ctx->swscaler) {
92 0 : gf_filter_pid_drop_packet(ctx->ipid);
93 0 : return GF_NOT_SUPPORTED;
94 : }
95 :
96 2733 : data = gf_filter_pck_get_data(pck, &osize);
97 2733 : frame_ifce = gf_filter_pck_get_frame_interface(pck);
98 : //we may have biffer input (padding) but shall not have smaller
99 2733 : if (osize && (ctx->out_src_size > osize) ) {
100 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[FFSWS] Mismatched in source osize, expected %d got %d - stride issue ?\n", ctx->out_src_size, osize));
101 0 : gf_filter_pid_drop_packet(ctx->ipid);
102 0 : return GF_NOT_SUPPORTED;
103 : }
104 :
105 : memset(src_planes, 0, sizeof(src_planes));
106 : memset(dst_planes, 0, sizeof(dst_planes));
107 2733 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, ctx->out_size, &output);
108 2733 : if (!dst_pck) return GF_OUT_OF_MEM;
109 :
110 2733 : gf_filter_pck_merge_properties(pck, dst_pck);
111 :
112 2733 : if (data) {
113 2731 : src_planes[0] = (u8 *) data;
114 :
115 2731 : if (ctx->nb_src_planes==1) {
116 2719 : } else if (ctx->nb_src_planes==2) {
117 0 : src_planes[1] = src_planes[0] + ctx->src_stride[0]*ctx->h;
118 2719 : } else if (ctx->nb_src_planes==3) {
119 2719 : src_planes[1] = src_planes[0] + ctx->src_stride[0] * ctx->h;
120 2719 : src_planes[2] = src_planes[1] + ctx->src_stride[1] * ctx->src_uv_height;
121 0 : } else if (ctx->nb_src_planes==4) {
122 0 : src_planes[1] = src_planes[0] + ctx->src_stride[0] * ctx->h;
123 0 : src_planes[2] = src_planes[1] + ctx->src_stride[1] * ctx->src_uv_height;
124 0 : src_planes[3] = src_planes[2] + ctx->src_stride[2] * ctx->src_uv_height;
125 : }
126 2 : } else if (frame_ifce && frame_ifce->get_plane) {
127 : u32 i=0;
128 2 : for (i=0; i<ctx->nb_src_planes; i++) {
129 2 : if (frame_ifce->get_plane(frame_ifce, i, (const u8 **) &src_planes[i], &ctx->src_stride[i])!=GF_OK)
130 : break;
131 : }
132 : } else {
133 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[FFSWS] No data associated with packet, not supported\n"));
134 0 : gf_filter_pid_drop_packet(ctx->ipid);
135 0 : return GF_NOT_SUPPORTED;
136 : }
137 2733 : dst_planes[0] = output;
138 2733 : if (ctx->nb_planes==1) {
139 1632 : } else if (ctx->nb_planes==2) {
140 108 : dst_planes[1] = output + ctx->dst_stride[0] * ctx->oh;
141 1524 : } else if (ctx->nb_planes==3) {
142 1524 : dst_planes[1] = output + ctx->dst_stride[0] * ctx->oh;
143 1524 : dst_planes[2] = dst_planes[1] + ctx->dst_stride[1]*ctx->dst_uv_height;
144 0 : } else if (ctx->nb_planes==4) {
145 0 : dst_planes[1] = output + ctx->dst_stride[0] * ctx->oh;
146 0 : dst_planes[2] = dst_planes[1] + ctx->dst_stride[1]*ctx->dst_uv_height;
147 0 : dst_planes[3] = dst_planes[2] + ctx->dst_stride[2]*ctx->dst_uv_height;
148 : }
149 :
150 : //rescale the cropped frame
151 2733 : res = sws_scale(ctx->swscaler, (const u8**) src_planes, ctx->src_stride, 0, ctx->h, dst_planes, ctx->dst_stride);
152 2733 : if (res != ctx->oh) {
153 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[FFSWS] Error during scale, expected height %d got %d\n", ctx->oh, res));
154 0 : gf_filter_pid_drop_packet(ctx->ipid);
155 0 : gf_filter_pck_discard(dst_pck);
156 0 : return GF_NOT_SUPPORTED;
157 : }
158 :
159 2733 : if (ctx->swap_idx_1 || ctx->swap_idx_2) {
160 : u32 i, j;
161 13824 : for (i=0; i<ctx->h; i++) {
162 13824 : u8 *dst = output + ctx->dst_stride[0]*i;
163 898560 : for (j=0; j<ctx->dst_stride[0]; j+=4) {
164 884736 : u8 tmp = dst[ctx->swap_idx_1];
165 884736 : dst[ctx->swap_idx_1] = dst[ctx->swap_idx_2];
166 884736 : dst[ctx->swap_idx_2] = tmp;
167 884736 : dst += 4;
168 : }
169 : }
170 : }
171 :
172 2733 : gf_filter_pck_send(dst_pck);
173 2733 : gf_filter_pid_drop_packet(ctx->ipid);
174 2733 : return GF_OK;
175 : }
176 :
177 115 : static u32 get_sws_mode(u32 mode, u32 *has_param)
178 : {
179 115 : switch (mode) {
180 : case 0: return SWS_FAST_BILINEAR;
181 0 : case 1: return SWS_BILINEAR;
182 115 : case 2: *has_param = 2; return SWS_BICUBIC;
183 0 : case 3: return SWS_X;
184 0 : case 4: return SWS_POINT;
185 0 : case 5: return SWS_AREA;
186 0 : case 6: return SWS_BICUBLIN;
187 0 : case 7: *has_param = 1; return SWS_GAUSS;
188 0 : case 8: return SWS_SINC;
189 0 : case 9: *has_param = 1; return SWS_LANCZOS;
190 0 : case 10: return SWS_SPLINE;
191 : default: break;
192 : }
193 0 : *has_param = 2;
194 0 : return SWS_BICUBIC;
195 : }
196 :
197 177 : static GF_Err ffsws_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
198 : {
199 : const GF_PropertyValue *p;
200 : u32 w, h, stride, ofmt;
201 : GF_Fraction sar;
202 : Bool fullrange=GF_FALSE;
203 : Double par[2], *par_p=NULL;
204 177 : GF_FFSWScaleCtx *ctx = gf_filter_get_udta(filter);
205 :
206 177 : if (is_remove) {
207 0 : if (ctx->opid) {
208 0 : gf_filter_pid_remove(ctx->opid);
209 0 : ctx->opid = NULL;
210 : }
211 : return GF_OK;
212 : }
213 177 : if (! gf_filter_pid_check_caps(pid))
214 : return GF_NOT_SUPPORTED;
215 :
216 176 : if (!ctx->opid) {
217 62 : ctx->opid = gf_filter_pid_new(filter);
218 : }
219 :
220 176 : if (!ctx->ipid) {
221 62 : ctx->ipid = pid;
222 : }
223 :
224 : //if nothing is set we, consider we run as an adaptation filter, wait for caps to be set to declare output
225 176 : if (!ctx->ofmt && !ctx->osize.x && !ctx->osize.y)
226 : return GF_OK;
227 :
228 :
229 :
230 : w = h = ofmt = stride = 0;
231 124 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_WIDTH);
232 124 : if (p) w = p->value.uint;
233 124 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_HEIGHT);
234 124 : if (p) h = p->value.uint;
235 124 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_STRIDE);
236 124 : if (p) stride = p->value.uint;
237 124 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_PIXFMT);
238 124 : if (p) ofmt = p->value.uint;
239 124 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_SAR);
240 124 : if (p) sar = p->value.frac;
241 : else sar.den = sar.num = 1;
242 :
243 124 : p = gf_filter_pid_get_property(pid, GF_PROP_PID_COLR_RANGE);
244 124 : if (p) fullrange = p->value.boolean;
245 :
246 : //ctx->ofmt may be 0 if the filter is instantiated dynamically, we haven't yet been called for reconfigure
247 124 : if (!w || !h || !ofmt) {
248 : return GF_OK;
249 : }
250 : //copy properties at init or reconfig
251 116 : gf_filter_pid_copy_properties(ctx->opid, ctx->ipid);
252 :
253 116 : if (!ctx->ofmt)
254 9 : ctx->ofmt = ofmt;
255 :
256 116 : ctx->passthrough = GF_FALSE;
257 :
258 116 : ctx->ow = ctx->osize.x ? ctx->osize.x : w;
259 116 : ctx->oh = ctx->osize.y ? ctx->osize.y : h;
260 116 : if ((ctx->w == w) && (ctx->h == h) && (ctx->s_pfmt == ofmt) && (ctx->stride == stride) && (ctx->fullrange==fullrange)) {
261 : //nothing to reconfigure
262 : }
263 : //passthrough mode
264 116 : else if ((ctx->ow == w) && (ctx->oh == h) && (ctx->s_pfmt == ofmt) && (ofmt==ctx->ofmt) && (ctx->ofr == fullrange)
265 1 : && !ctx->brightness && !ctx->saturation && !ctx->contrast && (ctx->otable.nb_items!=4) && (ctx->itable.nb_items!=4)
266 : ) {
267 1 : memset(ctx->dst_stride, 0, sizeof(ctx->dst_stride));
268 1 : gf_pixel_get_size_info(ctx->ofmt, ctx->ow, ctx->oh, &ctx->out_size, &ctx->dst_stride[0], &ctx->dst_stride[1], &ctx->nb_planes, &ctx->dst_uv_height);
269 1 : ctx->passthrough = GF_TRUE;
270 : } else {
271 115 : u32 nb_par = 0;
272 : nb_par = 0;
273 : Bool res;
274 115 : u32 mode = get_sws_mode(ctx->scale, &nb_par);
275 115 : u32 ff_src_pfmt = ffmpeg_pixfmt_from_gpac(ofmt);
276 115 : u32 ff_dst_pfmt = ffmpeg_pixfmt_from_gpac(ctx->ofmt);
277 :
278 : //get layout info for source
279 115 : memset(ctx->src_stride, 0, sizeof(ctx->src_stride));
280 115 : if (ctx->stride) ctx->src_stride[0] = ctx->stride;
281 :
282 :
283 115 : res = gf_pixel_get_size_info(ofmt, w, h, &ctx->out_src_size, &ctx->src_stride[0], &ctx->src_stride[1], &ctx->nb_src_planes, &ctx->src_uv_height);
284 115 : if (!res) {
285 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[FFSWS] Failed to query source pixel format characteristics\n"));
286 0 : return GF_NOT_SUPPORTED;
287 : }
288 115 : if (ctx->nb_src_planes==3) ctx->src_stride[2] = ctx->src_stride[1];
289 115 : if (ctx->nb_src_planes==4) ctx->src_stride[3] = ctx->src_stride[0];
290 :
291 : //get layout info for dest
292 115 : memset(ctx->dst_stride, 0, sizeof(ctx->dst_stride));
293 115 : res = gf_pixel_get_size_info(ctx->ofmt, ctx->ow, ctx->oh, &ctx->out_size, &ctx->dst_stride[0], &ctx->dst_stride[1], &ctx->nb_planes, &ctx->dst_uv_height);
294 115 : if (!res) {
295 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[FFSWS] Failed to query output pixel format characteristics\n"));
296 : return GF_NOT_SUPPORTED;
297 : }
298 115 : if (ctx->nb_planes==3) ctx->dst_stride[2] = ctx->dst_stride[1];
299 115 : if (ctx->nb_planes==4) ctx->dst_stride[3] = ctx->dst_stride[0];
300 :
301 :
302 115 : if (nb_par) {
303 115 : if ((nb_par==1) && (ctx->p1!=GF_MAX_DOUBLE) ) {
304 0 : par[0] = ctx->p1;
305 0 : par_p = (Double *)par;
306 115 : } else if ((nb_par==2) && (ctx->p1!=GF_MAX_DOUBLE) && (ctx->p2!=GF_MAX_DOUBLE)) {
307 0 : par[0] = ctx->p1;
308 0 : par[1] = ctx->p2;
309 : par_p = (Double *)par;
310 : }
311 : }
312 : //create/get a swscale context
313 115 : ctx->swscaler = sws_getCachedContext(ctx->swscaler, w, h, ff_src_pfmt, ctx->ow, ctx->oh, ff_dst_pfmt, mode, NULL, NULL, par_p);
314 :
315 115 : if (!ctx->swscaler) {
316 : #ifndef GPAC_DISABLE_LOG
317 0 : Bool in_ok = sws_isSupportedInput(ff_src_pfmt);
318 0 : Bool out_ok = sws_isSupportedInput(ff_dst_pfmt);
319 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[FFSWS] Cannot allocate context for required format - input %s output %s\n", in_ok ? "OK" : "not supported" , out_ok ? "OK" : "not supported"));
320 : #endif
321 : return GF_NOT_SUPPORTED;
322 : }
323 : //set colorspace
324 115 : if (fullrange || ctx->ofr || ctx->brightness || ctx->saturation || ctx->contrast || (ctx->itable.nb_items==4) || (ctx->otable.nb_items==4)) {
325 : s32 in_full, out_full, brightness, contrast, saturation;
326 : s32 *inv_table, *table;
327 :
328 3 : sws_getColorspaceDetails(ctx->swscaler, &inv_table, &in_full, &table, &out_full, &brightness, &contrast, &saturation);
329 3 : in_full = fullrange;
330 3 : out_full = ctx->ofr;
331 3 : if (ctx->brightness) brightness = ctx->brightness;
332 3 : if (ctx->saturation) saturation = ctx->saturation;
333 3 : if (ctx->contrast) contrast = ctx->contrast;
334 :
335 3 : if (ctx->itable.nb_items==4)
336 0 : inv_table = ctx->itable.vals;
337 3 : if (ctx->otable.nb_items==4)
338 0 : table = ctx->otable.vals;
339 :
340 3 : sws_setColorspaceDetails(ctx->swscaler, (const int *) inv_table, in_full, (const int *)table, out_full, brightness, contrast, saturation);
341 : }
342 115 : ctx->w = w;
343 115 : ctx->h = h;
344 115 : ctx->s_pfmt = ofmt;
345 115 : ctx->fullrange = fullrange;
346 115 : GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[FFSWS] Setup rescaler from %dx%d fmt %s to %dx%d fmt %s\n", w, h, gf_pixel_fmt_name(ofmt), ctx->ow, ctx->oh, gf_pixel_fmt_name(ctx->ofmt)));
347 :
348 115 : ctx->swap_idx_1 = ctx->swap_idx_2 = 0;
349 : //if same source / dest pixel format, don'( swap UV components
350 115 : if (ctx->s_pfmt != ctx->ofmt) {
351 93 : if (ctx->ofmt==GF_PIXEL_VYUY) {
352 : ctx->swap_idx_1 = 0;
353 4 : ctx->swap_idx_2 = 2;
354 : }
355 89 : else if (ctx->ofmt==GF_PIXEL_YVYU) {
356 4 : ctx->swap_idx_1 = 1;
357 4 : ctx->swap_idx_2 = 3;
358 : }
359 : }
360 : }
361 :
362 116 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_WIDTH, &PROP_UINT(ctx->ow));
363 116 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_HEIGHT, &PROP_UINT(ctx->oh));
364 116 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE, &PROP_UINT(ctx->dst_stride[0]));
365 116 : if (ctx->nb_planes>1)
366 57 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STRIDE_UV, &PROP_UINT(ctx->dst_stride[1]));
367 :
368 116 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_CODECID, &PROP_UINT(GF_CODECID_RAW));
369 116 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_PIXFMT, &PROP_UINT(ctx->ofmt));
370 116 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_SAR, &PROP_FRAC(sar) );
371 116 : return GF_OK;
372 : }
373 :
374 62 : static void ffsws_finalize(GF_Filter *filter)
375 : {
376 62 : GF_FFSWScaleCtx *ctx = gf_filter_get_udta(filter);
377 62 : if (ctx->swscaler) sws_freeContext(ctx->swscaler);
378 62 : return;
379 : }
380 :
381 :
382 58 : static GF_Err ffsws_reconfigure_output(GF_Filter *filter, GF_FilterPid *pid)
383 : {
384 : const GF_PropertyValue *p;
385 58 : GF_FFSWScaleCtx *ctx = gf_filter_get_udta(filter);
386 58 : if (ctx->opid != pid) return GF_BAD_PARAM;
387 :
388 58 : p = gf_filter_pid_caps_query(pid, GF_PROP_PID_WIDTH);
389 58 : if (p) ctx->osize.x = p->value.uint;
390 :
391 58 : p = gf_filter_pid_caps_query(pid, GF_PROP_PID_HEIGHT);
392 58 : if (p) ctx->osize.y = p->value.uint;
393 :
394 58 : p = gf_filter_pid_caps_query(pid, GF_PROP_PID_PIXFMT);
395 58 : if (p) ctx->ofmt = p->value.uint;
396 58 : return ffsws_configure_pid(filter, ctx->ipid, GF_FALSE);
397 : }
398 :
399 :
400 : #define OFFS(_n) #_n, offsetof(GF_FFSWScaleCtx, _n)
401 : static GF_FilterArgs FFSWSArgs[] =
402 : {
403 : { OFFS(osize), "osize of output video. When not set, input osize is used", GF_PROP_VEC2I, NULL, NULL, 0},
404 : { OFFS(ofmt), "pixel format for output video. When not set, input format is used", GF_PROP_PIXFMT, "none", NULL, 0},
405 : { OFFS(scale), "scaling mode - see filter info", GF_PROP_UINT, "bicubic", "fastbilinear|bilinear|bicubic|X|point|area|bicublin|gauss|sinc|lanzcos|spline", GF_FS_ARG_HINT_ADVANCED},
406 : { OFFS(p1), "scaling algo param1 - see filter info", GF_PROP_DOUBLE, "+I", NULL, GF_FS_ARG_HINT_ADVANCED},
407 : { OFFS(p2), "scaling algo param2 - see filter info", GF_PROP_DOUBLE, "+I", NULL, GF_FS_ARG_HINT_ADVANCED},
408 :
409 : { OFFS(ofr), "force output full range", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_EXPERT},
410 : { OFFS(brightness), "16.16 fixed point brightness correction, 0 means use default", GF_PROP_BOOL, "0", NULL, GF_FS_ARG_HINT_EXPERT},
411 : { OFFS(contrast), "16.16 fixed point brightness correction, 0 means use default", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_EXPERT},
412 : { OFFS(saturation), "16.16 fixed point brightness correction, 0 means use default", GF_PROP_UINT, "0", NULL, GF_FS_ARG_HINT_EXPERT},
413 : { OFFS(otable), "the yuv2rgb coefficients describing the output yuv space, normally ff_yuv2rgb_coeffs[x], use default if not set", GF_PROP_SINT_LIST, NULL, NULL, GF_FS_ARG_HINT_EXPERT},
414 : { OFFS(itable), "the yuv2rgb coefficients describing the input yuv space, normally ff_yuv2rgb_coeffs[x], use default if not set", GF_PROP_SINT_LIST, NULL, NULL, GF_FS_ARG_HINT_EXPERT},
415 : {0}
416 : };
417 :
418 : static const GF_FilterCapability FFSWSCaps[] =
419 : {
420 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
421 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_RAW)
422 : };
423 :
424 :
425 : GF_FilterRegister FFSWSRegister = {
426 : .name = "ffsws",
427 : .version=LIBSWSCALE_IDENT,
428 : GF_FS_SET_DESCRIPTION("FFMPEG video rescaler")
429 : GF_FS_SET_HELP("For bicubic, to tune the shape of the basis function, [-p1]() tunes f(1) and [-p2]() f´(1)\n"\
430 : "For gauss [-p1]() tunes the exponent and thus cutoff frequency\n"\
431 : "For lanczos [-p1]() tunes the width of the window function"\
432 : "\nSee FFMPEG documentation (https://ffmpeg.org/documentation.html) for more details")
433 :
434 : .private_size = sizeof(GF_FFSWScaleCtx),
435 : .args = FFSWSArgs,
436 : .configure_pid = ffsws_configure_pid,
437 : SETCAPS(FFSWSCaps),
438 : .finalize = ffsws_finalize,
439 : .process = ffsws_process,
440 : .reconfigure_output = ffsws_reconfigure_output,
441 : };
442 :
443 : #else
444 : #include <gpac/filters.h>
445 : #endif //GPAC_HAS_FFMPEG
446 :
447 2877 : const GF_FilterRegister *ffsws_register(GF_FilterSession *session)
448 : {
449 : #ifdef GPAC_HAS_FFMPEG
450 2877 : FFSWSArgs[1].min_max_enum = gf_pixel_fmt_all_names();
451 2877 : return &FFSWSRegister;
452 : #else
453 : return NULL;
454 : #endif
455 : }
456 :
|