[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( &param );
     /* Parse command line */
     if( parse( argc, argv, &param, &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( &param );
 
 #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