2009-11-12 00:50:21 +01:00
/*
2010-11-28 11:22:58 +01:00
* Copyright ( c ) 2007 Bobby Bingham
2009-11-12 00:50:21 +01:00
*
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* FFmpeg is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
/**
2010-04-20 16:45:34 +02:00
* @ file
2009-11-12 00:50:21 +01:00
* scale video filter
*/
2012-08-06 15:49:32 +02:00
# include <stdio.h>
# include <string.h>
2009-11-12 00:50:21 +01:00
# include "avfilter.h"
2012-05-30 10:12:55 +02:00
# include "formats.h"
2012-06-12 20:12:42 +02:00
# include "internal.h"
2012-05-30 11:20:32 +02:00
# include "video.h"
2011-03-27 22:58:08 +02:00
# include "libavutil/avstring.h"
# include "libavutil/eval.h"
2012-08-06 15:49:32 +02:00
# include "libavutil/internal.h"
2011-06-04 13:58:23 +02:00
# include "libavutil/mathematics.h"
2012-04-09 06:05:50 +02:00
# include "libavutil/opt.h"
2012-10-29 11:48:53 +01:00
# include "libavutil/parseutils.h"
2010-01-31 17:33:29 +01:00
# include "libavutil/pixdesc.h"
2012-04-08 15:11:13 +02:00
# include "libavutil/imgutils.h"
2011-03-28 00:09:58 +02:00
# include "libavutil/avassert.h"
2009-11-12 00:50:21 +01:00
# include "libswscale/swscale.h"
2012-02-20 09:42:33 +01:00
static const char * const var_names [ ] = {
2011-03-27 22:58:08 +02:00
" in_w " , " iw " ,
" in_h " , " ih " ,
" out_w " , " ow " ,
" out_h " , " oh " ,
2011-07-27 10:58:24 +02:00
" a " ,
2011-07-02 17:27:31 +02:00
" sar " ,
2011-07-27 10:58:24 +02:00
" dar " ,
2011-03-27 22:58:08 +02:00
" hsub " ,
" vsub " ,
2013-11-04 14:18:09 +01:00
" ohsub " ,
" ovsub " ,
2011-03-27 22:58:08 +02:00
NULL
} ;
enum var_name {
VAR_IN_W , VAR_IW ,
VAR_IN_H , VAR_IH ,
VAR_OUT_W , VAR_OW ,
VAR_OUT_H , VAR_OH ,
2011-07-27 10:58:24 +02:00
VAR_A ,
2011-07-02 17:27:31 +02:00
VAR_SAR ,
2011-07-27 10:58:24 +02:00
VAR_DAR ,
2011-03-27 22:58:08 +02:00
VAR_HSUB ,
VAR_VSUB ,
2013-11-04 14:18:09 +01:00
VAR_OHSUB ,
VAR_OVSUB ,
2011-03-27 22:58:08 +02:00
VARS_NB
} ;
2014-04-11 11:54:15 +02:00
typedef struct ScaleContext {
2012-10-06 12:30:26 +02:00
const AVClass * class ;
2009-11-12 00:50:21 +01:00
struct SwsContext * sws ; ///< software scaler context
2011-03-28 00:09:58 +02:00
struct SwsContext * isws [ 2 ] ; ///< software scaler context for interlaced material
2013-08-15 22:42:56 +02:00
AVDictionary * opts ;
2009-11-12 00:50:21 +01:00
/**
* New dimensions . Special values are :
* 0 = original width / height
* - 1 = keep original aspect
2014-01-25 15:02:15 +01:00
* - N = try to keep aspect but make sure it is divisible by N
2009-11-12 00:50:21 +01:00
*/
int w , h ;
2012-10-29 11:48:53 +01:00
char * size_str ;
2010-05-07 11:20:45 +02:00
unsigned int flags ; ///sws flags
2015-08-25 23:04:12 +02:00
double param [ 2 ] ; // sws params
2009-11-12 00:50:21 +01:00
int hsub , vsub ; ///< chroma subsampling
int slice_y ; ///< top of current output slice
int input_is_pal ; ///< set to 1 if the input format is paletted
2012-04-08 14:59:53 +02:00
int output_is_pal ; ///< set to 1 if the output format is paletted
2011-03-28 00:09:58 +02:00
int interlaced ;
2011-03-27 22:58:08 +02:00
2012-10-06 12:30:26 +02:00
char * w_expr ; ///< width expression string
char * h_expr ; ///< height expression string
2013-02-25 21:21:29 +01:00
char * flags_str ;
2013-07-20 22:11:50 +02:00
char * in_color_matrix ;
char * out_color_matrix ;
2013-07-20 22:12:42 +02:00
int in_range ;
int out_range ;
2013-07-14 05:03:06 +02:00
int out_h_chr_pos ;
int out_v_chr_pos ;
2013-07-24 18:33:58 +02:00
int in_h_chr_pos ;
int in_v_chr_pos ;
2013-08-04 01:30:00 +02:00
int force_original_aspect_ratio ;
2009-11-12 00:50:21 +01:00
} ScaleContext ;
2015-08-15 18:38:06 +02:00
AVFilter ff_vf_scale2ref ;
2013-08-15 22:42:56 +02:00
static av_cold int init_dict ( AVFilterContext * ctx , AVDictionary * * opts )
2009-11-12 00:50:21 +01:00
{
ScaleContext * scale = ctx - > priv ;
2012-10-06 12:30:26 +02:00
int ret ;
2012-10-29 11:48:53 +01:00
if ( scale - > size_str & & ( scale - > w_expr | | scale - > h_expr ) ) {
av_log ( ctx , AV_LOG_ERROR ,
" Size and width/height expressions cannot be set at the same time. \n " ) ;
return AVERROR ( EINVAL ) ;
}
2013-04-12 02:34:40 +02:00
if ( scale - > w_expr & & ! scale - > h_expr )
FFSWAP ( char * , scale - > w_expr , scale - > size_str ) ;
2012-10-29 11:48:53 +01:00
if ( scale - > size_str ) {
char buf [ 32 ] ;
if ( ( ret = av_parse_video_size ( & scale - > w , & scale - > h , scale - > size_str ) ) < 0 ) {
av_log ( ctx , AV_LOG_ERROR ,
" Invalid size '%s' \n " , scale - > size_str ) ;
return ret ;
}
snprintf ( buf , sizeof ( buf ) - 1 , " %d " , scale - > w ) ;
av_opt_set ( scale , " w " , buf , 0 ) ;
snprintf ( buf , sizeof ( buf ) - 1 , " %d " , scale - > h ) ;
av_opt_set ( scale , " h " , buf , 0 ) ;
}
if ( ! scale - > w_expr )
av_opt_set ( scale , " w " , " iw " , 0 ) ;
if ( ! scale - > h_expr )
av_opt_set ( scale , " h " , " ih " , 0 ) ;
2012-10-31 15:45:28 +01:00
av_log ( ctx , AV_LOG_VERBOSE , " w:%s h:%s flags:'%s' interl:%d \n " ,
scale - > w_expr , scale - > h_expr , ( char * ) av_x_if_null ( scale - > flags_str , " " ) , scale - > interlaced ) ;
2011-03-27 22:58:08 +02:00
2013-10-06 12:33:32 +02:00
scale - > flags = 0 ;
2013-04-12 02:34:40 +02:00
2012-10-06 12:30:26 +02:00
if ( scale - > flags_str ) {
const AVClass * class = sws_get_class ( ) ;
const AVOption * o = av_opt_find ( & class , " sws_flags " , NULL , 0 ,
AV_OPT_SEARCH_FAKE_OBJ ) ;
int ret = av_opt_eval_flags ( & class , o , scale - > flags_str , & scale - > flags ) ;
if ( ret < 0 )
return ret ;
2010-05-07 11:20:45 +02:00
}
2013-08-15 22:42:56 +02:00
scale - > opts = * opts ;
* opts = NULL ;
2009-11-12 00:50:21 +01:00
return 0 ;
}
static av_cold void uninit ( AVFilterContext * ctx )
{
ScaleContext * scale = ctx - > priv ;
sws_freeContext ( scale - > sws ) ;
2011-03-28 00:09:58 +02:00
sws_freeContext ( scale - > isws [ 0 ] ) ;
sws_freeContext ( scale - > isws [ 1 ] ) ;
2009-11-12 00:50:21 +01:00
scale - > sws = NULL ;
2013-08-15 22:42:56 +02:00
av_dict_free ( & scale - > opts ) ;
2009-11-12 00:50:21 +01:00
}
static int query_formats ( AVFilterContext * ctx )
{
AVFilterFormats * formats ;
2012-10-06 12:10:34 +02:00
enum AVPixelFormat pix_fmt ;
2010-01-09 00:48:32 +01:00
int ret ;
2009-11-12 00:50:21 +01:00
if ( ctx - > inputs [ 0 ] ) {
2014-05-24 11:15:15 +02:00
const AVPixFmtDescriptor * desc = NULL ;
2010-01-09 00:48:32 +01:00
formats = NULL ;
2014-05-24 11:15:15 +02:00
while ( ( desc = av_pix_fmt_desc_next ( desc ) ) ) {
pix_fmt = av_pix_fmt_desc_get_id ( desc ) ;
2013-04-26 14:49:43 +02:00
if ( ( sws_isSupportedInput ( pix_fmt ) | |
sws_isSupportedEndiannessConversion ( pix_fmt ) )
2012-05-30 10:12:55 +02:00
& & ( ret = ff_add_format ( & formats , pix_fmt ) ) < 0 ) {
ff_formats_unref ( & formats ) ;
2010-01-09 00:48:32 +01:00
return ret ;
}
2014-05-24 11:15:15 +02:00
}
2012-05-30 10:12:55 +02:00
ff_formats_ref ( formats , & ctx - > inputs [ 0 ] - > out_formats ) ;
2009-11-12 00:50:21 +01:00
}
if ( ctx - > outputs [ 0 ] ) {
2014-05-24 11:15:15 +02:00
const AVPixFmtDescriptor * desc = NULL ;
2010-01-09 00:48:32 +01:00
formats = NULL ;
2014-05-24 11:15:15 +02:00
while ( ( desc = av_pix_fmt_desc_next ( desc ) ) ) {
pix_fmt = av_pix_fmt_desc_get_id ( desc ) ;
2013-05-07 11:23:55 +02:00
if ( ( sws_isSupportedOutput ( pix_fmt ) | | pix_fmt = = AV_PIX_FMT_PAL8 | |
2013-04-26 14:49:43 +02:00
sws_isSupportedEndiannessConversion ( pix_fmt ) )
2012-05-30 10:12:55 +02:00
& & ( ret = ff_add_format ( & formats , pix_fmt ) ) < 0 ) {
ff_formats_unref ( & formats ) ;
2010-01-09 00:48:32 +01:00
return ret ;
}
2014-05-24 11:15:15 +02:00
}
2012-05-30 10:12:55 +02:00
ff_formats_ref ( formats , & ctx - > outputs [ 0 ] - > in_formats ) ;
2009-11-12 00:50:21 +01:00
}
return 0 ;
}
2013-07-20 22:11:50 +02:00
static const int * parse_yuv_type ( const char * s , enum AVColorSpace colorspace )
{
if ( ! s )
s = " bt601 " ;
if ( s & & strstr ( s , " bt709 " ) ) {
colorspace = AVCOL_SPC_BT709 ;
} else if ( s & & strstr ( s , " fcc " ) ) {
colorspace = AVCOL_SPC_FCC ;
} else if ( s & & strstr ( s , " smpte240m " ) ) {
colorspace = AVCOL_SPC_SMPTE240M ;
} else if ( s & & ( strstr ( s , " bt601 " ) | | strstr ( s , " bt470 " ) | | strstr ( s , " smpte170m " ) ) ) {
colorspace = AVCOL_SPC_BT470BG ;
}
if ( colorspace < 1 | | colorspace > 7 ) {
colorspace = AVCOL_SPC_BT470BG ;
}
2013-07-26 23:03:58 +02:00
return sws_getCoefficients ( colorspace ) ;
2013-07-20 22:11:50 +02:00
}
2009-11-12 00:50:21 +01:00
static int config_props ( AVFilterLink * outlink )
{
AVFilterContext * ctx = outlink - > src ;
2015-08-15 18:38:06 +02:00
AVFilterLink * inlink0 = outlink - > src - > inputs [ 0 ] ;
AVFilterLink * inlink = ctx - > filter = = & ff_vf_scale2ref ?
outlink - > src - > inputs [ 1 ] :
outlink - > src - > inputs [ 0 ] ;
2012-10-08 20:54:00 +02:00
enum AVPixelFormat outfmt = outlink - > format ;
2009-11-12 00:50:21 +01:00
ScaleContext * scale = ctx - > priv ;
2012-10-06 13:29:37 +02:00
const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get ( inlink - > format ) ;
2013-11-04 14:18:09 +01:00
const AVPixFmtDescriptor * out_desc = av_pix_fmt_desc_get ( outlink - > format ) ;
2009-11-12 00:50:21 +01:00
int64_t w , h ;
2011-03-27 22:58:08 +02:00
double var_values [ VARS_NB ] , res ;
char * expr ;
int ret ;
2014-01-25 15:00:02 +01:00
int factor_w , factor_h ;
2011-03-27 22:58:08 +02:00
var_values [ VAR_IN_W ] = var_values [ VAR_IW ] = inlink - > w ;
var_values [ VAR_IN_H ] = var_values [ VAR_IH ] = inlink - > h ;
var_values [ VAR_OUT_W ] = var_values [ VAR_OW ] = NAN ;
var_values [ VAR_OUT_H ] = var_values [ VAR_OH ] = NAN ;
2012-10-06 13:23:05 +02:00
var_values [ VAR_A ] = ( double ) inlink - > w / inlink - > h ;
2011-07-02 17:27:31 +02:00
var_values [ VAR_SAR ] = inlink - > sample_aspect_ratio . num ?
2012-10-05 14:45:30 +02:00
( double ) inlink - > sample_aspect_ratio . num / inlink - > sample_aspect_ratio . den : 1 ;
2011-07-27 10:58:24 +02:00
var_values [ VAR_DAR ] = var_values [ VAR_A ] * var_values [ VAR_SAR ] ;
2012-10-06 13:29:37 +02:00
var_values [ VAR_HSUB ] = 1 < < desc - > log2_chroma_w ;
var_values [ VAR_VSUB ] = 1 < < desc - > log2_chroma_h ;
2013-11-04 14:18:09 +01:00
var_values [ VAR_OHSUB ] = 1 < < out_desc - > log2_chroma_w ;
var_values [ VAR_OVSUB ] = 1 < < out_desc - > log2_chroma_h ;
2011-03-27 22:58:08 +02:00
/* evaluate width and height */
av_expr_parse_and_eval ( & res , ( expr = scale - > w_expr ) ,
var_names , var_values ,
NULL , NULL , NULL , NULL , NULL , 0 , ctx ) ;
2011-04-17 17:23:48 +02:00
scale - > w = var_values [ VAR_OUT_W ] = var_values [ VAR_OW ] = res ;
2011-03-27 22:58:08 +02:00
if ( ( ret = av_expr_parse_and_eval ( & res , ( expr = scale - > h_expr ) ,
var_names , var_values ,
NULL , NULL , NULL , NULL , NULL , 0 , ctx ) ) < 0 )
goto fail ;
2011-04-17 17:23:48 +02:00
scale - > h = var_values [ VAR_OUT_H ] = var_values [ VAR_OH ] = res ;
2011-03-27 22:58:08 +02:00
/* evaluate again the width, as it may depend on the output height */
if ( ( ret = av_expr_parse_and_eval ( & res , ( expr = scale - > w_expr ) ,
var_names , var_values ,
NULL , NULL , NULL , NULL , NULL , 0 , ctx ) ) < 0 )
goto fail ;
scale - > w = res ;
w = scale - > w ;
h = scale - > h ;
2014-01-25 14:40:48 +01:00
/* Check if it is requested that the result has to be divisible by a some
2014-01-25 16:54:24 +01:00
* factor ( w or h = - n with n being the factor ) . */
2014-01-25 15:00:02 +01:00
factor_w = 1 ;
factor_h = 1 ;
2014-01-25 14:40:48 +01:00
if ( w < - 1 ) {
factor_w = - w ;
2011-03-27 22:58:08 +02:00
}
2014-01-25 14:40:48 +01:00
if ( h < - 1 ) {
factor_h = - h ;
}
2014-01-25 16:54:24 +01:00
if ( w < 0 & & h < 0 )
2011-03-27 22:58:08 +02:00
scale - > w = scale - > h = 0 ;
2009-11-12 00:50:21 +01:00
if ( ! ( w = scale - > w ) )
w = inlink - > w ;
if ( ! ( h = scale - > h ) )
h = inlink - > h ;
2014-01-25 14:40:48 +01:00
/* Make sure that the result is divisible by the factor we determined
* earlier . If no factor was set , it is nothing will happen as the default
* factor is 1 */
2014-01-25 16:54:24 +01:00
if ( w < 0 )
2014-01-25 16:48:13 +01:00
w = av_rescale ( h , inlink - > w , inlink - > h * factor_w ) * factor_w ;
2014-01-25 16:54:24 +01:00
if ( h < 0 )
2014-01-25 16:48:13 +01:00
h = av_rescale ( w , inlink - > h , inlink - > w * factor_h ) * factor_h ;
2014-01-25 14:40:48 +01:00
/* Note that force_original_aspect_ratio may overwrite the previous set
* dimensions so that it is not divisible by the set factors anymore . */
2013-08-04 01:30:00 +02:00
if ( scale - > force_original_aspect_ratio ) {
int tmp_w = av_rescale ( h , inlink - > w , inlink - > h ) ;
int tmp_h = av_rescale ( w , inlink - > h , inlink - > w ) ;
if ( scale - > force_original_aspect_ratio = = 1 ) {
w = FFMIN ( tmp_w , w ) ;
h = FFMIN ( tmp_h , h ) ;
} else {
w = FFMAX ( tmp_w , w ) ;
h = FFMAX ( tmp_h , h ) ;
}
}
2009-11-12 00:50:21 +01:00
if ( w > INT_MAX | | h > INT_MAX | |
( h * inlink - > w ) > INT_MAX | |
( w * inlink - > h ) > INT_MAX )
av_log ( ctx , AV_LOG_ERROR , " Rescaled value for width or height is too big. \n " ) ;
outlink - > w = w ;
outlink - > h = h ;
/* TODO: make algorithm configurable */
2013-05-12 15:41:49 +02:00
scale - > input_is_pal = desc - > flags & AV_PIX_FMT_FLAG_PAL | |
desc - > flags & AV_PIX_FMT_FLAG_PSEUDOPAL ;
2012-10-08 20:54:00 +02:00
if ( outfmt = = AV_PIX_FMT_PAL8 ) outfmt = AV_PIX_FMT_BGR8 ;
2013-05-15 10:50:20 +02:00
scale - > output_is_pal = av_pix_fmt_desc_get ( outfmt ) - > flags & AV_PIX_FMT_FLAG_PAL | |
av_pix_fmt_desc_get ( outfmt ) - > flags & AV_PIX_FMT_FLAG_PSEUDOPAL ;
2009-11-12 00:50:21 +01:00
2011-05-02 12:35:39 +02:00
if ( scale - > sws )
2011-03-09 03:30:24 +01:00
sws_freeContext ( scale - > sws ) ;
2013-07-14 05:19:46 +02:00
if ( scale - > isws [ 0 ] )
sws_freeContext ( scale - > isws [ 0 ] ) ;
if ( scale - > isws [ 1 ] )
sws_freeContext ( scale - > isws [ 1 ] ) ;
scale - > isws [ 0 ] = scale - > isws [ 1 ] = scale - > sws = NULL ;
2015-08-15 18:38:06 +02:00
if ( inlink0 - > w = = outlink - > w & &
inlink0 - > h = = outlink - > h & &
2015-08-30 23:49:04 +02:00
! scale - > out_color_matrix & &
2015-08-30 23:46:11 +02:00
scale - > in_range = = scale - > out_range & &
2015-08-15 18:38:06 +02:00
inlink0 - > format = = outlink - > format )
2013-07-14 05:19:46 +02:00
;
2012-03-29 07:02:27 +02:00
else {
2013-07-14 05:19:46 +02:00
struct SwsContext * * swscs [ 3 ] = { & scale - > sws , & scale - > isws [ 0 ] , & scale - > isws [ 1 ] } ;
int i ;
for ( i = 0 ; i < 3 ; i + + ) {
struct SwsContext * * s = swscs [ i ] ;
* s = sws_alloc_context ( ) ;
if ( ! * s )
return AVERROR ( ENOMEM ) ;
2015-08-15 18:38:06 +02:00
av_opt_set_int ( * s , " srcw " , inlink0 - > w , 0 ) ;
av_opt_set_int ( * s , " srch " , inlink0 - > h > > ! ! i , 0 ) ;
av_opt_set_int ( * s , " src_format " , inlink0 - > format , 0 ) ;
2013-07-14 05:19:46 +02:00
av_opt_set_int ( * s , " dstw " , outlink - > w , 0 ) ;
av_opt_set_int ( * s , " dsth " , outlink - > h > > ! ! i , 0 ) ;
av_opt_set_int ( * s , " dst_format " , outfmt , 0 ) ;
av_opt_set_int ( * s , " sws_flags " , scale - > flags , 0 ) ;
2015-08-31 10:07:34 +02:00
av_opt_set_int ( * s , " param0 " , scale - > param [ 0 ] , 0 ) ;
av_opt_set_int ( * s , " param1 " , scale - > param [ 1 ] , 0 ) ;
2015-09-01 09:17:26 +02:00
if ( scale - > in_range ! = AVCOL_RANGE_UNSPECIFIED )
av_opt_set_int ( * s , " src_range " ,
scale - > in_range = = AVCOL_RANGE_JPEG , 0 ) ;
if ( scale - > out_range ! = AVCOL_RANGE_UNSPECIFIED )
av_opt_set_int ( * s , " dst_range " ,
scale - > out_range = = AVCOL_RANGE_JPEG , 0 ) ;
2013-07-14 05:19:46 +02:00
2015-08-08 14:43:12 +02:00
if ( scale - > opts ) {
AVDictionaryEntry * e = NULL ;
while ( ( e = av_dict_get ( scale - > opts , " " , e , AV_DICT_IGNORE_SUFFIX ) ) ) {
if ( ( ret = av_opt_set ( * s , e - > key , e - > value , 0 ) ) < 0 )
return ret ;
}
}
2014-12-25 00:52:46 +01:00
/* Override YUV420P settings to have the correct (MPEG-2) chroma positions
* MPEG - 2 chroma positions are used by convention
* XXX : support other 4 : 2 : 0 pixel formats */
2015-08-15 18:38:06 +02:00
if ( inlink0 - > format = = AV_PIX_FMT_YUV420P ) {
2014-12-25 00:52:46 +01:00
scale - > in_v_chr_pos = ( i = = 0 ) ? 128 : ( i = = 1 ) ? 64 : 192 ;
}
if ( outlink - > format = = AV_PIX_FMT_YUV420P ) {
scale - > out_v_chr_pos = ( i = = 0 ) ? 128 : ( i = = 1 ) ? 64 : 192 ;
}
2013-07-24 18:33:58 +02:00
av_opt_set_int ( * s , " src_h_chr_pos " , scale - > in_h_chr_pos , 0 ) ;
av_opt_set_int ( * s , " src_v_chr_pos " , scale - > in_v_chr_pos , 0 ) ;
2013-07-14 05:03:06 +02:00
av_opt_set_int ( * s , " dst_h_chr_pos " , scale - > out_h_chr_pos , 0 ) ;
av_opt_set_int ( * s , " dst_v_chr_pos " , scale - > out_v_chr_pos , 0 ) ;
2013-07-14 05:19:46 +02:00
if ( ( ret = sws_init_context ( * s , NULL , NULL ) ) < 0 )
return ret ;
2013-07-18 11:03:56 +02:00
if ( ! scale - > interlaced )
break ;
2013-07-14 05:19:46 +02:00
}
2012-03-29 07:02:27 +02:00
}
2010-05-08 00:12:13 +02:00
2011-08-27 01:49:55 +02:00
if ( inlink - > sample_aspect_ratio . num ) {
outlink - > sample_aspect_ratio = av_mul_q ( ( AVRational ) { outlink - > h * inlink - > w , outlink - > w * inlink - > h } , inlink - > sample_aspect_ratio ) ;
} else
outlink - > sample_aspect_ratio = inlink - > sample_aspect_ratio ;
2012-07-14 18:26:04 +02:00
av_log ( ctx , AV_LOG_VERBOSE , " w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x \n " ,
2012-10-12 17:04:58 +02:00
inlink - > w , inlink - > h , av_get_pix_fmt_name ( inlink - > format ) ,
2012-03-17 12:28:35 +01:00
inlink - > sample_aspect_ratio . num , inlink - > sample_aspect_ratio . den ,
2012-10-12 17:04:58 +02:00
outlink - > w , outlink - > h , av_get_pix_fmt_name ( outlink - > format ) ,
2012-03-17 12:28:35 +01:00
outlink - > sample_aspect_ratio . num , outlink - > sample_aspect_ratio . den ,
scale - > flags ) ;
2011-01-16 21:11:46 +01:00
return 0 ;
2011-03-27 22:58:08 +02:00
fail :
av_log ( NULL , AV_LOG_ERROR ,
2011-12-04 23:33:40 +01:00
" Error when evaluating the expression '%s'. \n "
" Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing. \n " ,
expr , scale - > w_expr , scale - > h_expr ) ;
2011-03-27 22:58:08 +02:00
return ret ;
2009-11-12 00:50:21 +01:00
}
2015-08-15 18:38:06 +02:00
static int config_props_ref ( AVFilterLink * outlink )
{
AVFilterLink * inlink = outlink - > src - > inputs [ 1 ] ;
outlink - > w = inlink - > w ;
outlink - > h = inlink - > h ;
outlink - > sample_aspect_ratio = inlink - > sample_aspect_ratio ;
2015-08-18 15:06:10 +02:00
outlink - > time_base = inlink - > time_base ;
2015-08-15 18:38:06 +02:00
return 0 ;
}
2015-08-18 15:10:30 +02:00
static int request_frame ( AVFilterLink * outlink )
{
return ff_request_frame ( outlink - > src - > inputs [ 0 ] ) ;
}
static int request_frame_ref ( AVFilterLink * outlink )
{
return ff_request_frame ( outlink - > src - > inputs [ 1 ] ) ;
}
2013-03-10 01:30:30 +01:00
static int scale_slice ( AVFilterLink * link , AVFrame * out_buf , AVFrame * cur_pic , struct SwsContext * sws , int y , int h , int mul , int field )
2009-11-12 00:50:21 +01:00
{
ScaleContext * scale = link - > dst - > priv ;
2011-06-01 20:26:54 +02:00
const uint8_t * in [ 4 ] ;
uint8_t * out [ 4 ] ;
2011-03-28 00:09:58 +02:00
int in_stride [ 4 ] , out_stride [ 4 ] ;
int i ;
for ( i = 0 ; i < 4 ; i + + ) {
int vsub = ( ( i + 1 ) & 2 ) ? scale - > vsub : 0 ;
in_stride [ i ] = cur_pic - > linesize [ i ] * mul ;
out_stride [ i ] = out_buf - > linesize [ i ] * mul ;
in [ i ] = cur_pic - > data [ i ] + ( ( y > > vsub ) + field ) * cur_pic - > linesize [ i ] ;
out [ i ] = out_buf - > data [ i ] + field * out_buf - > linesize [ i ] ;
}
2012-04-08 14:59:53 +02:00
if ( scale - > input_is_pal )
2011-03-28 00:09:58 +02:00
in [ 1 ] = cur_pic - > data [ 1 ] ;
2012-04-08 14:59:53 +02:00
if ( scale - > output_is_pal )
2011-03-28 00:09:58 +02:00
out [ 1 ] = out_buf - > data [ 1 ] ;
return sws_scale ( sws , in , in_stride , y / mul , h ,
out , out_stride ) ;
}
2012-11-28 08:41:07 +01:00
static int filter_frame ( AVFilterLink * link , AVFrame * in )
2009-11-12 00:50:21 +01:00
{
ScaleContext * scale = link - > dst - > priv ;
2012-11-29 01:19:35 +01:00
AVFilterLink * outlink = link - > dst - > outputs [ 0 ] ;
2012-11-28 08:41:07 +01:00
AVFrame * out ;
2012-11-29 01:19:35 +01:00
const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get ( link - > format ) ;
char buf [ 32 ] ;
2013-07-25 01:27:00 +02:00
int in_range ;
2012-11-29 01:19:35 +01:00
2015-04-13 13:45:41 +02:00
if ( av_frame_get_colorspace ( in ) = = AVCOL_SPC_YCGCO )
av_log ( link - > dst , AV_LOG_WARNING , " Detected unsupported YCgCo colorspace. \n " ) ;
2013-03-10 01:30:30 +01:00
if ( in - > width ! = link - > w
| | in - > height ! = link - > h
| | in - > format ! = link - > format ) {
2012-11-29 01:19:35 +01:00
int ret ;
snprintf ( buf , sizeof ( buf ) - 1 , " %d " , outlink - > w ) ;
av_opt_set ( scale , " w " , buf , 0 ) ;
snprintf ( buf , sizeof ( buf ) - 1 , " %d " , outlink - > h ) ;
av_opt_set ( scale , " h " , buf , 0 ) ;
2009-11-12 00:50:21 +01:00
2012-11-29 01:19:35 +01:00
link - > dst - > inputs [ 0 ] - > format = in - > format ;
2013-03-10 01:30:30 +01:00
link - > dst - > inputs [ 0 ] - > w = in - > width ;
link - > dst - > inputs [ 0 ] - > h = in - > height ;
2012-11-29 01:19:35 +01:00
if ( ( ret = config_props ( outlink ) ) < 0 )
return ret ;
2012-03-29 07:02:27 +02:00
}
2012-11-29 01:19:35 +01:00
if ( ! scale - > sws )
return ff_filter_frame ( outlink , in ) ;
scale - > hsub = desc - > log2_chroma_w ;
scale - > vsub = desc - > log2_chroma_h ;
2012-11-28 08:41:07 +01:00
out = ff_get_video_buffer ( outlink , outlink - > w , outlink - > h ) ;
2012-11-29 01:19:35 +01:00
if ( ! out ) {
2012-11-28 08:41:07 +01:00
av_frame_free ( & in ) ;
2012-11-29 01:19:35 +01:00
return AVERROR ( ENOMEM ) ;
}
2012-11-28 08:41:07 +01:00
av_frame_copy_props ( out , in ) ;
out - > width = outlink - > w ;
out - > height = outlink - > h ;
2012-11-29 01:19:35 +01:00
if ( scale - > output_is_pal )
avpriv_set_systematic_pal2 ( ( uint32_t * ) out - > data [ 1 ] , outlink - > format = = AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : outlink - > format ) ;
2013-07-25 01:27:00 +02:00
in_range = av_frame_get_color_range ( in ) ;
2013-07-20 22:11:50 +02:00
if ( scale - > in_color_matrix
| | scale - > out_color_matrix
| | scale - > in_range ! = AVCOL_RANGE_UNSPECIFIED
2013-07-25 01:27:00 +02:00
| | in_range ! = AVCOL_RANGE_UNSPECIFIED
2013-07-20 22:11:50 +02:00
| | scale - > out_range ! = AVCOL_RANGE_UNSPECIFIED ) {
int in_full , out_full , brightness , contrast , saturation ;
const int * inv_table , * table ;
sws_getColorspaceDetails ( scale - > sws , ( int * * ) & inv_table , & in_full ,
( int * * ) & table , & out_full ,
& brightness , & contrast , & saturation ) ;
if ( scale - > in_color_matrix )
inv_table = parse_yuv_type ( scale - > in_color_matrix , av_frame_get_colorspace ( in ) ) ;
if ( scale - > out_color_matrix )
table = parse_yuv_type ( scale - > out_color_matrix , AVCOL_SPC_UNSPECIFIED ) ;
2015-08-31 00:17:50 +02:00
else if ( scale - > in_color_matrix )
table = inv_table ;
2013-07-20 22:11:50 +02:00
2013-07-20 22:12:42 +02:00
if ( scale - > in_range ! = AVCOL_RANGE_UNSPECIFIED )
in_full = ( scale - > in_range = = AVCOL_RANGE_JPEG ) ;
2013-07-25 01:27:00 +02:00
else if ( in_range ! = AVCOL_RANGE_UNSPECIFIED )
in_full = ( in_range = = AVCOL_RANGE_JPEG ) ;
2013-07-20 22:12:42 +02:00
if ( scale - > out_range ! = AVCOL_RANGE_UNSPECIFIED )
out_full = ( scale - > out_range = = AVCOL_RANGE_JPEG ) ;
2013-07-20 22:11:50 +02:00
sws_setColorspaceDetails ( scale - > sws , inv_table , in_full ,
table , out_full ,
brightness , contrast , saturation ) ;
if ( scale - > isws [ 0 ] )
2013-07-20 22:20:25 +02:00
sws_setColorspaceDetails ( scale - > isws [ 0 ] , inv_table , in_full ,
table , out_full ,
brightness , contrast , saturation ) ;
2013-07-20 22:11:50 +02:00
if ( scale - > isws [ 1 ] )
2013-07-20 22:20:25 +02:00
sws_setColorspaceDetails ( scale - > isws [ 1 ] , inv_table , in_full ,
table , out_full ,
brightness , contrast , saturation ) ;
2013-07-20 22:11:50 +02:00
}
2012-11-28 08:41:07 +01:00
av_reduce ( & out - > sample_aspect_ratio . num , & out - > sample_aspect_ratio . den ,
( int64_t ) in - > sample_aspect_ratio . num * outlink - > h * link - > w ,
( int64_t ) in - > sample_aspect_ratio . den * outlink - > w * link - > h ,
2012-11-29 01:19:35 +01:00
INT_MAX ) ;
2009-11-12 00:50:21 +01:00
2013-03-10 01:30:30 +01:00
if ( scale - > interlaced > 0 | | ( scale - > interlaced < 0 & & in - > interlaced_frame ) ) {
2012-11-29 01:19:35 +01:00
scale_slice ( link , out , in , scale - > isws [ 0 ] , 0 , ( link - > h + 1 ) / 2 , 2 , 0 ) ;
scale_slice ( link , out , in , scale - > isws [ 1 ] , 0 , link - > h / 2 , 2 , 1 ) ;
2011-03-28 00:09:58 +02:00
} else {
2012-11-29 01:19:35 +01:00
scale_slice ( link , out , in , scale - > sws , 0 , link - > h , 1 , 0 ) ;
2011-03-28 00:09:58 +02:00
}
2009-11-12 00:50:21 +01:00
2012-11-28 08:41:07 +01:00
av_frame_free ( & in ) ;
2012-11-29 01:19:35 +01:00
return ff_filter_frame ( outlink , out ) ;
2009-11-12 00:50:21 +01:00
}
2015-08-15 18:38:06 +02:00
static int filter_frame_ref ( AVFilterLink * link , AVFrame * in )
{
AVFilterLink * outlink = link - > dst - > outputs [ 1 ] ;
return ff_filter_frame ( outlink , in ) ;
}
2015-07-21 12:45:43 +02:00
static int process_command ( AVFilterContext * ctx , const char * cmd , const char * args ,
char * res , int res_len , int flags )
{
ScaleContext * scale = ctx - > priv ;
int ret ;
if ( ! strcmp ( cmd , " width " ) | | ! strcmp ( cmd , " w " )
| | ! strcmp ( cmd , " height " ) | | ! strcmp ( cmd , " h " ) ) {
int old_w = scale - > w ;
int old_h = scale - > h ;
AVFilterLink * outlink = ctx - > outputs [ 0 ] ;
av_opt_set ( scale , cmd , args , 0 ) ;
if ( ( ret = config_props ( outlink ) ) < 0 ) {
scale - > w = old_w ;
scale - > h = old_h ;
}
} else
ret = AVERROR ( ENOSYS ) ;
return ret ;
}
2013-08-15 22:42:56 +02:00
static const AVClass * child_class_next ( const AVClass * prev )
{
return prev ? NULL : sws_get_class ( ) ;
}
2013-02-25 21:21:29 +01:00
# define OFFSET(x) offsetof(ScaleContext, x)
2013-04-10 20:29:25 +02:00
# define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption scale_options [ ] = {
2013-04-12 02:34:40 +02:00
{ " w " , " Output video width " , OFFSET ( w_expr ) , AV_OPT_TYPE_STRING , . flags = FLAGS } ,
{ " width " , " Output video width " , OFFSET ( w_expr ) , AV_OPT_TYPE_STRING , . flags = FLAGS } ,
{ " h " , " Output video height " , OFFSET ( h_expr ) , AV_OPT_TYPE_STRING , . flags = FLAGS } ,
{ " height " , " Output video height " , OFFSET ( h_expr ) , AV_OPT_TYPE_STRING , . flags = FLAGS } ,
2013-02-25 21:21:29 +01:00
{ " flags " , " Flags to pass to libswscale " , OFFSET ( flags_str ) , AV_OPT_TYPE_STRING , { . str = " bilinear " } , . flags = FLAGS } ,
2013-04-10 20:29:25 +02:00
{ " interl " , " set interlacing " , OFFSET ( interlaced ) , AV_OPT_TYPE_INT , { . i64 = 0 } , - 1 , 1 , FLAGS } ,
{ " size " , " set video size " , OFFSET ( size_str ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , FLAGS } ,
{ " s " , " set video size " , OFFSET ( size_str ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , FLAGS } ,
2013-07-27 01:16:07 +02:00
{ " in_color_matrix " , " set input YCbCr type " , OFFSET ( in_color_matrix ) , AV_OPT_TYPE_STRING , { . str = " auto " } , . flags = FLAGS } ,
2013-07-20 22:11:50 +02:00
{ " out_color_matrix " , " set output YCbCr type " , OFFSET ( out_color_matrix ) , AV_OPT_TYPE_STRING , { . str = NULL } , . flags = FLAGS } ,
2013-07-20 22:12:42 +02:00
{ " in_range " , " set input color range " , OFFSET ( in_range ) , AV_OPT_TYPE_INT , { . i64 = AVCOL_RANGE_UNSPECIFIED } , 0 , 2 , FLAGS , " range " } ,
{ " out_range " , " set output color range " , OFFSET ( out_range ) , AV_OPT_TYPE_INT , { . i64 = AVCOL_RANGE_UNSPECIFIED } , 0 , 2 , FLAGS , " range " } ,
{ " auto " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = AVCOL_RANGE_UNSPECIFIED } , 0 , 0 , FLAGS , " range " } ,
{ " full " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = AVCOL_RANGE_JPEG } , 0 , 0 , FLAGS , " range " } ,
{ " jpeg " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = AVCOL_RANGE_JPEG } , 0 , 0 , FLAGS , " range " } ,
{ " mpeg " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = AVCOL_RANGE_MPEG } , 0 , 0 , FLAGS , " range " } ,
2013-10-23 12:50:07 +02:00
{ " tv " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = AVCOL_RANGE_MPEG } , 0 , 0 , FLAGS , " range " } ,
{ " pc " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = AVCOL_RANGE_JPEG } , 0 , 0 , FLAGS , " range " } ,
2014-09-21 12:12:50 +02:00
{ " in_v_chr_pos " , " input vertical chroma position in luma grid/256 " , OFFSET ( in_v_chr_pos ) , AV_OPT_TYPE_INT , { . i64 = - 513 } , - 513 , 512 , FLAGS } ,
{ " in_h_chr_pos " , " input horizontal chroma position in luma grid/256 " , OFFSET ( in_h_chr_pos ) , AV_OPT_TYPE_INT , { . i64 = - 513 } , - 513 , 512 , FLAGS } ,
{ " out_v_chr_pos " , " output vertical chroma position in luma grid/256 " , OFFSET ( out_v_chr_pos ) , AV_OPT_TYPE_INT , { . i64 = - 513 } , - 513 , 512 , FLAGS } ,
{ " out_h_chr_pos " , " output horizontal chroma position in luma grid/256 " , OFFSET ( out_h_chr_pos ) , AV_OPT_TYPE_INT , { . i64 = - 513 } , - 513 , 512 , FLAGS } ,
2013-08-04 01:30:00 +02:00
{ " force_original_aspect_ratio " , " decrease or increase w/h if necessary to keep the original AR " , OFFSET ( force_original_aspect_ratio ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 2 , FLAGS , " force_oar " } ,
{ " disable " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 0 } , 0 , 0 , FLAGS , " force_oar " } ,
{ " decrease " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 1 } , 0 , 0 , FLAGS , " force_oar " } ,
{ " increase " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 2 } , 0 , 0 , FLAGS , " force_oar " } ,
2015-08-25 23:04:12 +02:00
{ " param0 " , " Scaler param 0 " , OFFSET ( param [ 0 ] ) , AV_OPT_TYPE_DOUBLE , { . dbl = SWS_PARAM_DEFAULT } , INT_MIN , INT_MAX , FLAGS } ,
{ " param1 " , " Scaler param 1 " , OFFSET ( param [ 1 ] ) , AV_OPT_TYPE_DOUBLE , { . dbl = SWS_PARAM_DEFAULT } , INT_MIN , INT_MAX , FLAGS } ,
2013-09-07 14:13:50 +02:00
{ NULL }
2013-02-25 21:21:29 +01:00
} ;
2013-08-15 22:42:56 +02:00
static const AVClass scale_class = {
. class_name = " scale " ,
. item_name = av_default_item_name ,
. option = scale_options ,
. version = LIBAVUTIL_VERSION_INT ,
2014-07-28 05:15:16 +02:00
. category = AV_CLASS_CATEGORY_FILTER ,
2013-08-15 22:42:56 +02:00
. child_class_next = child_class_next ,
} ;
2013-02-25 21:21:29 +01:00
2012-07-24 15:14:01 +02:00
static const AVFilterPad avfilter_vf_scale_inputs [ ] = {
{
2013-09-07 14:13:50 +02:00
. name = " default " ,
. type = AVMEDIA_TYPE_VIDEO ,
2012-11-29 01:19:35 +01:00
. filter_frame = filter_frame ,
2012-07-24 15:14:01 +02:00
} ,
{ NULL }
} ;
static const AVFilterPad avfilter_vf_scale_outputs [ ] = {
{
. name = " default " ,
. type = AVMEDIA_TYPE_VIDEO ,
. config_props = config_props ,
} ,
{ NULL }
} ;
2013-10-28 07:44:24 +01:00
AVFilter ff_vf_scale = {
2015-07-21 12:45:43 +02:00
. name = " scale " ,
. description = NULL_IF_CONFIG_SMALL ( " Scale the input video size and/or convert the image format. " ) ,
. init_dict = init_dict ,
. uninit = uninit ,
. query_formats = query_formats ,
. priv_size = sizeof ( ScaleContext ) ,
. priv_class = & scale_class ,
. inputs = avfilter_vf_scale_inputs ,
. outputs = avfilter_vf_scale_outputs ,
. process_command = process_command ,
2009-11-12 00:50:21 +01:00
} ;
2015-08-15 18:38:06 +02:00
static const AVClass scale2ref_class = {
. class_name = " scale2ref " ,
. item_name = av_default_item_name ,
. option = scale_options ,
. version = LIBAVUTIL_VERSION_INT ,
. category = AV_CLASS_CATEGORY_FILTER ,
. child_class_next = child_class_next ,
} ;
static const AVFilterPad avfilter_vf_scale2ref_inputs [ ] = {
{
. name = " default " ,
. type = AVMEDIA_TYPE_VIDEO ,
. filter_frame = filter_frame ,
} ,
{
. name = " ref " ,
. type = AVMEDIA_TYPE_VIDEO ,
. filter_frame = filter_frame_ref ,
} ,
{ NULL }
} ;
static const AVFilterPad avfilter_vf_scale2ref_outputs [ ] = {
{
. name = " default " ,
. type = AVMEDIA_TYPE_VIDEO ,
. config_props = config_props ,
2015-08-18 15:10:30 +02:00
. request_frame = request_frame ,
2015-08-15 18:38:06 +02:00
} ,
{
. name = " ref " ,
. type = AVMEDIA_TYPE_VIDEO ,
. config_props = config_props_ref ,
2015-08-18 15:10:30 +02:00
. request_frame = request_frame_ref ,
2015-08-15 18:38:06 +02:00
} ,
{ NULL }
} ;
AVFilter ff_vf_scale2ref = {
. name = " scale2ref " ,
. description = NULL_IF_CONFIG_SMALL ( " Scale the input video size and/or convert the image format to the given reference. " ) ,
. init_dict = init_dict ,
. uninit = uninit ,
. query_formats = query_formats ,
. priv_size = sizeof ( ScaleContext ) ,
. priv_class = & scale2ref_class ,
. inputs = avfilter_vf_scale2ref_inputs ,
. outputs = avfilter_vf_scale2ref_outputs ,
. process_command = process_command ,
} ;