[FFmpeg-devel] [PATCH] submit_thread should also lock the mutex that guards the source avctx (prev_thread->avctx) when calling update_context_from_thread.

Wan-Teh Chang wtc at google.com
Fri Feb 26 23:35:09 CET 2016


On Fri, Feb 26, 2016 at 1:17 PM, Ronald S. Bultje <rsbultje at gmail.com> wrote:
>
> I'm happy to help out if you tell me which field/member tsan is complaining
> about.

Hi Ronald,

I am using an old version of ffmpeg. Here is the ThreadSanitizer
warning on the data race and the relevant source code from that ffmpeg
source tree.

The data race is reported on the |qscale| member of MpegEncContext.
(In the current version, the corresponding thing seems to be the
|qscale| member in H264SliceContext.)

I will also try to reproduce the data race with the current version of
ffmpeg. The relevant code in the current version looks similar, but it
is certainly possible that the data race is gone.

Thanks a lot for your help!

Wan-Teh Chang

==============================

WARNING: ThreadSanitizer: data race (pid=161600)
  Write of size 4 at 0x7f53af71a830 by thread T8 (mutexes: write M16537):
    #0 ff_h264_decode_mb_cabac ffmpeg/libavcodec/h264_cabac.c:2336:23
(754b7d528ac43192f37741068b3495f5+0x000000673706)
    #1 decode_slice ffmpeg/libavcodec/h264.c:3553:23
(754b7d528ac43192f37741068b3495f5+0x000000667e37)
    #2 execute_decode_slices ffmpeg/libavcodec/h264.c:3709:16
(754b7d528ac43192f37741068b3495f5+0x00000066691d)
    #3 decode_nal_units ffmpeg/libavcodec/h264.c:4010:17
(754b7d528ac43192f37741068b3495f5+0x000000633530)
    #4 decode_frame ffmpeg/libavcodec/h264.c:4132:17
(754b7d528ac43192f37741068b3495f5+0x00000064a6eb)
    #5 frame_worker_thread ffmpeg/libavcodec/pthread.c:389:21
(754b7d528ac43192f37741068b3495f5+0x00000098669f)

  Previous read of size 8 at 0x7f53af71a830 by main thread (mutexes:
write M16539):
    #0 memcpy llvm/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:685:5
(754b7d528ac43192f37741068b3495f5+0x0000000d6600)
    #1 ff_mpeg_update_thread_context
ffmpeg/libavcodec/mpegvideo.c:542:9
(754b7d528ac43192f37741068b3495f5+0x0000008e08e7)
    #2 decode_update_thread_context ffmpeg/libavcodec/h264.c:1178:11
(754b7d528ac43192f37741068b3495f5+0x00000064965a)
    #3 update_context_from_thread ffmpeg/libavcodec/pthread.c:462:19
(754b7d528ac43192f37741068b3495f5+0x000000983a5e)
    #4 submit_packet ffmpeg/libavcodec/pthread.c:563:15
(754b7d528ac43192f37741068b3495f5+0x000000982e0c)
    #5 ff_thread_decode_frame ffmpeg/libavcodec/pthread.c:624
(754b7d528ac43192f37741068b3495f5+0x000000982e0c)
    #6 avcodec_decode_video2 ffmpeg/libavcodec/utils.c:1565:19
(754b7d528ac43192f37741068b3495f5+0x000000a8e401)

Code snippets for the stack trace of the first thread (thread T8):

