Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52867 views
1
/*****************************************************************************
2
* resize.c: resize video filter
3
*****************************************************************************
4
* Copyright (C) 2010-2016 x264 project
5
*
6
* Authors: Steven Walters <[email protected]>
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 [email protected].
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
required |= info->fullrange != param->vui.b_fullrange;
39
return required;
40
}
41
42
#if HAVE_SWSCALE
43
#undef DECLARE_ALIGNED
44
#include <libswscale/swscale.h>
45
#include <libavutil/opt.h>
46
#include <libavutil/pixdesc.h>
47
48
#ifndef AV_PIX_FMT_BGRA64
49
#define AV_PIX_FMT_BGRA64 AV_PIX_FMT_NONE
50
#endif
51
52
typedef struct
53
{
54
int width;
55
int height;
56
int pix_fmt;
57
int range;
58
} frame_prop_t;
59
60
typedef struct
61
{
62
hnd_t prev_hnd;
63
cli_vid_filter_t prev_filter;
64
65
cli_pic_t buffer;
66
int buffer_allocated;
67
int dst_csp;
68
int input_range;
69
struct SwsContext *ctx;
70
uint32_t ctx_flags;
71
/* state of swapping chroma planes pre and post resize */
72
int pre_swap_chroma;
73
int post_swap_chroma;
74
int variable_input; /* input is capable of changing properties */
75
int working; /* we have already started working with frames */
76
frame_prop_t dst; /* desired output properties */
77
frame_prop_t scale; /* properties of the SwsContext input */
78
} resizer_hnd_t;
79
80
static void help( int longhelp )
81
{
82
printf( " "NAME":[width,height][,sar][,fittobox][,csp][,method]\n" );
83
if( !longhelp )
84
return;
85
printf( " resizes frames based on the given criteria:\n"
86
" - resolution only: resizes and adapts sar to avoid stretching\n"
87
" - sar only: sets the sar and resizes to avoid stretching\n"
88
" - resolution and sar: resizes to given resolution and sets the sar\n"
89
" - fittobox: resizes the video based on the desired constraints\n"
90
" - width, height, both\n"
91
" - fittobox and sar: same as above except with specified sar\n"
92
" - csp: convert to the given csp. syntax: [name][:depth]\n"
93
" - valid csp names [keep current]: " );
94
95
for( int i = X264_CSP_NONE+1; i < X264_CSP_CLI_MAX; i++ )
96
{
97
if( x264_cli_csps[i].name )
98
{
99
printf( "%s", x264_cli_csps[i].name );
100
if( i+1 < X264_CSP_CLI_MAX )
101
printf( ", " );
102
}
103
}
104
printf( "\n"
105
" - depth: 8 or 16 bits per pixel [keep current]\n"
106
" note: not all depths are supported by all csps.\n"
107
" - method: use resizer method [\"bicubic\"]\n"
108
" - fastbilinear, bilinear, bicubic, experimental, point,\n"
109
" - area, bicublin, gauss, sinc, lanczos, spline\n" );
110
}
111
112
static uint32_t convert_method_to_flag( const char *name )
113
{
114
uint32_t flag = 0;
115
if( !strcasecmp( name, "fastbilinear" ) )
116
flag = SWS_FAST_BILINEAR;
117
else if( !strcasecmp( name, "bilinear" ) )
118
flag = SWS_BILINEAR;
119
else if( !strcasecmp( name, "bicubic" ) )
120
flag = SWS_BICUBIC;
121
else if( !strcasecmp( name, "experimental" ) )
122
flag = SWS_X;
123
else if( !strcasecmp( name, "point" ) )
124
flag = SWS_POINT;
125
else if( !strcasecmp( name, "area" ) )
126
flag = SWS_AREA;
127
else if( !strcasecmp( name, "bicublin" ) )
128
flag = SWS_BICUBLIN;
129
else if( !strcasecmp( name, "guass" ) )
130
flag = SWS_GAUSS;
131
else if( !strcasecmp( name, "sinc" ) )
132
flag = SWS_SINC;
133
else if( !strcasecmp( name, "lanczos" ) )
134
flag = SWS_LANCZOS;
135
else if( !strcasecmp( name, "spline" ) )
136
flag = SWS_SPLINE;
137
else // default
138
flag = SWS_BICUBIC;
139
return flag;
140
}
141
142
static int convert_csp_to_pix_fmt( int csp )
143
{
144
if( csp&X264_CSP_OTHER )
145
return csp&X264_CSP_MASK;
146
switch( csp&X264_CSP_MASK )
147
{
148
case X264_CSP_YV12: /* specially handled via swapping chroma */
149
case X264_CSP_I420: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_YUV420P16 : AV_PIX_FMT_YUV420P;
150
case X264_CSP_YV16: /* specially handled via swapping chroma */
151
case X264_CSP_I422: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_YUV422P16 : AV_PIX_FMT_YUV422P;
152
case X264_CSP_YV24: /* specially handled via swapping chroma */
153
case X264_CSP_I444: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_YUV444P;
154
case X264_CSP_RGB: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_RGB48 : AV_PIX_FMT_RGB24;
155
case X264_CSP_BGR: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_BGR48 : AV_PIX_FMT_BGR24;
156
case X264_CSP_BGRA: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_BGRA64 : AV_PIX_FMT_BGRA;
157
/* the next csp has no equivalent 16bit depth in swscale */
158
case X264_CSP_NV12: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_NONE : AV_PIX_FMT_NV12;
159
case X264_CSP_NV21: return csp&X264_CSP_HIGH_DEPTH ? AV_PIX_FMT_NONE : AV_PIX_FMT_NV21;
160
/* the next csp is no supported by swscale at all */
161
case X264_CSP_NV16:
162
default: return AV_PIX_FMT_NONE;
163
}
164
}
165
166
static int pix_number_of_planes( const AVPixFmtDescriptor *pix_desc )
167
{
168
int num_planes = 0;
169
for( int i = 0; i < pix_desc->nb_components; i++ )
170
{
171
int plane_plus1 = pix_desc->comp[i].plane + 1;
172
num_planes = X264_MAX( plane_plus1, num_planes );
173
}
174
return num_planes;
175
}
176
177
static int pick_closest_supported_csp( int csp )
178
{
179
int pix_fmt = convert_csp_to_pix_fmt( csp );
180
// first determine the base csp
181
int ret = X264_CSP_NONE;
182
const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get( pix_fmt );
183
if( !pix_desc || !pix_desc->name )
184
return ret;
185
186
const char *pix_fmt_name = pix_desc->name;
187
int is_rgb = pix_desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PAL);
188
int is_bgr = !!strstr( pix_fmt_name, "bgr" );
189
if( is_bgr || is_rgb )
190
{
191
if( pix_desc->nb_components == 4 ) // has alpha
192
ret = X264_CSP_BGRA;
193
else if( is_bgr )
194
ret = X264_CSP_BGR;
195
else
196
ret = X264_CSP_RGB;
197
}
198
else
199
{
200
// yuv-based
201
if( pix_desc->nb_components == 1 || pix_desc->nb_components == 2 ) // no chroma
202
ret = X264_CSP_I420;
203
else if( pix_desc->log2_chroma_w && pix_desc->log2_chroma_h ) // reduced chroma width & height
204
ret = (pix_number_of_planes( pix_desc ) == 2) ? X264_CSP_NV12 : X264_CSP_I420;
205
else if( pix_desc->log2_chroma_w ) // reduced chroma width only
206
ret = X264_CSP_I422; // X264_CSP_NV16 is not supported by swscale so don't use it
207
else
208
ret = X264_CSP_I444;
209
}
210
// now determine high depth
211
for( int i = 0; i < pix_desc->nb_components; i++ )
212
if( pix_desc->comp[i].depth_minus1 >= 8 )
213
ret |= X264_CSP_HIGH_DEPTH;
214
return ret;
215
}
216
217
static int handle_opts( const char **optlist, char **opts, video_info_t *info, resizer_hnd_t *h )
218
{
219
uint32_t out_sar_w, out_sar_h;
220
221
char *str_width = x264_get_option( optlist[0], opts );
222
char *str_height = x264_get_option( optlist[1], opts );
223
char *str_sar = x264_get_option( optlist[2], opts );
224
char *fittobox = x264_get_option( optlist[3], opts );
225
char *str_csp = x264_get_option( optlist[4], opts );
226
int width = x264_otoi( str_width, -1 );
227
int height = x264_otoi( str_height, -1 );
228
229
int csp_only = 0;
230
uint32_t in_sar_w = info->sar_width;
231
uint32_t in_sar_h = info->sar_height;
232
233
if( str_csp )
234
{
235
/* output csp was specified, first check if optional depth was provided */
236
char *str_depth = strchr( str_csp, ':' );
237
int depth = x264_cli_csp_depth_factor( info->csp ) * 8;
238
if( str_depth )
239
{
240
/* csp bit depth was specified */
241
*str_depth++ = '\0';
242
depth = x264_otoi( str_depth, -1 );
243
FAIL_IF_ERROR( depth != 8 && depth != 16, "unsupported bit depth %d\n", depth );
244
}
245
/* now lookup against the list of valid csps */
246
int csp;
247
if( strlen( str_csp ) == 0 )
248
csp = info->csp & X264_CSP_MASK;
249
else
250
for( csp = X264_CSP_CLI_MAX-1; csp > X264_CSP_NONE; csp-- )
251
{
252
if( x264_cli_csps[csp].name && !strcasecmp( x264_cli_csps[csp].name, str_csp ) )
253
break;
254
}
255
FAIL_IF_ERROR( csp == X264_CSP_NONE, "unsupported colorspace `%s'\n", str_csp );
256
h->dst_csp = csp;
257
if( depth == 16 )
258
h->dst_csp |= X264_CSP_HIGH_DEPTH;
259
}
260
261
/* if the input sar is currently invalid, set it to 1:1 so it can be used in math */
262
if( !in_sar_w || !in_sar_h )
263
in_sar_w = in_sar_h = 1;
264
if( str_sar )
265
{
266
FAIL_IF_ERROR( 2 != sscanf( str_sar, "%u:%u", &out_sar_w, &out_sar_h ) &&
267
2 != sscanf( str_sar, "%u/%u", &out_sar_w, &out_sar_h ),
268
"invalid sar `%s'\n", str_sar )
269
}
270
else
271
out_sar_w = out_sar_h = 1;
272
if( fittobox )
273
{
274
/* resize the video to fit the box as much as possible */
275
if( !strcasecmp( fittobox, "both" ) )
276
{
277
FAIL_IF_ERROR( width <= 0 || height <= 0, "invalid box resolution %sx%s\n",
278
x264_otos( str_width, "<unset>" ), x264_otos( str_height, "<unset>" ) )
279
}
280
else if( !strcasecmp( fittobox, "width" ) )
281
{
282
FAIL_IF_ERROR( width <= 0, "invalid box width `%s'\n", x264_otos( str_width, "<unset>" ) )
283
height = INT_MAX;
284
}
285
else if( !strcasecmp( fittobox, "height" ) )
286
{
287
FAIL_IF_ERROR( height <= 0, "invalid box height `%s'\n", x264_otos( str_height, "<unset>" ) )
288
width = INT_MAX;
289
}
290
else FAIL_IF_ERROR( 1, "invalid fittobox mode `%s'\n", fittobox )
291
292
/* maximally fit the new coded resolution to the box */
293
const x264_cli_csp_t *csp = x264_cli_get_csp( h->dst_csp );
294
double width_units = (double)info->height * in_sar_h * out_sar_w;
295
double height_units = (double)info->width * in_sar_w * out_sar_h;
296
width = width / csp->mod_width * csp->mod_width;
297
height = height / csp->mod_height * csp->mod_height;
298
if( width * width_units > height * height_units )
299
{
300
int new_width = round( height * height_units / (width_units * csp->mod_width) );
301
new_width *= csp->mod_width;
302
width = X264_MIN( new_width, width );
303
}
304
else
305
{
306
int new_height = round( width * width_units / (height_units * csp->mod_height) );
307
new_height *= csp->mod_height;
308
height = X264_MIN( new_height, height );
309
}
310
}
311
else
312
{
313
if( str_width || str_height )
314
{
315
FAIL_IF_ERROR( width <= 0 || height <= 0, "invalid resolution %sx%s\n",
316
x264_otos( str_width, "<unset>" ), x264_otos( str_height, "<unset>" ) )
317
if( !str_sar ) /* res only -> adjust sar */
318
{
319
/* new_sar = (new_h * old_w * old_sar_w) / (old_h * new_w * old_sar_h) */
320
uint64_t num = (uint64_t)info->width * height;
321
uint64_t den = (uint64_t)info->height * width;
322
x264_reduce_fraction64( &num, &den );
323
out_sar_w = num * in_sar_w;
324
out_sar_h = den * in_sar_h;
325
x264_reduce_fraction( &out_sar_w, &out_sar_h );
326
}
327
}
328
else if( str_sar ) /* sar only -> adjust res */
329
{
330
const x264_cli_csp_t *csp = x264_cli_get_csp( h->dst_csp );
331
double width_units = (double)in_sar_h * out_sar_w;
332
double height_units = (double)in_sar_w * out_sar_h;
333
width = info->width;
334
height = info->height;
335
if( width_units > height_units ) // SAR got wider, decrease width
336
{
337
width = round( info->width * height_units / (width_units * csp->mod_width) );
338
width *= csp->mod_width;
339
}
340
else // SAR got thinner, decrease height
341
{
342
height = round( info->height * width_units / (height_units * csp->mod_height) );
343
height *= csp->mod_height;
344
}
345
}
346
else /* csp only */
347
{
348
h->dst.width = info->width;
349
h->dst.height = info->height;
350
csp_only = 1;
351
}
352
}
353
if( !csp_only )
354
{
355
info->sar_width = out_sar_w;
356
info->sar_height = out_sar_h;
357
h->dst.width = width;
358
h->dst.height = height;
359
}
360
return 0;
361
}
362
363
static int x264_init_sws_context( resizer_hnd_t *h )
364
{
365
if( h->ctx )
366
sws_freeContext( h->ctx );
367
h->ctx = sws_alloc_context();
368
if( !h->ctx )
369
return -1;
370
371
av_opt_set_int( h->ctx, "sws_flags", h->ctx_flags, 0 );
372
av_opt_set_int( h->ctx, "dstw", h->dst.width, 0 );
373
av_opt_set_int( h->ctx, "dsth", h->dst.height, 0 );
374
av_opt_set_int( h->ctx, "dst_format", h->dst.pix_fmt, 0 );
375
av_opt_set_int( h->ctx, "dst_range", h->dst.range, 0 );
376
377
av_opt_set_int( h->ctx, "srcw", h->scale.width, 0 );
378
av_opt_set_int( h->ctx, "srch", h->scale.height, 0 );
379
av_opt_set_int( h->ctx, "src_format", h->scale.pix_fmt, 0 );
380
av_opt_set_int( h->ctx, "src_range", h->scale.range, 0 );
381
382
/* FIXME: use the correct matrix coefficients (only YUV -> RGB conversions are supported) */
383
sws_setColorspaceDetails( h->ctx,
384
sws_getCoefficients( SWS_CS_DEFAULT ), h->scale.range,
385
sws_getCoefficients( SWS_CS_DEFAULT ), h->dst.range,
386
0, 1<<16, 1<<16 );
387
388
return sws_init_context( h->ctx, NULL, NULL ) < 0;
389
}
390
391
static int check_resizer( resizer_hnd_t *h, cli_pic_t *in )
392
{
393
frame_prop_t input_prop = { in->img.width, in->img.height, convert_csp_to_pix_fmt( in->img.csp ), h->input_range };
394
if( !memcmp( &input_prop, &h->scale, sizeof(frame_prop_t) ) )
395
return 0;
396
/* also warn if the resizer was initialized after the first frame */
397
if( h->ctx || h->working )
398
x264_cli_log( NAME, X264_LOG_WARNING, "stream properties changed at pts %"PRId64"\n", in->pts );
399
h->scale = input_prop;
400
if( !h->buffer_allocated )
401
{
402
if( x264_cli_pic_alloc_aligned( &h->buffer, h->dst_csp, h->dst.width, h->dst.height ) )
403
return -1;
404
h->buffer_allocated = 1;
405
}
406
FAIL_IF_ERROR( x264_init_sws_context( h ), "swscale init failed\n" )
407
return 0;
408
}
409
410
static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )
411
{
412
/* if called for normalizing the csp to known formats and the format is not unknown, exit */
413
if( opt_string && !strcmp( opt_string, "normcsp" ) && !(info->csp&X264_CSP_OTHER) )
414
return 0;
415
/* if called by x264cli and nothing needs to be done, exit */
416
if( !opt_string && !full_check( info, param ) )
417
return 0;
418
419
static const char *optlist[] = { "width", "height", "sar", "fittobox", "csp", "method", NULL };
420
char **opts = x264_split_options( opt_string, optlist );
421
if( !opts && opt_string )
422
return -1;
423
424
resizer_hnd_t *h = calloc( 1, sizeof(resizer_hnd_t) );
425
if( !h )
426
return -1;
427
if( opts )
428
{
429
h->dst_csp = info->csp;
430
h->dst.width = info->width;
431
h->dst.height = info->height;
432
h->dst.range = info->fullrange; // maintain input range
433
if( !strcmp( opt_string, "normcsp" ) )
434
{
435
/* only in normalization scenarios is the input capable of changing properties */
436
h->variable_input = 1;
437
h->dst_csp = pick_closest_supported_csp( info->csp );
438
FAIL_IF_ERROR( h->dst_csp == X264_CSP_NONE,
439
"filter get invalid input pixel format %d (colorspace %d)\n", convert_csp_to_pix_fmt( info->csp ), info->csp )
440
}
441
else if( handle_opts( optlist, opts, info, h ) )
442
return -1;
443
}
444
else
445
{
446
h->dst_csp = param->i_csp;
447
h->dst.width = param->i_width;
448
h->dst.height = param->i_height;
449
h->dst.range = param->vui.b_fullrange; // change to libx264's range
450
}
451
h->ctx_flags = convert_method_to_flag( x264_otos( x264_get_option( optlist[5], opts ), "" ) );
452
x264_free_string_array( opts );
453
454
if( h->ctx_flags != SWS_FAST_BILINEAR )
455
h->ctx_flags |= SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | SWS_ACCURATE_RND;
456
h->dst.pix_fmt = convert_csp_to_pix_fmt( h->dst_csp );
457
h->scale = h->dst;
458
h->input_range = info->fullrange;
459
460
/* swap chroma planes if YV12/YV16/YV24 is involved, as libswscale works with I420/I422/I444 */
461
int src_csp = info->csp & (X264_CSP_MASK | X264_CSP_OTHER);
462
int dst_csp = h->dst_csp & (X264_CSP_MASK | X264_CSP_OTHER);
463
h->pre_swap_chroma = src_csp == X264_CSP_YV12 || src_csp == X264_CSP_YV16 || src_csp == X264_CSP_YV24;
464
h->post_swap_chroma = dst_csp == X264_CSP_YV12 || dst_csp == X264_CSP_YV16 || dst_csp == X264_CSP_YV24;
465
466
int src_pix_fmt = convert_csp_to_pix_fmt( info->csp );
467
468
int src_pix_fmt_inv = convert_csp_to_pix_fmt( info->csp ^ X264_CSP_HIGH_DEPTH );
469
int dst_pix_fmt_inv = convert_csp_to_pix_fmt( h->dst_csp ^ X264_CSP_HIGH_DEPTH );
470
471
/* confirm swscale can support this conversion */
472
FAIL_IF_ERROR( src_pix_fmt == AV_PIX_FMT_NONE && src_pix_fmt_inv != AV_PIX_FMT_NONE,
473
"input colorspace %s with bit depth %d is not supported\n", av_get_pix_fmt_name( src_pix_fmt_inv ),
474
info->csp & X264_CSP_HIGH_DEPTH ? 16 : 8 );
475
FAIL_IF_ERROR( !sws_isSupportedInput( src_pix_fmt ), "input colorspace %s is not supported\n", av_get_pix_fmt_name( src_pix_fmt ) )
476
FAIL_IF_ERROR( h->dst.pix_fmt == AV_PIX_FMT_NONE && dst_pix_fmt_inv != AV_PIX_FMT_NONE,
477
"input colorspace %s with bit depth %d is not supported\n", av_get_pix_fmt_name( dst_pix_fmt_inv ),
478
h->dst_csp & X264_CSP_HIGH_DEPTH ? 16 : 8 );
479
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 ) )
480
FAIL_IF_ERROR( h->dst.height != info->height && info->interlaced,
481
"swscale is not compatible with interlaced vertical resizing\n" )
482
/* confirm that the desired resolution meets the colorspace requirements */
483
const x264_cli_csp_t *csp = x264_cli_get_csp( h->dst_csp );
484
FAIL_IF_ERROR( h->dst.width % csp->mod_width || h->dst.height % csp->mod_height,
485
"resolution %dx%d is not compliant with colorspace %s\n", h->dst.width, h->dst.height, csp->name )
486
487
if( h->dst.width != info->width || h->dst.height != info->height )
488
x264_cli_log( NAME, X264_LOG_INFO, "resizing to %dx%d\n", h->dst.width, h->dst.height );
489
if( h->dst.pix_fmt != src_pix_fmt )
490
x264_cli_log( NAME, X264_LOG_WARNING, "converting from %s to %s\n",
491
av_get_pix_fmt_name( src_pix_fmt ), av_get_pix_fmt_name( h->dst.pix_fmt ) );
492
else if( h->dst.range != h->input_range )
493
x264_cli_log( NAME, X264_LOG_WARNING, "converting range from %s to %s\n",
494
h->input_range ? "PC" : "TV", h->dst.range ? "PC" : "TV" );
495
h->dst_csp |= info->csp & X264_CSP_VFLIP; // preserve vflip
496
497
/* if the input is not variable, initialize the context */
498
if( !h->variable_input )
499
{
500
cli_pic_t input_pic = {{info->csp, info->width, info->height, 0}, 0};
501
if( check_resizer( h, &input_pic ) )
502
return -1;
503
}
504
505
/* finished initing, overwrite values */
506
info->csp = h->dst_csp;
507
info->width = h->dst.width;
508
info->height = h->dst.height;
509
info->fullrange = h->dst.range;
510
511
h->prev_filter = *filter;
512
h->prev_hnd = *handle;
513
*handle = h;
514
*filter = resize_filter;
515
516
return 0;
517
}
518
519
static int get_frame( hnd_t handle, cli_pic_t *output, int frame )
520
{
521
resizer_hnd_t *h = handle;
522
if( h->prev_filter.get_frame( h->prev_hnd, output, frame ) )
523
return -1;
524
if( h->variable_input && check_resizer( h, output ) )
525
return -1;
526
h->working = 1;
527
if( h->pre_swap_chroma )
528
XCHG( uint8_t*, output->img.plane[1], output->img.plane[2] );
529
if( h->ctx )
530
{
531
sws_scale( h->ctx, (const uint8_t* const*)output->img.plane, output->img.stride,
532
0, output->img.height, h->buffer.img.plane, h->buffer.img.stride );
533
output->img = h->buffer.img; /* copy img data */
534
}
535
else
536
output->img.csp = h->dst_csp;
537
if( h->post_swap_chroma )
538
XCHG( uint8_t*, output->img.plane[1], output->img.plane[2] );
539
540
return 0;
541
}
542
543
static int release_frame( hnd_t handle, cli_pic_t *pic, int frame )
544
{
545
resizer_hnd_t *h = handle;
546
return h->prev_filter.release_frame( h->prev_hnd, pic, frame );
547
}
548
549
static void free_filter( hnd_t handle )
550
{
551
resizer_hnd_t *h = handle;
552
h->prev_filter.free( h->prev_hnd );
553
if( h->ctx )
554
sws_freeContext( h->ctx );
555
if( h->buffer_allocated )
556
x264_cli_pic_clean( &h->buffer );
557
free( h );
558
}
559
560
#else /* no swscale */
561
static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )
562
{
563
int ret = 0;
564
565
if( !opt_string )
566
ret = full_check( info, param );
567
else
568
{
569
if( !strcmp( opt_string, "normcsp" ) )
570
ret = info->csp & X264_CSP_OTHER;
571
else
572
ret = -1;
573
}
574
575
/* pass if nothing needs to be done, otherwise fail */
576
FAIL_IF_ERROR( ret, "not compiled with swscale support\n" )
577
return 0;
578
}
579
580
#define help NULL
581
#define get_frame NULL
582
#define release_frame NULL
583
#define free_filter NULL
584
#define convert_csp_to_pix_fmt(x) (x & X264_CSP_MASK)
585
586
#endif
587
588
cli_vid_filter_t resize_filter = { NAME, help, init, get_frame, release_frame, free_filter, NULL };
589
590