[PATCH v6 5/5] winegstreamer: Replace source pad interface with GstAppSrc.

Zebediah Figura (she/her) zfigura at codeweavers.com
Wed Sep 29 10:30:11 CDT 2021


On 9/29/21 02:59, Derek Lesho wrote:
> On 9/29/21 00:18, Zebediah Figura (she/her) wrote:
> 
>> On 9/28/21 03:08, Derek Lesho wrote:
>>>
>>> On 9/28/21 07:23, Zebediah Figura (she/her) wrote:
>>>> On 9/24/21 14:23, Derek Lesho wrote:
>>>>>
>>>>> On 9/24/21 12:38, Zebediah Figura wrote:
>>>>>> On 9/24/21 3:05 AM, Derek Lesho wrote:
>>>>>>> On 9/21/21 13:02, Zebediah Figura wrote:
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> 1. Rely on the fact that seek-data is sent during a seek, and 
>>>>>>>> use it
>>>>>>>> to effectively invalidate any buffers sent before the seek. 
>>>>>>>> Unlike the
>>>>>>>> aforementioned problem with validation, this will actually work: at
>>>>>>>> the time that seek-data is sent appsrc should be flushing, so any
>>>>>>>> buffers we send before it will be discarded by appsrc, and any 
>>>>>>>> buffers
>>>>>>>> we send afterward can be discarded by us if they aren't valid. 
>>>>>>>> This is
>>>>>>>> very fragile, though. There's really no reason for appsrc to send
>>>>>>>> seek-data for random-access streams in the first place, and this 
>>>>>>>> kind
>>>>>>>> of synchronization is easy to get wrong if I haven't already.
>>>>>>>
>>>>>>> This sounds like the best way forward in my opinion, how is it 
>>>>>>> fragile?
>>>>>>
>>>>>> It's fragile in general because we're making a lot of assumptions, 
>>>>>> that aren't documented, about when and from which thread gstappsrc 
>>>>>> will send these signals, and what synchronization guarantees it 
>>>>>> applies when doing so.
>>>>>
>>>>> My perspective is that if we can get it working, documenting the 
>>>>> two required quirks to the GStreamer project, eventually the 
>>>>> problem will be be cleared up and/or fixed, and we can remove the 
>>>>> quirks then.
>>>>
>>>> The problem is that we're still going to have to keep those 
>>>> workarounds for a long time. Not to mention that clearly filing a 
>>>> bug is not enough to get the attention of the GStreamer developers.
>>>>
>>>> As the maintainer of this code, I don't think I feel very 
>>>> comfortable relying this much on the internals of appsrc, whether as 
>>>> workarounds or not.
>>>>
>>>>>
>>>>>>
>>>>>>> It seems that if we just ensure that a pushed buffer takes into 
>>>>>>> account
>>>>>>> the latest seek/need data pair, not much can go wrong.
>>>>>>>
>>>>>>
>>>>>> That's not enough by itself. We can, generally speaking, send a 
>>>>>> buffer after a seek-data/need-data is triggered but before it is 
>>>>>> actually sent. 
>>>>> Before what is sent?
>>>>
>>>> Before the seek-data or need-data signal is sent. There is a window 
>>>> there, however short.
>>>
>>> I'm not sure exactly what the difference between triggering a signal 
>>> and sending a signal is, but assuming you mean that if seek-data 
>>> doesn't acquire the mutex, it would be possible to push-buffer to not 
>>> see the seek, then send the buffer after seek-data, then yeah, we do 
>>> need to put seek-data and push-buffer in the same mutex to make sure 
>>> that push-buffer is responding to the latest seek/need data callbacks.
>>>
>>>>
>>>>>> This happens in practice with flushes.
>>>>>>
>>>>>> In order to get around that, you need the hack I mentioned: assume 
>>>>>> that a flush will be accompanied by a seek-data signal. This is 
>>>>>> especially fragile because there's no reason for appsrc to even be 
>>>>>> sending this signal in the first place (it only really makes sense 
>>>>>> in "seekable" mode), and they could easily decide to not do that.
>>>>>
>>>>> I'm not sure I understand, whenever the next buffer app source 
>>>>> wants is not consecutively after the last, seek-data is required 
>>>>> (and sent). What does "assume the flush will be accompanied by a 
>>>>> seek-data signal" mean?  The app source client doesn't have any 
>>>>> conception of a flush, just seek-data and need-data, and to fix 
>>>>> this problem all we need to do is add a quite rational check that 
>>>>> push_data is responding to the latest seek/need data pair.
>>>>
>>>> Let me try to explain more clearly. At least one race, the one I've 
>>>> been trying to describe, looks like this:
>>>>
>>>>
>>>> read thread         main thread
>>>> -------------------------------------
>>>>                     push seek event
>>>> retrieve data
>>>> validate offset
>>>>                     send flush-start
>>>>                     emit seek-data
>>>>                     send flush-stop
>>>> push-buffer
>>>>
>>>>
>>>> At which point appsrc will get the wrong buffer.
>>>>
>>>> Solution 1 has us rely on the seek-data signal to effectively wait 
>>>> for the read thread (most likely using the parser mutex) and, in a 
>>>> sense, put a barrier between reads occuring before and after the flush.
>>>
>>>
>>> I mean, yeah, but from the perspective of the interface, all we are 
>>> doing is making sure that buffers that are responding to requests 
>>> from before a seek-data don't get sent, which I really don't think 
>>> should be too controversial.  That the seek happens to be caused by a 
>>> flush shouldn't matter, we're putting a barrier between buffers sent 
>>> for a different offset, and the current offset we've gotten from 
>>> seek-data. Honestly, I'm not even sure this is a GStreamer bug, 
>>> should they really have to handle a case where the client responds 
>>> with an incorrect buffer after a seek?
>>
>> I don't think this is obvious at all. It's certainly not called out in 
>> the documentation.
> The documentation does say "After receiving the seek-data signal, the 
> application should push-buffers from the new position."

