[FFmpeg-devel] [PATCH] ffplay: fix a crash caused by aborting the video queue
Marton Balint
cus at passwd.hu
Sat Aug 27 22:13:12 CEST 2011
On Sun, 28 Aug 2011, avcoder wrote:
> On Sun, Aug 28, 2011 at 1:26 AM, Marton Balint <cus at passwd.hu> wrote:
>>
>> On Sun, 28 Aug 2011, avcoder wrote:
>>
>>> On Sun, Aug 28, 2011 at 12:40 AM, Marton Balint <cus at passwd.hu> wrote:
>>>>
>>>> On Sat, 27 Aug 2011, avcoder wrote:
>>>>
>>>>> On Sat, Aug 27, 2011 at 6:09 PM, Marton Balint <cus at passwd.hu> wrote:
>>>>>>
>>>>>> Yes, the patch description is probably not entirely correct, sorry, my
>>>>>> mistake. The thought of changing w_index somehow remained in my mind
>>>>>> from
>>>>>> the time I debugged this.
>>>>>>
>>>>>> The main problem with the code is that multiple ALLOC events may occur
>>>>>> at
>>>>>> the same time if we don't pop them from the event queue on abort. If
>>>>>> these
>>>>>> alloc events tries to allocate the same vp, vp->bmp changes (free-d,
>>>>>> and
>>>>>> the
>>>>>> then allocated again), I typically got the crash when
>>>>>> SDL_LockYUVOverlay(vp->bmp) was called from the video thread, after
>>>>>> SDL_FreeYUVOverlay(vp->bmp) was called from the main thread.
>>>>>
>>>>> Why do you get multiple ALLOC envents?
>>>>>
>>>>> I checked the ALLOC events, FF_ALLOC_EVENT is only pushed in
>>>>> "queue_picture()" which is called by "video_thread()", it is
>>>>> impossible to have MULTIPLE FF_ALLOC_EVENT.
>>>>
>>>> When you abort the video queue, an ALLOC event may be in the event queue.
>>>> When another video_thread() is stared (e.g. when changing the video
>>>> stream)
>>>> the event from the first video_thread may still be in the queue.
>>>>
>>>
>>> OK, that's the point.
>>>
>>> But this scenario has no relationship with your previous explanation
>>> -----'if these alloc events tries to allocate the same vp...., "
>>> The vp is not same if you start another video_thread(). so there's no
>>> scenario to produce your bug: " I typically got the crash when
>>> SDL_LockYUVOverlay(vp->bmp) was called from the video thread, after
>>> SDL_FreeYUVOverlay(vp->bmp) was called from the main thread."
>>>
>>> Your patch is harmless, but useless.
>>>
>>
>> I don't agree, because with my patch, alloc_picture and SDL_LockYUVOverlay
>> of queue_picture cannot run at the same time, therefore there is no chance
>> that SDL_LockYUVOverlay will do a lock using a currently freed pointer,
>> which may be the case, if SDL_LockYUVOverlay happens when the main thread is
>> in the middle of alloc_picture.
>
>
> SDL_LockYUVOverlay has no chance to happens when the main thread is in
> the middle of alloc_picture in the original implementation
>
> there are serialization.
>
> /* alloc or resize hardware picture buffer */
> if (!vp->bmp ||
> #if CONFIG_AVFILTER
> vp->width != is->out_video_filter->inputs[0]->w ||
> vp->height != is->out_video_filter->inputs[0]->h) {
> #else
> vp->width != is->video_st->codec->width ||
> vp->height != is->video_st->codec->height) {
> #endif
> SDL_Event event;
>
> vp->allocated = 0;
>
> /* the allocation must be done in the main thread to avoid
> locking problems */
> event.type = FF_ALLOC_EVENT;
> event.user.data1 = is;
> SDL_PushEvent(&event);
>
> // ----------------------- code a--------------------------------------
> /* wait until the picture is allocated */
> SDL_LockMutex(is->pictq_mutex);
> while (!vp->allocated && !is->videoq.abort_request) {
> SDL_CondWait(is->pictq_cond, is->pictq_mutex);
> }
> SDL_UnlockMutex(is->pictq_mutex);
>
> // -----------------------code b --------------------------------------
> if (is->videoq.abort_request)
> return -1;
> }
>
> /* if the frame is not skipped, then display it */
> if (vp->bmp) {
> AVPicture pict;
> #if CONFIG_AVFILTER
> if(vp->picref)
> avfilter_unref_buffer(vp->picref);
> vp->picref = src_frame->opaque;
> #endif
>
> // ----------------------------code c-----------------------------------
> /* get a pointer on the bitmap */
> SDL_LockYUVOverlay (vp->bmp);
>
> memset(&pict,0,sizeof(AVPicture));
> pict.data[0] = vp->bmp->pixels[0];
> pict.data[1] = vp->bmp->pixels[2];
> pict.data[2] = vp->bmp->pixels[1];
>
> pict.linesize[0] = vp->bmp->pitches[0];
> pict.linesize[1] = vp->bmp->pitches[2];
> pict.linesize[2] = vp->bmp->pitches[1];
>
> ......
>
> }
>
>
> 'code c' and 'alloc_picture()' can be concurrent only in abort mode,
> but 'code b ' prevent them.
'Code b' only prevents the lock in the aborted thread. It does not prevent
the lock when a new video_thread is spawned, and videoq.abort_request is
no longer set. In the freshly spawned video_thread the code execution goes
through 'code a', because the alloc event from the aborted thread
may only be processed after posting of the second alloc event.
Regards,
Marton
>
>
> --
> -----------------------------------------------------------------------------------------
> My key fingerprint: d1:03:f5:32:26:ff:d7:3c:e4:42:e3:51:ec:92:78:b2
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
More information about the ffmpeg-devel
mailing list