libavcodec/h264_cabac.c
2316         // decode_cabac_mb_dqp
2317         if(get_cabac_noinline( &h->cabac, &h->cabac_state[60 +
(h->last_qscale_diff != 0)])){
2318             int val = 1;
2319             int ctx= 2;
2320             const int max_qp = 51 + 6*(h->sps.bit_depth_luma-8);
2321
2322             while( get_cabac_noinline( &h->cabac,
&h->cabac_state[60 + ctx] ) ) {
2323                 ctx= 3;
2324                 val++;
2325                 if(val > 2*max_qp){ //prevent infinite loop
2326                     av_log(h->s.avctx, AV_LOG_ERROR, "cabac
decode of qscale diff failed at %d %d\n", s->mb_x, s->mb_y);
2327                     return -1;
2328                 }
2329             }
2330
2331             if( val&0x01 )
2332                 val=   (val + 1)>>1 ;
2333             else
2334                 val= -((val + 1)>>1);
2335             h->last_qscale_diff = val;
2336             s->qscale += val;
2337             if(((unsigned)s->qscale) > max_qp){
2338                 if(s->qscale<0) s->qscale+= max_qp+1;
2339                 else            s->qscale-= max_qp+1;
2340             }
2341             h->chroma_qp[0] = get_chroma_qp(h, 0, s->qscale);
2342             h->chroma_qp[1] = get_chroma_qp(h, 1, s->qscale);
2343         }else

libavcodec/h264.c (the first two code snippets are in
libavcodec/h264_slice.c in the current version):
3525 static int decode_slice(struct AVCodecContext *avctx, void *arg)
3526 {
3527     H264Context *h = *(void **)arg;
3528     MpegEncContext *const s = &h->s;
3529     const int part_mask     = s->partitioned_frame ? (ER_AC_END |
ER_AC_ERROR)
3530                                                    : 0x7F;
3531     int lf_x_start = s->mb_x;
3532
3533     s->mb_skip_run = -1;
3534
3535     h->is_complex = FRAME_MBAFF || s->picture_structure != PICT_FRAME ||
3536                     s->codec_id != AV_CODEC_ID_H264 ||
3537                     (CONFIG_GRAY && (s->flags & CODEC_FLAG_GRAY));
3538
3539     if (h->pps.cabac) {
3540         /* realign */
3541         align_get_bits(&s->gb);
3542
3543         /* init cabac */
3544         ff_init_cabac_states();
3545         ff_init_cabac_decoder(&h->cabac,
3546                               s->gb.buffer + get_bits_count(&s->gb) / 8,
3547                               (get_bits_left(&s->gb) + 7) / 8);
3548
3549         ff_h264_init_cabac_states(h);
3550
3551         for (;;) {
3552             // START_TIMER
3553             int ret = ff_h264_decode_mb_cabac(h);
3554             int eos;
3555             // STOP_TIMER("decode_mb_cabac")
3556
3557             if (ret >= 0)
3558                 ff_h264_hl_decode_mb(h);
...
3698 static int execute_decode_slices(H264Context *h, int context_count)
3699 {
3700     MpegEncContext *const s     = &h->s;
3701     AVCodecContext *const avctx = s->avctx;
3702     H264Context *hx;
3703     int i;
3704
3705     if (s->avctx->hwaccel ||
3706         s->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
3707         return 0;
3708     if (context_count == 1) {
3709         return decode_slice(avctx, &h);
3710     } else {
...
3997             case NAL_AUD:
3998             case NAL_END_SEQUENCE:
3999             case NAL_END_STREAM:
4000             case NAL_FILLER_DATA:
4001             case NAL_SPS_EXT:
4002             case NAL_AUXILIARY_SLICE:
4003                 break;
4004             default:
4005                 av_log(avctx, AV_LOG_DEBUG, "Unknown NAL code: %d
(%d bits)\n",
4006                        hx->nal_unit_type, bit_length);
4007             }
4008
4009             if (context_count == h->max_contexts) {
4010                 execute_decode_slices(h, context_count);
4011                 context_count = 0;
4012             }
...
4121     if (h->is_avc && av_packet_get_side_data(avpkt,
AV_PKT_DATA_NEW_EXTRADATA, NULL)) {
4122         int side_size;
4123         uint8_t *side = av_packet_get_side_data(avpkt,
AV_PKT_DATA_NEW_EXTRADATA, &side_size);
4124         if (is_extra(side, side_size))
4125             ff_h264_decode_extradata(h, side, side_size);
4126     }
4127     if(h->is_avc && buf_size >= 9 && buf[0]==1 && buf[2]==0 &&
(buf[4]&0xFC)==0xFC && (buf[5]&0x1F) && buf[8]==0x67){
4128         if(is_extra(buf, buf_size))
4129            return ff_h264_decode_extradata(h, buf, buf_size);
4130     }
4131
4132     buf_index = decode_nal_units(h, buf, buf_size);
4133     if (buf_index < 0)
4134         return -1;

libavcodec/pthread.c (this is in libavcodec/pthread_frame.c in the
current version of ffmpeg)
 368 static attribute_align_arg void *frame_worker_thread(void *arg)
 369 {
 370     PerThreadContext *p = arg;
 371     FrameThreadContext *fctx = p->parent;
 372     AVCodecContext *avctx = p->avctx;
 373     const AVCodec *codec = avctx->codec;
 374
 375     pthread_mutex_lock(&p->mutex);
 376     while (1) {
 377         int i;
 378             while (p->state == STATE_INPUT_READY && !fctx->die)
 379                 pthread_cond_wait(&p->input_cond, &p->mutex);
 380
 381         if (fctx->die) break;
 382
 383         if (!codec->update_thread_context &&
(avctx->thread_safe_callbacks || avctx->get_buffer ==
avcodec_default_get_buffer))
 384             ff_thread_finish_setup(avctx);
 385
 386         avcodec_get_frame_defaults(&p->frame);
 387         p->got_frame = 0;
 388         int did_split = av_packet_split_side_data(&p->avpkt);
 389         p->result = codec->decode(avctx, &p->frame,
&p->got_frame, &p->avpkt);
 390         if (did_split) {
 391             av_packet_free_side_data(&p->avpkt);
 392         }

Code snippets for the stack trace of the first thread (main thread):

libavcodec/mpegvideo.c
 531 int ff_mpeg_update_thread_context(AVCodecContext *dst,
 532                                   const AVCodecContext *src)
 533 {
 534     MpegEncContext *s = dst->priv_data, *s1 = src->priv_data;
 535
 536     if (dst == src)
 537         return 0;
 538
 539     // FIXME can parameters change on I-frames?
 540     // in that case dst may need a reinit
 541     if (!s->context_initialized) {
 542         memcpy(s, s1, sizeof(MpegEncContext));
 543
 544         s->avctx                 = dst;
 545         s->bitstream_buffer      = NULL;
 546         s->bitstream_buffer_size = s->allocated_bitstream_buffer_size = 0;
 547
 548         if (s1->context_initialized){
 549             s->picture_range_start  += MAX_PICTURE_COUNT;
 550             s->picture_range_end    += MAX_PICTURE_COUNT;
 551             ff_MPV_common_init(s);
 552         }
 553     }

libavcodec/h264.c (I can't quite figure out where this code is now. It
seems to be the ff_h264_update_thread_context function in
libavcodec/h264_slice.c)
1167 static int decode_update_thread_context(AVCodecContext *dst,
1168                                         const AVCodecContext *src)
1169 {
1170     H264Context *h = dst->priv_data, *h1 = src->priv_data;
1171     MpegEncContext *const s = &h->s, *const s1 = &h1->s;
1172     int inited = s->context_initialized, err;
1173     int i;
1174
1175     if (dst == src)
1176         return 0;
1177
1178     err = ff_mpeg_update_thread_context(dst, src);
1179     if (err)
1180         return err;
1181
1182     // FIXME handle width/height changing
1183     if (!inited) {
1184         for (i = 0; i < MAX_SPS_COUNT; i++)
1185             av_freep(h->sps_buffers + i);
1186
1187         for (i = 0; i < MAX_PPS_COUNT; i++)
1188             av_freep(h->pps_buffers + i);

libavcodec/pthread.c (this is in libavcodec/pthread_frame.c in the
current version of ffmpeg)
 424 static int update_context_from_thread(AVCodecContext *dst,
AVCodecContext *src, int for_user)
 425 {
 426     int err = 0;
 427
 428     if (dst != src) {
 429         dst->time_base = src->time_base;
 430         dst->width     = src->width;
 431         dst->height    = src->height;
 432         dst->pix_fmt   = src->pix_fmt;
...
 451         dst->color_trc   = src->color_trc;
 452         dst->colorspace  = src->colorspace;
 453         dst->color_range = src->color_range;
 454         dst->chroma_sample_location = src->chroma_sample_location;
 455     }
 456
 457     if (for_user) {
 458         dst->delay       = src->thread_count - 1;
 459         dst->coded_frame = src->coded_frame;
 460     } else {
 461         if (dst->codec->update_thread_context)
 462             err = dst->codec->update_thread_context(dst, src);
 463     }
 464
 465     return err;
 466 }
...
 541 static int submit_packet(PerThreadContext *p, AVPacket *avpkt)
 542 {
 543     FrameThreadContext *fctx = p->parent;
 544     PerThreadContext *prev_thread = fctx->prev_thread;
 545     const AVCodec *codec = p->avctx->codec;
 546     uint8_t *buf = p->avpkt.data;
 547
 548     if (!avpkt->size && !(codec->capabilities & CODEC_CAP_DELAY)) return 0;
 549
 550     pthread_mutex_lock(&p->mutex);
 551
 552     release_delayed_buffers(p);
 553
 554     if (prev_thread) {
 555         int err;
 556         if (prev_thread->state == STATE_SETTING_UP) {
 557             pthread_mutex_lock(&prev_thread->progress_mutex);
 558             while (prev_thread->state == STATE_SETTING_UP)
 559                 pthread_cond_wait(&prev_thread->progress_cond,
&prev_thread->progress_mutex);
 560             pthread_mutex_unlock(&prev_thread->progress_mutex);
 561         }
 562
 563         err = update_context_from_thread(p->avctx, prev_thread->avctx, 0);
 564         if (err) {
 565             pthread_mutex_unlock(&p->mutex);
 566             return err;
 567         }
 568     }
 569
 570     av_fast_malloc(&buf, &p->allocated_buf_size, avpkt->size +
FF_INPUT_BUFFER_PADDING_SIZE);
 571     p->avpkt = *avpkt;
 572     p->avpkt.data = buf;
 573     memcpy(buf, avpkt->data, avpkt->size);
 574     memset(buf + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
 575
 576     p->state = STATE_SETTING_UP;
 577     pthread_cond_signal(&p->input_cond);
 578     pthread_mutex_unlock(&p->mutex);
...
 608 int ff_thread_decode_frame(AVCodecContext *avctx,
 609                            AVFrame *picture, int *got_picture_ptr,
 610                            AVPacket *avpkt)
 611 {
 612     FrameThreadContext *fctx = avctx->thread_opaque;
 613     int finished = fctx->next_finished;
 614     PerThreadContext *p;
 615     int err;
 616
 617     /*
 618      * Submit a packet to the next decoding thread.
 619      */
 620
 621     p = &fctx->threads[fctx->next_decoding];
 622     err = update_context_from_user(p->avctx, avctx);
 623     if (err) return err;
 624     err = submit_packet(p, avpkt);
 625     if (err) return err;

libavcodec/utils.c
1543 int attribute_align_arg avcodec_decode_video2(AVCodecContext
*avctx, AVFrame *picture,
1544                                               int *got_picture_ptr,
1545                                               const AVPacket *avpkt)
1546 {
1547     int ret;
1548     // copy to ensure we do not change avpkt
1549     AVPacket tmp = *avpkt;
1550
1551     if (avctx->codec->type != AVMEDIA_TYPE_VIDEO) {
1552         av_log(avctx, AV_LOG_ERROR, "Invalid media type for video\n");
1553         return AVERROR(EINVAL);
1554     }
1555
1556     *got_picture_ptr = 0;
1557     if ((avctx->coded_width || avctx->coded_height) &&
av_image_check_size(avctx->coded_width, avctx->coded_height, 0,
avctx))
1558         return AVERROR(EINVAL);
1559
1560     if ((avctx->codec->capabilities & CODEC_CAP_DELAY) ||
avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
1561         int did_split = 0;
1562         apply_param_change(avctx, &tmp);
1563         avctx->pkt = &tmp;
1564         if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
1565             ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr,
1566                                          &tmp);
1567         else {
1568             did_split = av_packet_split_side_data(&tmp);
1569             ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
1570                                        &tmp);
1571             picture->pkt_dts             = avpkt->dts;
1572
1573             if(!avctx->has_b_frames){
1574                 picture->pkt_pos         = avpkt->pos;
1575             }
1576             //FIXME these should be under if(!avctx->has_b_frames)
1577             if (!picture->sample_aspect_ratio.num)
picture->sample_aspect_ratio = avctx->sample_aspect_ratio;
1578             if (!picture->width)                   picture->width
              = avctx->width;
1579             if (!picture->height)
picture->height              = avctx->height;
1580             if (picture->format == PIX_FMT_NONE)
picture->format              = avctx->pix_fmt;
1581         }


More information about the ffmpeg-devel mailing list