[Bug] mb_info_free is called before all threads are done using mb_info
encoder/encoder.c
currently looks like the following:
x264_threadslice_cond_broadcast( h, 2 );
/* Do the first row of hpel, now that the previous slice is done */
if( h->i_thread_idx > 0 )
{
x264_threadslice_cond_wait( h->thread[h->i_thread_idx-1], 2 );
fdec_filter_row( h, h->i_threadslice_start + (1 << SLICE_MBAFF), 2 );
}
[....]
if( h->fdec->mb_info_free && (!h->param.b_sliced_threads || h->i_thread_idx == (h->param.i_threads-1)) )
{
h->fdec->mb_info_free( h->fdec->mb_info );
h->fdec->mb_info = NULL;
h->fdec->mb_info_free = NULL;
}
}
Consider a case with at least three threads:
- Thread 0 is lagging behind the other threads and still in the x264_macroblock_analyse(...) method.
- Thread 1 is almost done and signals thread 2, then waits on thread 0 to signal in turn.
- Thread 2 receives the green from thread 1 and goes on to call mb_info_free(...).
- Thread 0 gets a SEGV if it checks for mb_info in the x264_macroblock_analyse(...).
A fix is for each thread to first wait (except for thread 0) then signal.
A possible fix is the following:
diff --git a/encoder/encoder.c b/encoder/encoder.c
index cf0da680..5db8d95e 100644
--- a/encoder/encoder.c
+++ b/encoder/encoder.c
@@ -3108,11 +3108,15 @@ cont:
/* Do hpel now */
for( int mb_y = h->i_threadslice_start; mb_y <= h->i_threadslice_end; mb_y++ )
fdec_filter_row( h, mb_y, 1 );
- x264_threadslice_cond_broadcast( h, 2 );
- /* Do the first row of hpel, now that the previous slice is done */
- if( h->i_thread_idx > 0 )
+
+ if( h->i_thread_idx == 0 ) {
+ x264_threadslice_cond_broadcast( h, 2 );
+ }
+ else
{
x264_threadslice_cond_wait( h->thread[h->i_thread_idx-1], 2 );
+ x264_threadslice_cond_broadcast( h, 2 );
+ /* Do the first row of hpel, now that the previous slice is done */
fdec_filter_row( h, h->i_threadslice_start + (1 << SLICE_MBAFF), 2 );
}
}