[x264-devel] [Git][videolan/x264][master] Add new API function: x264_param_cleanup
Anton Mitrofanov
gitlab at videolan.org
Thu Jul 2 22:24:01 CEST 2020
Anton Mitrofanov pushed to branch master at VideoLAN / x264
Commits:
4c2aafd8 by Anton Mitrofanov at 2020-07-02T22:23:50+02:00
Add new API function: x264_param_cleanup
Should be called to free struct members allocated internally by libx264,
e.g. by x264_param_parse.
Partially based on videolan/x264!18 by Derek Buitenhuis.
- - - - -
7 changed files:
- common/base.c
- common/base.h
- common/frame.c
- encoder/encoder.c
- encoder/ratecontrol.c
- x264.c
- x264.h
Changes:
=====================================
common/base.c
=====================================
@@ -198,6 +198,66 @@ error:
return NULL;
}
+/****************************************************************************
+ * x264_strdup:
+ ****************************************************************************/
+typedef struct {
+ int size;
+ int count;
+ void *ptr[];
+} strdup_buffer;
+
+#define BUFFER_OFFSET offsetof(strdup_buffer, ptr)
+#define BUFFER_DEFAULT_SIZE 16
+
+char *x264_strdup( x264_param_t *param, const char *src )
+{
+ strdup_buffer *buf = param->opaque;
+ if( !buf )
+ {
+ buf = malloc( BUFFER_OFFSET + BUFFER_DEFAULT_SIZE * sizeof(void *) );
+ if( !buf )
+ goto fail;
+ buf->size = BUFFER_DEFAULT_SIZE;
+ buf->count = 0;
+ param->opaque = buf;
+ }
+ else if( buf->count == buf->size )
+ {
+ if( buf->size > (INT_MAX - BUFFER_OFFSET) / 2 / (int)sizeof(void *) )
+ goto fail;
+ int new_size = buf->size * 2;
+ buf = realloc( buf, BUFFER_OFFSET + new_size * sizeof(void *) );
+ if( !buf )
+ goto fail;
+ buf->size = new_size;
+ param->opaque = buf;
+ }
+ char *res = strdup( src );
+ if( !res )
+ goto fail;
+ buf->ptr[buf->count++] = res;
+ return res;
+fail:
+ x264_log_internal( X264_LOG_ERROR, "strdup failed\n" );
+ return NULL;
+}
+
+/****************************************************************************
+ * x264_param_cleanup:
+ ****************************************************************************/
+REALIGN_STACK void x264_param_cleanup( x264_param_t *param )
+{
+ strdup_buffer *buf = param->opaque;
+ if( buf )
+ {
+ for( int i = 0; i < buf->count; i++ )
+ free( buf->ptr[i] );
+ free( buf );
+ param->opaque = NULL;
+ }
+}
+
/****************************************************************************
* x264_picture_init:
****************************************************************************/
@@ -811,6 +871,15 @@ static double atof_internal( const char *str, int *b_error )
#undef atof
#define atoi(str) atoi_internal( str, &b_error )
#define atof(str) atof_internal( str, &b_error )
+#define CHECKED_ERROR_STRDUP( var, param, src )\
+do {\
+ var = x264_strdup( param, src );\
+ if( !var )\
+ {\
+ b_error = 1;\
+ errortype = X264_PARAM_ALLOC_FAILED;\
+ }\
+} while( 0 )
REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const char *value )
{
@@ -833,7 +902,7 @@ REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const cha
char *c;
name_buf = strdup(name);
if( !name_buf )
- return X264_PARAM_BAD_NAME;
+ return X264_PARAM_ALLOC_FAILED;
while( (c = strchr( name_buf, '_' )) )
*c = '-';
name = name_buf;
@@ -876,6 +945,8 @@ REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const cha
if( (p->cpu&X264_CPU_SSSE3) && !(p->cpu&X264_CPU_SSE2_IS_SLOW) )
p->cpu |= X264_CPU_SSE2_IS_FAST;
}
+ else
+ errortype = X264_PARAM_ALLOC_FAILED;
}
}
OPT("threads")
@@ -1062,10 +1133,10 @@ REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const cha
else if( strstr( value, "jvt" ) )
p->i_cqm_preset = X264_CQM_JVT;
else
- p->psz_cqm_file = strdup(value);
+ CHECKED_ERROR_STRDUP( p->psz_cqm_file, p, value );
}
OPT("cqmfile")
- p->psz_cqm_file = strdup(value);
+ CHECKED_ERROR_STRDUP( p->psz_cqm_file, p, value );
OPT("cqm4")
{
p->i_cqm_preset = X264_CQM_CUSTOM;
@@ -1129,7 +1200,7 @@ REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const cha
OPT("log")
p->i_log_level = atoi(value);
OPT("dump-yuv")
- p->psz_dump_yuv = strdup(value);
+ CHECKED_ERROR_STRDUP( p->psz_dump_yuv, p, value );
OPT2("analyse", "partitions")
{
p->analyse.inter = 0;
@@ -1245,8 +1316,8 @@ REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const cha
}
OPT("stats")
{
- p->rc.psz_stat_in = strdup(value);
- p->rc.psz_stat_out = strdup(value);
+ CHECKED_ERROR_STRDUP( p->rc.psz_stat_in, p, value );
+ CHECKED_ERROR_STRDUP( p->rc.psz_stat_out, p, value );
}
OPT("qcomp")
p->rc.f_qcompress = atof(value);
@@ -1257,7 +1328,7 @@ REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const cha
OPT2("cplxblur", "cplx-blur")
p->rc.f_complexity_blur = atof(value);
OPT("zones")
- p->rc.psz_zones = strdup(value);
+ CHECKED_ERROR_STRDUP( p->rc.psz_zones, p, value );
OPT("crop-rect")
b_error |= sscanf( value, "%d,%d,%d,%d", &p->crop_rect.i_left, &p->crop_rect.i_top,
&p->crop_rect.i_right, &p->crop_rect.i_bottom ) != 4;
@@ -1292,7 +1363,7 @@ REALIGN_STACK int x264_param_parse( x264_param_t *p, const char *name, const cha
OPT("opencl")
p->b_opencl = atobool( value );
OPT("opencl-clbin")
- p->psz_clbin_file = strdup( value );
+ CHECKED_ERROR_STRDUP( p->psz_clbin_file, p, value );
OPT("opencl-device")
p->i_opencl_device = atoi( value );
else
=====================================
common/base.h
=====================================
@@ -261,7 +261,7 @@ X264_API void x264_reduce_fraction64( uint64_t *n, uint64_t *d );
X264_API void x264_log_default( void *p_unused, int i_level, const char *psz_fmt, va_list arg );
X264_API void x264_log_internal( int i_level, const char *psz_fmt, ... );
-/* x264_malloc : will do or emulate a memalign
+/* x264_malloc: will do or emulate a memalign
* you have to use x264_free for buffers allocated with x264_malloc */
X264_API void *x264_malloc( int64_t );
X264_API void x264_free( void * );
@@ -269,6 +269,10 @@ X264_API void x264_free( void * );
/* x264_slurp_file: malloc space for the whole file and read it */
X264_API char *x264_slurp_file( const char *filename );
+/* x264_strdup: will do strdup and save returned pointer inside
+ * x264_param_t for later freeing during x264_param_cleanup */
+char *x264_strdup( x264_param_t *param, const char *src );
+
/* x264_param2string: return a (malloced) string containing most of
* the encoding options */
X264_API char *x264_param2string( x264_param_t *p, int b_res );
@@ -287,6 +291,12 @@ do {\
CHECKED_MALLOC( var, size );\
memset( var, 0, size );\
} while( 0 )
+#define CHECKED_STRDUP( var, param, src )\
+do {\
+ var = x264_strdup( param, src );\
+ if( !var )\
+ goto fail;\
+} while( 0 )
/* Macros for merging multiple allocations into a single large malloc, for improved
* use with huge pages. */
=====================================
common/frame.c
=====================================
@@ -318,7 +318,10 @@ void x264_frame_delete( x264_frame_t *frame )
x264_free( frame->base );
if( frame->param && frame->param->param_free )
+ {
+ x264_param_cleanup( frame->param );
frame->param->param_free( frame->param );
+ }
if( frame->mb_info_free )
frame->mb_info_free( frame->mb_info );
if( frame->extra_sei.sei_free )
=====================================
encoder/encoder.c
=====================================
@@ -1460,9 +1460,27 @@ x264_t *x264_encoder_open( x264_param_t *param )
/* Create a copy of param */
memcpy( &h->param, param, sizeof(x264_param_t) );
+ h->param.opaque = NULL;
+ h->param.param_free = NULL;
+
+ if( h->param.psz_cqm_file )
+ CHECKED_STRDUP( h->param.psz_cqm_file, &h->param, h->param.psz_cqm_file );
+ if( h->param.psz_dump_yuv )
+ CHECKED_STRDUP( h->param.psz_dump_yuv, &h->param, h->param.psz_dump_yuv );
+ if( h->param.rc.psz_stat_out )
+ CHECKED_STRDUP( h->param.rc.psz_stat_out, &h->param, h->param.rc.psz_stat_out );
+ if( h->param.rc.psz_stat_in )
+ CHECKED_STRDUP( h->param.rc.psz_stat_in, &h->param, h->param.rc.psz_stat_in );
+ if( h->param.rc.psz_zones )
+ CHECKED_STRDUP( h->param.rc.psz_zones, &h->param, h->param.rc.psz_zones );
+ if( h->param.psz_clbin_file )
+ CHECKED_STRDUP( h->param.psz_clbin_file, &h->param, h->param.psz_clbin_file );
if( param->param_free )
+ {
+ x264_param_cleanup( param );
param->param_free( param );
+ }
#if HAVE_INTEL_DISPATCHER
x264_intel_dispatcher_override();
@@ -1481,11 +1499,6 @@ x264_t *x264_encoder_open( x264_param_t *param )
if( x264_cqm_parse_file( h, h->param.psz_cqm_file ) < 0 )
goto fail;
- if( h->param.rc.psz_stat_out )
- h->param.rc.psz_stat_out = strdup( h->param.rc.psz_stat_out );
- if( h->param.rc.psz_stat_in )
- h->param.rc.psz_stat_in = strdup( h->param.rc.psz_stat_in );
-
x264_reduce_fraction( &h->param.i_fps_num, &h->param.i_fps_den );
x264_reduce_fraction( &h->param.i_timebase_num, &h->param.i_timebase_den );
@@ -1900,6 +1913,7 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
void x264_encoder_parameters( x264_t *h, x264_param_t *param )
{
memcpy( param, &h->thread[h->i_thread_phase]->param, sizeof(x264_param_t) );
+ param->opaque = NULL;
}
/* internal usage */
@@ -3395,6 +3409,7 @@ int x264_encoder_encode( x264_t *h,
x264_encoder_reconfig_apply( h, h->fenc->param );
if( h->fenc->param->param_free )
{
+ x264_param_cleanup( h->fenc->param );
h->fenc->param->param_free( h->fenc->param );
h->fenc->param = NULL;
}
@@ -4418,10 +4433,7 @@ void x264_encoder_close ( x264_t *h )
x264_ratecontrol_delete( h );
/* param */
- if( h->param.rc.psz_stat_out )
- free( h->param.rc.psz_stat_out );
- if( h->param.rc.psz_stat_in )
- free( h->param.rc.psz_stat_in );
+ x264_param_cleanup( &h->param );
x264_cqm_delete( h );
x264_free( h->nal_buffer );
=====================================
encoder/ratecontrol.c
=====================================
@@ -1237,6 +1237,7 @@ static int parse_zone( x264_t *h, x264_zone_t *z, char *p )
return 0;
CHECKED_MALLOC( z->param, sizeof(x264_param_t) );
memcpy( z->param, &h->param, sizeof(x264_param_t) );
+ z->param->opaque = NULL;
z->param->param_free = x264_free;
while( (tok = strtok_r( p, ",", &saveptr )) )
{
@@ -1315,6 +1316,7 @@ static int parse_zones( x264_t *h )
rc->zones[0].f_bitrate_factor = 1;
CHECKED_MALLOC( rc->zones[0].param, sizeof(x264_param_t) );
memcpy( rc->zones[0].param, &h->param, sizeof(x264_param_t) );
+ rc->zones[0].param->opaque = NULL;
for( int i = 1; i < rc->i_zones; i++ )
{
if( !rc->zones[i].param )
@@ -1391,10 +1393,14 @@ void x264_ratecontrol_delete( x264_t *h )
macroblock_tree_rescale_destroy( rc );
if( rc->zones )
{
+ x264_param_cleanup( rc->zones[0].param );
x264_free( rc->zones[0].param );
for( int i = 1; i < rc->i_zones; i++ )
if( rc->zones[i].param != rc->zones[0].param && rc->zones[i].param->param_free )
+ {
+ x264_param_cleanup( rc->zones[i].param );
rc->zones[i].param->param_free( rc->zones[i].param );
+ }
x264_free( rc->zones );
}
x264_free( rc );
=====================================
x264.c
=====================================
@@ -288,7 +288,7 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt );
static int encode( x264_param_t *param, cli_opt_t *opt );
/* logging and printing for within the cli system */
-static int cli_log_level;
+static int cli_log_level = X264_LOG_INFO;
void x264_cli_log( const char *name, int i_level, const char *fmt, ... )
{
if( i_level > cli_log_level )
@@ -393,6 +393,7 @@ REALIGN_STACK int main( int argc, char **argv )
_setmode( _fileno( stderr ), _O_BINARY );
#endif
+ x264_param_default( ¶m );
/* Parse command line */
if( parse( argc, argv, ¶m, &opt ) < 0 )
ret = -1;
@@ -419,6 +420,7 @@ REALIGN_STACK int main( int argc, char **argv )
fclose( opt.tcfile_out );
if( opt.qpfile )
fclose( opt.qpfile );
+ x264_param_cleanup( ¶m );
#ifdef _WIN32
SetConsoleTitleW( org_console_title );
@@ -1412,16 +1414,6 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt )
char *preset = NULL;
char *tune = NULL;
- x264_param_default( &defaults );
- cli_log_level = defaults.i_log_level;
-
- memset( &input_opt, 0, sizeof(cli_input_opt_t) );
- memset( &output_opt, 0, sizeof(cli_output_opt_t) );
- input_opt.bit_depth = 8;
- input_opt.input_range = input_opt.output_range = param->vui.b_fullrange = RANGE_AUTO;
- int output_csp = defaults.i_csp;
- opt->b_progress = 1;
-
/* Presets are applied before all other options. */
for( optind = 0;; )
{
@@ -1439,9 +1431,19 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt )
if( preset && !strcasecmp( preset, "placebo" ) )
b_turbo = 0;
- if( x264_param_default_preset( param, preset, tune ) < 0 )
+ if( (preset || tune) && x264_param_default_preset( param, preset, tune ) < 0 )
return -1;
+ x264_param_default( &defaults );
+ cli_log_level = defaults.i_log_level;
+
+ memset( &input_opt, 0, sizeof(cli_input_opt_t) );
+ memset( &output_opt, 0, sizeof(cli_output_opt_t) );
+ input_opt.bit_depth = 8;
+ input_opt.input_range = input_opt.output_range = param->vui.b_fullrange = RANGE_AUTO;
+ int output_csp = defaults.i_csp;
+ opt->b_progress = 1;
+
/* Parse command line options */
for( optind = 0;; )
{
=====================================
x264.h
=====================================
@@ -45,7 +45,7 @@ extern "C" {
#include "x264_config.h"
-#define X264_BUILD 160
+#define X264_BUILD 161
#ifdef _WIN32
# define X264_DLL_IMPORT __declspec(dllimport)
@@ -583,6 +583,9 @@ typedef struct x264_param_t
* e.g. if doing multiple encodes in one process.
*/
void (*nalu_process)( x264_t *h, x264_nal_t *nal, void *opaque );
+
+ /* For internal use only */
+ void *opaque;
} x264_param_t;
X264_API void x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal );
@@ -625,11 +628,20 @@ X264_API void x264_param_default( x264_param_t * );
* note: BAD_VALUE occurs only if it can't even parse the value,
* numerical range is not checked until x264_encoder_open() or
* x264_encoder_reconfig().
- * value=NULL means "true" for boolean options, but is a BAD_VALUE for non-booleans. */
+ * value=NULL means "true" for boolean options, but is a BAD_VALUE for non-booleans.
+ * can allocate memory which should be freed by call of x264_param_cleanup. */
#define X264_PARAM_BAD_NAME (-1)
#define X264_PARAM_BAD_VALUE (-2)
+#define X264_PARAM_ALLOC_FAILED (-3)
X264_API int x264_param_parse( x264_param_t *, const char *name, const char *value );
+/* x264_param_cleanup:
+ * Cleans up and frees allocated members of x264_param_t.
+ * This *does not* free the x264_param_t itself, as it may exist on the
+ * stack. It only frees any members of the struct that were allocated by
+ * x264 itself, in e.g. x264_param_parse(). */
+X264_API void x264_param_cleanup( x264_param_t *param );
+
/****************************************************************************
* Advanced parameter handling functions
****************************************************************************/
View it on GitLab: https://code.videolan.org/videolan/x264/-/commit/4c2aafd864dd201832ec2be0fef4484925146650
--
View it on GitLab: https://code.videolan.org/videolan/x264/-/commit/4c2aafd864dd201832ec2be0fef4484925146650
You're receiving this email because of your account on code.videolan.org.
More information about the x264-devel
mailing list