From 350b214c5abe7e82618ac46a14f23b7ab543045e Mon Sep 17 00:00:00 2001 From: Anton Mitrofanov Date: Sun, 27 Oct 2013 15:22:51 +0400 Subject: [PATCH] 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. --- 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 c9f7bf0e..9e05525c 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 52392269..90c8d78e 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 @@ -1755,6 +1763,25 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param ) return ret; } +/**************************************************************************** + * 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: ****************************************************************************/ @@ -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 f1f165b9..fe087583 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 02d30d60..9306b27d 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 8a0a3320..0aeec056 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; -- 2.40.0