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

Zebediah Figura zfigura at codeweavers.com
Tue Sep 21 12:02:26 CDT 2021


On 9/21/21 9:36 AM, Francois Gouget wrote:
> On Wed, 15 Sep 2021, Zebediah Figura wrote:
> [...]
>> +static gboolean src_seek_data(GstElement *appsrc, guint64 offset, gpointer user)
>> +{
>> +    struct wg_parser *parser = user;
>>   
>> -    ret = parser->read_request.ret;
>> -    gst_buffer_set_size(*buffer, parser->read_request.size);
>> +    pthread_mutex_lock(&parser->mutex);
>> +
>> +    assert(!parser->read_request.pending);
> 
> quartz:mpegsplit randomly triggers this assertion.
> 
> https://bugs.winehq.org/show_bug.cgi?id=51774
> 
> https://test.winehq.org/data/patterns.html#quartz:mpegsplit
> 
> 

I had this brought to my attention by Gijs and ended up debugging it 
myself. The short version is that appsrc has even more problems than we 
thought. Unfortunately I did not carefully check the flushing code when 
reviewing.

The problem is that a flushing seek can both start and finish between 
wg_parser_get_next_read_offset and wg_parser_push_data. This will cause 
seek-data and need-data to be sent, then the flush will interrupt 
appsrc, after which it will send the same signals again. This isn't a 
problem in itself—we can just remove the assertion as it is in fact 
bogus—except that it means that, once again, we will be sending the 
wrong data.

Note that we can't validate the buffers sent ourself (i.e. do appsrc's 
job for it), because these buffers can be validated and sent before we 
even get seek-data, and yet can still be wrong.

There are two ways I see to fix this while still using appsrc, and both 
of them seem very janky:

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.

2. Send buffers synchronously from within need-data. Honestly I have to 
assume that the developers of appsrc only ever tried this case, even 
though they have documented that you can send data "from a separate 
thread". In this case we'd have to start flushing the read thread before 
and after seeking.

The other options we have are to remove appsrc. I had originally wanted 
to use appsrc for three reasons: first, it would abstract away most of 
the difference between push and pull mode; second, it would deal with 
pad activation and state change logic for us; and third, it would take 
care of all the nonsense surrounding flushing and synchronization so 
that we didn't have to do that. Unfortunately it is quickly turning out 
that the third part doesn't hold, and the first part holds less and less 
as well.

Based on that I see two more options:

3. Build our own element using basesrc. For seekable parsers this does 
still abstract away the difference between push and pull mode. For 
PE-level push mode (e.g. MFTs) it doesn't, and I'm not sure what the 
best move is there. We'd have to do about the same amount of work as 
solution #2, but at least we'd be working within clearly documented 
parameters, plus we actually have the ability to properly deal with 
flushes using the unlock/unlock_stop callbacks. The main downside here 
is that we have to deal with GLib OOP nonsense.

4. Go back to using a custom pad.



More information about the wine-devel mailing list