Resize filter updates
[x264/x264-sandbox.git] / filters / video / resize.c
1 /*****************************************************************************
2  * resize.c: resize video filter
3  *****************************************************************************
4  * Copyright (C) 2010-2011 x264 project
5  *
6  * Authors: Steven Walters <kemuri9@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
21  *
22  * This program is also available under a commercial proprietary license.
23  * For more information, contact us at licensing@x264.com.
24  *****************************************************************************/
25
26 #include "video.h"
27 #define NAME "resize"
28 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, NAME, __VA_ARGS__ )
29
30 cli_vid_filter_t resize_filter;
31
32 static int full_check( video_info_t *info, x264_param_t *param )
33 {
34     int required = 0;
35     required |= info->csp    != param->i_csp;
36     required |= info->width  != param->i_width;
37     required |= info->height != param->i_height;
38     return required;
39 }
40
41 #if HAVE_SWSCALE
42 #undef DECLARE_ALIGNED
43 #include <libswscale/swscale.h>
44 #include <libavutil/opt.h>
45 #include <libavutil/pixdesc.h>
46
47 typedef struct
48 {
49     int width;
50     int height;
51     int pix_fmt;
52 } frame_prop_t;
53
54 typedef struct
55 {
56     hnd_t prev_hnd;
57     cli_vid_filter_t prev_filter;
58
59     cli_pic_t buffer;
60     int buffer_allocated;
61     int dst_csp;
62     struct SwsContext *ctx;
63     uint32_t ctx_flags;
64     /* state of swapping chroma planes pre and post resize */
65     int pre_swap_chroma;
66     int post_swap_chroma;
67     int variable_input; /* input is capable of changing properties */
68     frame_prop_t dst;   /* desired output properties */
69     frame_prop_t scale; /* properties of the SwsContext input */
70 } resizer_hnd_t;
71
72 static void help( int longhelp )
73 {
74     printf( "      "NAME":[width,height][,sar][,fittobox][,csp][,method]\n" );
75     if( !longhelp )
76         return;
77     printf( "            resizes frames based on the given criteria:\n"
78             "            - resolution only: resizes and adapts sar to avoid stretching\n"
79             "            - sar only: sets the sar and resizes to avoid stretching\n"
80             "            - resolution and sar: resizes to given resolution and sets the sar\n"
81             "            - fittobox: resizes the video based on the desired contraints\n"
82             "               - width, height, both\n"
83             "            - fittobox and sar: same as above except with specified sar\n"
84             "            - csp: convert to the given csp. syntax: [name][:depth]\n"
85             "               - valid csp names [keep current]: " );
86
87     for( int i = X264_CSP_NONE+1; i < X264_CSP_CLI_MAX; i++ )
88     {
89         printf( "%s", x264_cli_csps[i].name );
90         if( i+1 < X264_CSP_CLI_MAX )
91             printf( ", " );
92     }
93     printf( "\n"
94             "               - depth: 8 or 16 bits per pixel [keep current]\n"
95             "            note: not all depths are supported by all csps.\n"
96             "            - method: use resizer method [\"bicubic\"]\n"
97             "               - fastbilinear, bilinear, bicubic, experimental, point,\n"
98             "               - area, bicublin, gauss, sinc, lanczos, spline\n" );
99 }
100
101 static uint32_t convert_method_to_flag( const char *name )
102 {
103     uint32_t flag = 0;
104     if( !strcasecmp( name, "fastbilinear" ) )
105         flag = SWS_FAST_BILINEAR;
106     else if( !strcasecmp( name, "bilinear" ) )
107         flag = SWS_BILINEAR;
108     else if( !strcasecmp( name, "bicubic" ) )
109         flag = SWS_BICUBIC;
110     else if( !strcasecmp( name, "experimental" ) )
111         flag = SWS_X;
112     else if( !strcasecmp( name, "point" ) )
113         flag = SWS_POINT;
114     else if( !strcasecmp( name, "area" ) )
115         flag = SWS_AREA;
116     else if( !strcasecmp( name, "bicublin" ) )
117         flag = SWS_BICUBLIN;
118     else if( !strcasecmp( name, "guass" ) )
119         flag = SWS_GAUSS;
120     else if( !strcasecmp( name, "sinc" ) )
121         flag = SWS_SINC;
122     else if( !strcasecmp( name, "lanczos" ) )
123         flag = SWS_LANCZOS;
124     else if( !strcasecmp( name, "spline" ) )
125         flag = SWS_SPLINE;
126     else // default
127         flag = SWS_BICUBIC;
128     return flag;
129 }
130
131 static int convert_csp_to_pix_fmt( int csp )
132 {
133     if( csp&X264_CSP_OTHER )
134         return csp&X264_CSP_MASK;
135     switch( csp&X264_CSP_MASK )
136     {
137         case X264_CSP_YV12: /* specially handled via swapping chroma */
138         case X264_CSP_I420: return csp&X264_CSP_HIGH_DEPTH ? PIX_FMT_YUV420P16 : PIX_FMT_YUV420P;
139         case X264_CSP_I422: return csp&X264_CSP_HIGH_DEPTH ? PIX_FMT_YUV422P16 : PIX_FMT_YUV422P;
140         case X264_CSP_I444: return csp&X264_CSP_HIGH_DEPTH ? PIX_FMT_YUV444P16 : PIX_FMT_YUV444P;
141         case X264_CSP_RGB:  return csp&X264_CSP_HIGH_DEPTH ? PIX_FMT_RGB48     : PIX_FMT_RGB24;
142         /* the next 3 csps have no equivalent 16bit depth in swscale */
143         case X264_CSP_NV12: return csp&X264_CSP_HIGH_DEPTH ? PIX_FMT_NONE      : PIX_FMT_NV12;
144         case X264_CSP_BGR:  return csp&X264_CSP_HIGH_DEPTH ? PIX_FMT_NONE      : PIX_FMT_BGR24;
145         case X264_CSP_BGRA: return csp&X264_CSP_HIGH_DEPTH ? PIX_FMT_NONE      : PIX_FMT_BGRA;
146         default:            return PIX_FMT_NONE;
147     }
148 }
149
150 static int pick_closest_supported_csp( int csp )
151 {
152     int pix_fmt = convert_csp_to_pix_fmt( csp );
153     switch( pix_fmt )
154     {
155         case PIX_FMT_YUV420P16LE:
156         case PIX_FMT_YUV420P16BE:
157             return X264_CSP_I420 | X264_CSP_HIGH_DEPTH;
158         case PIX_FMT_YUV422P:
159         case PIX_FMT_YUYV422:
160         case PIX_FMT_UYVY422:
161             return X264_CSP_I422;
162         case PIX_FMT_YUV422P16LE:
163         case PIX_FMT_YUV422P16BE:
164             return X264_CSP_I422 | X264_CSP_HIGH_DEPTH;
165         case PIX_FMT_YUV444P:
166             return X264_CSP_I444;
167         case PIX_FMT_YUV444P16LE:
168         case PIX_FMT_YUV444P16BE:
169             return X264_CSP_I444 | X264_CSP_HIGH_DEPTH;
170         case PIX_FMT_RGB24:
171         case PIX_FMT_RGB565BE:
172         case PIX_FMT_RGB565LE:
173         case PIX_FMT_RGB555BE:
174         case PIX_FMT_RGB555LE:
175             return X264_CSP_RGB;
176         case PIX_FMT_RGB48BE:
177         case PIX_FMT_RGB48LE:
178             return X264_CSP_RGB | X264_CSP_HIGH_DEPTH;
179         case PIX_FMT_BGR24:
180         case PIX_FMT_BGR565BE:
181         case PIX_FMT_BGR565LE:
182         case PIX_FMT_BGR555BE:
183         case PIX_FMT_BGR555LE:
184             return X264_CSP_BGR;
185         case PIX_FMT_ARGB:
186         case PIX_FMT_RGBA:
187         case PIX_FMT_ABGR:
188         case PIX_FMT_BGRA:
189             return X264_CSP_BGRA;
190         case PIX_FMT_NV12:
191         case PIX_FMT_NV21:
192              return X264_CSP_NV12;
193         default:
194             return X264_CSP_I420;
195     }
196 }
197
198 static int handle_opts( const char **optlist, char **opts, video_info_t *info, resizer_hnd_t *h )
199 {
200     uint32_t out_sar_w, out_sar_h;
201
202     char *str_width  = x264_get_option( optlist[0], opts );
203     char *str_height = x264_get_option( optlist[1], opts );
204     char *str_sar    = x264_get_option( optlist[2], opts );
205     char *fittobox   = x264_get_option( optlist[3], opts );
206     char *str_csp    = x264_get_option( optlist[4], opts );
207     int width        = x264_otoi( str_width, -1 );
208     int height       = x264_otoi( str_height, -1 );
209
210     int csp_only = 0;
211     uint32_t in_sar_w = info->sar_width;
212     uint32_t in_sar_h = info->sar_height;
213
214     if( str_csp )
215     {
216         /* output csp was specified, first check if optional depth was provided */
217         char *str_depth = strchr( str_csp, ':' );
218         int depth = x264_cli_csp_depth_factor( info->csp ) * 8;
219         if( str_depth )
220         {
221             /* csp bit depth was specified */
222             *str_depth++ = '\0';
223             depth = x264_otoi( str_depth, -1 );
224             FAIL_IF_ERROR( depth != 8 && depth != 16, "unsupported bit depth %d\n", depth );
225         }
226         /* now lookup against the list of valid csps */
227         int csp;
228         if( strlen( str_csp ) == 0 )
229             csp = info->csp & X264_CSP_MASK;
230         else
231             for( csp = X264_CSP_CLI_MAX-1; x264_cli_csps[csp].name && strcasecmp( x264_cli_csps[csp].name, str_csp ); )
232                 csp--;
233         FAIL_IF_ERROR( csp == X264_CSP_NONE, "unsupported colorspace `%s'\n", str_csp );
234         h->dst_csp = csp;
235         if( depth == 16 )
236             h->dst_csp |= X264_CSP_HIGH_DEPTH;
237     }
238
239     /* if the input sar is currently invalid, set it to 1:1 so it can be used in math */
240     if( !in_sar_w || !in_sar_h )
241         in_sar_w = in_sar_h = 1;
242     if( str_sar )
243     {
244         FAIL_IF_ERROR( 2 != sscanf( str_sar, "%u:%u", &out_sar_w, &out_sar_h ) &&
245                        2 != sscanf( str_sar, "%u/%u", &out_sar_w, &out_sar_h ),
246                        "invalid sar `%s'\n", str_sar )
247     }
248     else
249         out_sar_w = out_sar_h = 1;
250     if( fittobox )
251     {
252         /* resize the video to fit the box as much as possible */
253         if( !strcasecmp( fittobox, "both" ) )
254         {
255             FAIL_IF_ERROR( width <= 0 || height <= 0, "invalid box resolution %sx%s\n",
256                            x264_otos( str_width, "<unset>" ), x264_otos( str_height, "<unset>" ) )
257         }
258         else if( !strcasecmp( fittobox, "width" ) )
259         {
260             FAIL_IF_ERROR( width <= 0, "invalid box width `%s'\n", x264_otos( str_width, "<unset>" ) )
261             height = INT_MAX;
262         }
263         else if( !strcasecmp( fittobox, "height" ) )
264         {
265             FAIL_IF_ERROR( height <= 0, "invalid box height `%s'\n", x264_otos( str_height, "<unset>" ) )
266             width = INT_MAX;
267         }
268         else FAIL_IF_ERROR( 1, "invalid fittobox mode `%s'\n", fittobox )
269
270         /* maximally fit the new coded resolution to the box */
271         const x264_cli_csp_t *csp = x264_cli_get_csp( h->dst_csp );
272         double width_units = (double)info->height * in_sar_h * out_sar_w;
273         double height_units = (double)info->width * in_sar_w * out_sar_h;
274         width = width / csp->mod_width * csp->mod_width;
275         height = height / csp->mod_height * csp->mod_height;
276         if( width * width_units > height * height_units )
277         {
278             int new_width = round( height * height_units / (width_units * csp->mod_width) );
279             new_width *= csp->mod_width;
280             width = X264_MIN( new_width, width );
281         }
282         else
283         {
284             int new_height = round( width * width_units / (height_units * csp->mod_height) );
285             new_height *= csp->mod_height;
286             height = X264_MIN( new_height, height );
287         }
288     }
289     else
290     {
291         if( str_width || str_height )
292         {
293             FAIL_IF_ERROR( width <= 0 || height <= 0, "invalid resolution %sx%s\n",
294                            x264_otos( str_width, "<unset>" ), x264_otos( str_height, "<unset>" ) )
295             if( !str_sar ) /* res only -> adjust sar */
296             {
297                 /* new_sar = (new_h * old_w * old_sar_w) / (old_h * new_w * old_sar_h) */
298                 uint64_t num = (uint64_t)info->width  * height;
299                 uint64_t den = (uint64_t)info->height * width;
300                 x264_reduce_fraction64( &num, &den );
301                 out_sar_w = num * in_sar_w;
302                 out_sar_h = den * in_sar_h;
303                 x264_reduce_fraction( &out_sar_w, &out_sar_h );
304             }
305         }
306         else if( str_sar ) /* sar only -> adjust res */
307         {
308              const x264_cli_csp_t *csp = x264_cli_get_csp( h->dst_csp );
309              double width_units = (double)in_sar_h * out_sar_w;
310              double height_units = (double)in_sar_w * out_sar_h;
311              width  = info->width;
312              height = info->height;
313              if( width_units > height_units ) // SAR got wider, decrease width
314              {
315                  width = round( info->width * height_units / (width_units * csp->mod_width) );
316                  width *= csp->mod_width;
317              }
318              else // SAR got thinner, decrease height
319              {
320                  height = round( info->height * width_units / (height_units * csp->mod_height) );
321                  height *= csp->mod_height;
322              }
323         }
324         else /* csp only */
325         {
326             h->dst.width  = info->width;
327             h->dst.height = info->height;
328             csp_only = 1;
329         }
330     }
331     if( !csp_only )
332     {
333         info->sar_width  = out_sar_w;
334         info->sar_height = out_sar_h;
335         h->dst.width  = width;
336         h->dst.height = height;
337     }
338     return 0;
339 }
340
341 static int x264_init_sws_context( resizer_hnd_t *h )
342 {
343     if( !h->ctx )
344     {
345         h->ctx = sws_alloc_context();
346         if( !h->ctx )
347             return -1;
348
349         /* set flags that will not change */
350         av_set_int( h->ctx, "sws_flags",  h->ctx_flags );
351         av_set_int( h->ctx, "dstw",       h->dst.width );
352         av_set_int( h->ctx, "dsth",       h->dst.height );
353         av_set_int( h->ctx, "dst_format", h->dst.pix_fmt );
354         av_set_int( h->ctx, "dst_range",  0 ); /* FIXME: use the correct full range value */
355     }
356
357     av_set_int( h->ctx, "srcw",       h->scale.width );
358     av_set_int( h->ctx, "srch",       h->scale.height );
359     av_set_int( h->ctx, "src_format", h->scale.pix_fmt );
360     av_set_int( h->ctx, "src_range",  0 ); /* FIXME: use the correct full range value */
361
362     /* FIXME: use the correct full range values
363      * FIXME: use the correct matrix coefficients (only YUV -> RGB conversions are supported) */
364     sws_setColorspaceDetails( h->ctx, sws_getCoefficients( SWS_CS_DEFAULT ), 0,
365                               sws_getCoefficients( SWS_CS_DEFAULT ), 0, 0, 1<<16, 1<<16 );
366
367     return sws_init_context( h->ctx, NULL, NULL ) < 0;
368 }
369
370 static int check_resizer( resizer_hnd_t *h, cli_pic_t *in, int frame )
371 {
372     frame_prop_t input_prop = { in->img.width, in->img.height, convert_csp_to_pix_fmt( in->img.csp ) };
373     if( !memcmp( &input_prop, &h->scale, sizeof(frame_prop_t) ) )
374         return 0;
375     /* also warn if the resizer was initialized after the first frame */
376     if( h->ctx || frame )
377         x264_cli_log( NAME, X264_LOG_WARNING, "stream properties changed at pts %"PRId64"\n", in->pts );
378     h->scale = input_prop;
379     if( !h->buffer_allocated )
380     {
381         if( x264_cli_pic_alloc( &h->buffer, h->dst_csp, h->dst.width, h->dst.height ) )
382             return -1;
383         h->buffer_allocated = 1;
384     }
385     FAIL_IF_ERROR( x264_init_sws_context( h ), "swscale init failed\n" )
386     return 0;
387 }
388
389 static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )
390 {
391     /* if called for normalizing the csp to known formats and the format is not unknown, exit */
392     if( opt_string && !strcmp( opt_string, "normcsp" ) && !(info->csp&X264_CSP_OTHER) )
393         return 0;
394     /* if called by x264cli and nothing needs to be done, exit */
395     if( !opt_string && !full_check( info, param ) )
396         return 0;
397
398     static const char *optlist[] = { "width", "height", "sar", "fittobox", "csp", "method", NULL };
399     char **opts = x264_split_options( opt_string, optlist );
400     if( !opts && opt_string )
401         return -1;
402
403     resizer_hnd_t *h = calloc( 1, sizeof(resizer_hnd_t) );
404     if( !h )
405         return -1;
406     if( opts )
407     {
408         h->dst_csp    = info->csp;
409         h->dst.width  = info->width;
410         h->dst.height = info->height;
411         if( !strcmp( opt_string, "normcsp" ) )
412         {
413             /* only in normalization scenarios is the input capable of changing properties */
414             h->variable_input = 1;
415             h->dst_csp = pick_closest_supported_csp( info->csp );
416             /* now fix the catch-all i420 choice if it does not allow for the current input resolution dimensions. */
417             if( h->dst_csp == X264_CSP_I420 && info->width&1 )
418                 h->dst_csp = X264_CSP_I444;
419             if( h->dst_csp == X264_CSP_I420 && info->height&1 )
420                 h->dst_csp = X264_CSP_I422;
421         }
422         else if( handle_opts( optlist, opts, info, h ) )
423             return -1;
424     }
425     else
426     {
427         h->dst_csp    = param->i_csp;
428         h->dst.width  = param->i_width;
429         h->dst.height = param->i_height;
430     }
431     h->ctx_flags = convert_method_to_flag( x264_otos( x264_get_option( optlist[5], opts ), "" ) );
432     x264_free_string_array( opts );
433
434     if( h->ctx_flags != SWS_FAST_BILINEAR )
435         h->ctx_flags |= SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | SWS_ACCURATE_RND;
436     h->dst.pix_fmt = convert_csp_to_pix_fmt( h->dst_csp );
437     h->scale = h->dst;
438
439     /* swap chroma planes if YV12 is involved, as libswscale works with I420 */
440     h->pre_swap_chroma = (info->csp & X264_CSP_MASK) == X264_CSP_YV12;
441     h->post_swap_chroma = (h->dst_csp & X264_CSP_MASK) == X264_CSP_YV12;
442
443     int src_pix_fmt = convert_csp_to_pix_fmt( info->csp );
444
445     int src_pix_fmt_inv = convert_csp_to_pix_fmt( info->csp ^ X264_CSP_HIGH_DEPTH );
446     int dst_pix_fmt_inv = convert_csp_to_pix_fmt( h->dst_csp ^ X264_CSP_HIGH_DEPTH );
447
448     /* confirm swscale can support this conversion */
449     FAIL_IF_ERROR( src_pix_fmt == PIX_FMT_NONE && src_pix_fmt_inv != PIX_FMT_NONE,
450                    "input colorspace %s with bit depth %d is not supported\n", av_get_pix_fmt_name( src_pix_fmt_inv ),
451                    info->csp & X264_CSP_HIGH_DEPTH ? 16 : 8 );
452     FAIL_IF_ERROR( !sws_isSupportedInput( src_pix_fmt ), "input colorspace %s is not supported\n", av_get_pix_fmt_name( src_pix_fmt ) )
453     FAIL_IF_ERROR( h->dst.pix_fmt == PIX_FMT_NONE && dst_pix_fmt_inv != PIX_FMT_NONE,
454                    "input colorspace %s with bit depth %d is not supported\n", av_get_pix_fmt_name( dst_pix_fmt_inv ),
455                    h->dst_csp & X264_CSP_HIGH_DEPTH ? 16 : 8 );
456     FAIL_IF_ERROR( !sws_isSupportedOutput( h->dst.pix_fmt ), "output colorspace %s is not supported\n", av_get_pix_fmt_name( h->dst.pix_fmt ) )
457     FAIL_IF_ERROR( h->dst.height != info->height && info->interlaced,
458                    "swscale is not compatible with interlaced vertical resizing\n" )
459     /* confirm that the desired resolution meets the colorspace requirements */
460     const x264_cli_csp_t *csp = x264_cli_get_csp( h->dst_csp );
461     FAIL_IF_ERROR( h->dst.width % csp->mod_width || h->dst.height % csp->mod_height,
462                    "resolution %dx%d is not compliant with colorspace %s\n", h->dst.width, h->dst.height, csp->name )
463
464     if( h->dst.width != info->width || h->dst.height != info->height )
465         x264_cli_log( NAME, X264_LOG_INFO, "resizing to %dx%d\n", h->dst.width, h->dst.height );
466     if( h->dst.pix_fmt != src_pix_fmt )
467         x264_cli_log( NAME, X264_LOG_WARNING, "converting from %s to %s\n",
468                       av_get_pix_fmt_name( src_pix_fmt ), av_get_pix_fmt_name( h->dst.pix_fmt ) );
469     h->dst_csp |= info->csp & X264_CSP_VFLIP; // preserve vflip
470
471     /* if the input is not variable, initialize the context */
472     if( !h->variable_input )
473     {
474         cli_pic_t input_pic = {{info->csp, info->width, info->height, 0}, 0};
475         if( check_resizer( h, &input_pic, 0 ) )
476             return -1;
477     }
478
479     /* finished initing, overwrite values */
480     info->csp    = h->dst_csp;
481     info->width  = h->dst.width;
482     info->height = h->dst.height;
483
484     h->prev_filter = *filter;
485     h->prev_hnd = *handle;
486     *handle = h;
487     *filter = resize_filter;
488
489     return 0;
490 }
491
492 static int get_frame( hnd_t handle, cli_pic_t *output, int frame )
493 {
494     resizer_hnd_t *h = handle;
495     if( h->prev_filter.get_frame( h->prev_hnd, output, frame ) )
496         return -1;
497     if( h->variable_input && check_resizer( h, output, frame ) )
498         return -1;
499     if( h->pre_swap_chroma )
500         XCHG( uint8_t*, output->img.plane[1], output->img.plane[2] );
501     if( h->ctx )
502     {
503         sws_scale( h->ctx, (const uint8_t* const*)output->img.plane, output->img.stride,
504                    0, output->img.height, h->buffer.img.plane, h->buffer.img.stride );
505         output->img = h->buffer.img; /* copy img data */
506     }
507     else
508         output->img.csp = h->dst_csp;
509     if( h->post_swap_chroma )
510         XCHG( uint8_t*, output->img.plane[1], output->img.plane[2] );
511
512     return 0;
513 }
514
515 static int release_frame( hnd_t handle, cli_pic_t *pic, int frame )
516 {
517     resizer_hnd_t *h = handle;
518     return h->prev_filter.release_frame( h->prev_hnd, pic, frame );
519 }
520
521 static void free_filter( hnd_t handle )
522 {
523     resizer_hnd_t *h = handle;
524     h->prev_filter.free( h->prev_hnd );
525     if( h->ctx )
526         sws_freeContext( h->ctx );
527     if( h->buffer_allocated )
528         x264_cli_pic_clean( &h->buffer );
529     free( h );
530 }
531
532 #else /* no swscale */
533 static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )
534 {
535     int ret = 0;
536
537     if( !opt_string )
538         ret = full_check( info, param );
539     else
540     {
541         if( !strcmp( opt_string, "normcsp" ) )
542             ret = info->csp & X264_CSP_OTHER;
543         else
544             ret = -1;
545     }
546
547     /* pass if nothing needs to be done, otherwise fail */
548     FAIL_IF_ERROR( ret, "not compiled with swscale support\n" )
549     return 0;
550 }
551
552 #define help NULL
553 #define get_frame NULL
554 #define release_frame NULL
555 #define free_filter NULL
556 #define convert_csp_to_pix_fmt(x) (x & X264_CSP_MASK)
557
558 #endif
559
560 cli_vid_filter_t resize_filter = { NAME, help, init, get_frame, release_frame, free_filter, NULL };