There's quite a difference between that and "make sure that any old 
buffers are flushed out, and don't send any new buffers from the old 
position".

>> And, moreover, it's a lot of work, and it doesn't even look like a 
>> remotely idiomatic solution.
> As I've already said, making sure we don't push buffers to an old offset 
> after receiving a seek seems quite idiomatic to me.
>> Not to mention that, as I've said, appsrc really has no reason to send 
>> seek-data at all here.
> It sends it here to ensure that pre-flush buffers are discarded. After 
> it calls seek-data, it clears the queue, because of the aforementioned 
> expectation, namely that the app will respond to seek-data, this works.

Well, no, I don't think it does. I think it sends seek-data here for 
"seekable" mode, because that actually makes sense, and ends up also 
sending it for "random-access" mode unnecessarily.

>>
>> I'm pretty sure that you're correct that putting the whole of 
>> wg_parser_push_data inside a mutex, and the seek-data callback inside 
>> the same mutex, is actually sufficient to fix this race. But that 
>> stops being true if appsrc stops sending seek-data here.
> What reason would appsrc have to stop sending seek-data here, it has to 
> as far as I can see.
>>
>> Fundamentally the API contract here is that you don't send old buffers 
>> after a flush stops. DirectShow and GStreamer are both built on that 
>> idea. I believe that Media Foundation does away with it, which is one 
>> of the good things about Media Foundation. appsrc doesn't expose 
>> flushes to us, and it doesn't seem to do a good enough job of taking 
>> care of them itself.
> I think that requiring us not to send old buffers after seek-data and 
> sending seek-data when they flush, then discarding the rest of the queue 
> is a pretty good way of taking care of flushes.
>> Trying to infer when they happen is too fragile for my taste.
> We don't need to infer when they happen, all we need to do is follow the 
> guideline not to send buffers to a previous offset after seek-data.



More information about the wine-devel mailing list