[x264-devel] Make x264_encoder_reconfig more threadsafe
Anton Mitrofanov
git at videolan.org
Wed Oct 30 21:18:33 CET 2013
x264 | branch: master | Anton Mitrofanov <BugMaster at narod.ru> | Sun Oct 27 15:22:51 2013 +0400| [af66a8b36d13ee359cb5386a2813c73fcba496fd] | committer: Jason Garrett-Glaser
Make x264_encoder_reconfig more threadsafe
Do the reconfig when the next frame's encode begins.
Fixes some rare crashes with frame-threading and encoder_reconfig.
> http://git.videolan.org/gitweb.cgi/x264.git/?a=commit;h=af66a8b36d13ee359cb5386a2813c73fcba496fd
---
common/common.h | 3 ++
encoder/encoder.c | 78 +++++++++++++++++++++++++++++++++++--------------
encoder/ratecontrol.c | 2 +-
encoder/ratecontrol.h | 1 +
x264.c | 9 ++++--
5 files changed, 67 insertions(+), 26 deletions(-)
diff --git a/common/common.h b/common/common.h
index c9f7bf0..9e05525 100644
--- a/common/common.h
+++ b/common/common.h
@@ -517,6 +517,9 @@ struct x264_t
uint8_t *nal_buffer;
int nal_buffer_size;
+ x264_t *reconfig_h;
+ int reconfig;
+
/**** thread synchronization starts here ****/
/* frame number/poc */
diff --git a/encoder/encoder.c b/encoder/encoder.c
index 78ad56a..9a3aab2 100644
--- a/encoder/encoder.c
+++ b/encoder/encoder.c
@@ -517,6 +517,12 @@ static int x264_validate_parameters( x264_t *h, int b_open )
return -1;
}
+ if( h->param.vui.i_sar_width <= 0 || h->param.vui.i_sar_height <= 0 )
+ {
+ h->param.vui.i_sar_width = 0;
+ h->param.vui.i_sar_height = 0;
+ }
+
if( h->param.i_threads == X264_THREADS_AUTO )
h->param.i_threads = x264_cpu_num_processors() * (h->param.b_sliced_threads?2:3)/2;
int max_sliced_threads = X264_MAX( 1, (h->param.i_height+15)/16 / 4 );
@@ -1331,7 +1337,6 @@ static void x264_set_aspect_ratio( x264_t *h, x264_param_t *param, int initial )
h->param.vui.i_sar_width = i_w;
h->param.vui.i_sar_height = i_h;
}
- x264_sps_init( h->sps, h->param.i_sps_id, &h->param );
}
}
}
@@ -1385,11 +1390,11 @@ x264_t *x264_encoder_open( x264_param_t *param )
goto fail;
}
+ x264_set_aspect_ratio( h, &h->param, 1 );
+
x264_sps_init( h->sps, h->param.i_sps_id, &h->param );
x264_pps_init( h->pps, h->param.i_sps_id, &h->param, h->sps );
- x264_set_aspect_ratio( h, &h->param, 1 );
-
x264_validate_levels( h, 1 );
h->chroma_qp_table = i_chroma_qp_table + 12 + h->pps->i_chroma_qp_index_offset;
@@ -1540,6 +1545,8 @@ x264_t *x264_encoder_open( x264_param_t *param )
h->nal_buffer_size = h->out.i_bitstream * 3/2 + 4 + 64; /* +4 for startcode, +64 for nal_escape assembly padding */
CHECKED_MALLOC( h->nal_buffer, h->nal_buffer_size );
+ CHECKED_MALLOC( h->reconfig_h, sizeof(x264_t) );
+
if( h->param.i_threads > 1 &&
x264_threadpool_init( &h->threadpool, h->param.i_threads, (void*)x264_encoder_thread_init, h ) )
goto fail;
@@ -1568,6 +1575,7 @@ x264_t *x264_encoder_open( x264_param_t *param )
CHECKED_MALLOC( h->lookahead_thread[i], sizeof(x264_t) );
*h->lookahead_thread[i] = *h;
}
+ *h->reconfig_h = *h;
for( int i = 0; i < h->param.i_threads; i++ )
{
@@ -1667,18 +1675,10 @@ fail:
return NULL;
}
-/****************************************************************************
- * x264_encoder_reconfig:
- ****************************************************************************/
-int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
+/****************************************************************************/
+static int x264_encoder_try_reconfig( x264_t *h, x264_param_t *param, int *rc_reconfig )
{
- /* If the previous frame isn't done encoding, reconfiguring is probably dangerous. */
- if( h->param.b_sliced_threads )
- if( x264_threadpool_wait_all( h ) < 0 )
- return -1;
-
- int rc_reconfig = 0;
- h = h->thread[h->thread[0]->i_thread_phase];
+ *rc_reconfig = 0;
x264_set_aspect_ratio( h, param, 0 );
#define COPY(var) h->param.var = param->var
COPY( i_frame_reference ); // but never uses more refs than initially specified
@@ -1727,22 +1727,30 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
if( h->param.rc.i_vbv_max_bitrate > 0 && h->param.rc.i_vbv_buffer_size > 0 &&
param->rc.i_vbv_max_bitrate > 0 && param->rc.i_vbv_buffer_size > 0 )
{
- rc_reconfig |= h->param.rc.i_vbv_max_bitrate != param->rc.i_vbv_max_bitrate;
- rc_reconfig |= h->param.rc.i_vbv_buffer_size != param->rc.i_vbv_buffer_size;
- rc_reconfig |= h->param.rc.i_bitrate != param->rc.i_bitrate;
+ *rc_reconfig |= h->param.rc.i_vbv_max_bitrate != param->rc.i_vbv_max_bitrate;
+ *rc_reconfig |= h->param.rc.i_vbv_buffer_size != param->rc.i_vbv_buffer_size;
+ *rc_reconfig |= h->param.rc.i_bitrate != param->rc.i_bitrate;
COPY( rc.i_vbv_max_bitrate );
COPY( rc.i_vbv_buffer_size );
COPY( rc.i_bitrate );
}
- rc_reconfig |= h->param.rc.f_rf_constant != param->rc.f_rf_constant;
- rc_reconfig |= h->param.rc.f_rf_constant_max != param->rc.f_rf_constant_max;
+ *rc_reconfig |= h->param.rc.f_rf_constant != param->rc.f_rf_constant;
+ *rc_reconfig |= h->param.rc.f_rf_constant_max != param->rc.f_rf_constant_max;
COPY( rc.f_rf_constant );
COPY( rc.f_rf_constant_max );
#undef COPY
- mbcmp_init( h );
+ return x264_validate_parameters( h, 0 );
+}
- int ret = x264_validate_parameters( h, 0 );
+int x264_encoder_reconfig_apply( x264_t *h, x264_param_t *param )
+{
+ int rc_reconfig;
+ int ret = x264_encoder_try_reconfig( h, param, &rc_reconfig );
+
+ mbcmp_init( h );
+ if( !ret )
+ x264_sps_init( h->sps, h->param.i_sps_id, &h->param );
/* Supported reconfiguration options (1-pass only):
* vbv-maxrate
@@ -1756,6 +1764,25 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
}
/****************************************************************************
+ * x264_encoder_reconfig:
+ ****************************************************************************/
+int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
+{
+ h = h->thread[h->thread[0]->i_thread_phase];
+ x264_param_t param_save = h->reconfig_h->param;
+ h->reconfig_h->param = h->param;
+
+ int rc_reconfig;
+ int ret = x264_encoder_try_reconfig( h->reconfig_h, param, &rc_reconfig );
+ if( !ret )
+ h->reconfig = 1;
+ else
+ h->reconfig_h->param = param_save;
+
+ return ret;
+}
+
+/****************************************************************************
* x264_encoder_parameters:
****************************************************************************/
void x264_encoder_parameters( x264_t *h, x264_param_t *param )
@@ -2905,6 +2932,7 @@ static void x264_thread_sync_context( x264_t *dst, x264_t *src )
dst->param = src->param;
dst->stat = src->stat;
dst->pixf = src->pixf;
+ dst->reconfig = src->reconfig;
}
static void x264_thread_sync_stat( x264_t *dst, x264_t *src )
@@ -3223,9 +3251,14 @@ int x264_encoder_encode( x264_t *h,
if( h->i_frame == h->i_thread_frames - 1 )
h->i_reordered_pts_delay = h->fenc->i_reordered_pts;
+ if( h->reconfig )
+ {
+ x264_encoder_reconfig_apply( h, &h->reconfig_h->param );
+ h->reconfig = 0;
+ }
if( h->fenc->param )
{
- x264_encoder_reconfig( h, h->fenc->param );
+ x264_encoder_reconfig_apply( h, h->fenc->param );
if( h->fenc->param->param_free )
{
h->fenc->param->param_free( h->fenc->param );
@@ -4218,6 +4251,7 @@ void x264_encoder_close ( x264_t *h )
x264_cqm_delete( h );
x264_free( h->nal_buffer );
+ x264_free( h->reconfig_h );
x264_analyse_free_costs( h );
if( h->i_thread_frames > 1 )
diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c
index 1e98f92..8bb871a 100644
--- a/encoder/ratecontrol.c
+++ b/encoder/ratecontrol.c
@@ -1398,7 +1398,7 @@ void x264_ratecontrol_start( x264_t *h, int i_force_qp, int overhead )
x264_emms();
if( zone && (!rc->prev_zone || zone->param != rc->prev_zone->param) )
- x264_encoder_reconfig( h, zone->param );
+ x264_encoder_reconfig_apply( h, zone->param );
rc->prev_zone = zone;
if( h->param.rc.b_stat_read )
diff --git a/encoder/ratecontrol.h b/encoder/ratecontrol.h
index 02d30d6..9306b27 100644
--- a/encoder/ratecontrol.h
+++ b/encoder/ratecontrol.h
@@ -43,6 +43,7 @@ int x264_ratecontrol_new ( x264_t * );
void x264_ratecontrol_delete( x264_t * );
void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init );
+int x264_encoder_reconfig_apply( x264_t *h, x264_param_t *param );
void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame, float *quant_offsets );
int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offsets );
diff --git a/x264.c b/x264.c
index 783b74d..bcbbcdd 100644
--- a/x264.c
+++ b/x264.c
@@ -1589,8 +1589,11 @@ generic_option:
info.fps_den = param->i_fps_den;
info.fullrange = input_opt.input_range == RANGE_PC;
info.interlaced = param->b_interlaced;
- info.sar_width = param->vui.i_sar_width;
- info.sar_height = param->vui.i_sar_height;
+ if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 )
+ {
+ info.sar_width = param->vui.i_sar_width;
+ info.sar_height = param->vui.i_sar_height;
+ }
info.tff = param->b_tff;
info.vfr = param->b_vfr_input;
@@ -1633,7 +1636,7 @@ generic_option:
#endif
/* override detected values by those specified by the user */
- if( param->vui.i_sar_width && param->vui.i_sar_height )
+ if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 )
{
info.sar_width = param->vui.i_sar_width;
info.sar_height = param->vui.i_sar_height;
More information about the x264-devel
mailing list