After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 758257 - adaptivedemux: don't expose pads until caps are known
adaptivedemux: don't expose pads until caps are known
Status: RESOLVED FIXED
Product: GStreamer
Classification: Platform
Component: gst-plugins-bad
git master
Other Linux
: Normal enhancement
: 1.11.2
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2015-11-18 04:44 UTC by Jan Schmidt
Modified: 2017-02-07 13:36 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
adaptivedemux: Preroll streams before exposing them (12.89 KB, patch)
2015-11-27 14:46 UTC, Jan Schmidt
none Details | Review
adaptivedemux: Preroll streams before exposing them (13.29 KB, patch)
2015-12-02 16:11 UTC, Sebastian Dröge (slomo)
needs-work Details | Review
urisourcebin: Block demuxer's srcpad until get caps event (4.02 KB, patch)
2017-01-06 14:06 UTC, Seungha Yang
none Details | Review
[REBASE] adaptivedemux: Preroll streams before exposing them (12.99 KB, patch)
2017-01-07 10:57 UTC, Seungha Yang
none Details | Review
adaptivedemux: Block prerolling pads until exposed (6.19 KB, patch)
2017-01-07 11:00 UTC, Seungha Yang
none Details | Review
adaptivedemux: Activates only necessary thread's task (3.09 KB, patch)
2017-01-07 11:00 UTC, Seungha Yang
none Details | Review
adaptivedemux: Prepare GstSegment on only streams which are being prepared (1.07 KB, patch)
2017-01-10 12:35 UTC, Seungha Yang
none Details | Review
adaptivedemux: Activates only necessary thread's task (4.21 KB, patch)
2017-01-10 12:36 UTC, Seungha Yang
none Details | Review
adaptivedemux: Don't release manifest_lock before calling _expose_streams() (1.11 KB, patch)
2017-01-10 12:36 UTC, Seungha Yang
none Details | Review
adaptivedemux: Remove duplicated calling of _expose_streams() (1018 bytes, patch)
2017-01-10 12:37 UTC, Seungha Yang
none Details | Review
adaptivedemux: Release block after removing oldstreams (1.58 KB, patch)
2017-01-10 12:37 UTC, Seungha Yang
none Details | Review
adaptivedemux: Ensure setting caps before exposing pad (1.04 KB, patch)
2017-01-10 12:38 UTC, Seungha Yang
none Details | Review
adaptivedemux: Start download task depending on target streams (1.45 KB, patch)
2017-01-10 13:22 UTC, Seungha Yang
none Details | Review

Description Jan Schmidt 2015-11-18 04:44:49 UTC
In implementing decodebin3, it's causing me pain that when it switches bitrates, adaptivedemux immediately adds new pads and removes old ones, but the caps on the new pads aren't known until some time later when HTTP data arrives. That increases the window in which the demuxer is not connected to anything, when in fact if we know the caps, we could immediately splice the output onto an existing demuxer, parser or decoder.

My plan is:

1) Block all new streams. Keep a counter of number of pending streams.
   Store block-id on the Stream structure
2) When all new streams pre-roll (blocked => pending--, when pending == 0), unblock and expose them
3) Send EOS and remove old pads after new pads are exposed.                            
4) When handling a seek, unblock any blocked streams so the seek can be processed.

Anyone see any problems?
Comment 1 Jan Schmidt 2015-11-27 14:46:47 UTC
Created attachment 316388 [details] [review]
adaptivedemux: Preroll streams before exposing them

To ensure that pads have caps when they are exposed, do
the exposing when all pending streams have prerolled an
output buffer, and only then EOS and remove any old pads.

Improves the switching sequence by making caps available
as soon as a pad appears.
Comment 2 Sebastian Dröge (slomo) 2015-12-02 11:36:13 UTC
Makes sense to me, let's go ahead with this and give it some wider testing? But with dash, can't we know the caps immediately from the Manifest anyway, so won't have to wait until actual data is available?
Comment 3 Sebastian Dröge (slomo) 2015-12-02 11:39:25 UTC
For DASH at least, for HLS we don't and typefind. So maybe needs two code paths? Ideally exposing pads immediately for DASH would be nice.
Comment 4 Sebastian Dröge (slomo) 2015-12-02 15:08:32 UTC
This seems to break seeking in multi-period DASH streams btw
Comment 5 Sebastian Dröge (slomo) 2015-12-02 16:11:49 UTC
Created attachment 316666 [details] [review]
adaptivedemux: Preroll streams before exposing them

To ensure that pads have caps when they are exposed, do
the exposing when all pending streams have prerolled an
output buffer, and only then EOS and remove any old pads.

Improves the switching sequence by making caps available
as soon as a pad appears.
Comment 6 Sebastian Dröge (slomo) 2015-12-02 16:12:55 UTC
This fixes it for me, but I think the condition variable and the expose counter handling is a bit fragile. Probably needs to be reset in more cases, like in general when streams are disappearing.

But now I first have to look at a crash in dashdemux, exposed by this.
Comment 7 Sebastian Dröge (slomo) 2015-12-02 16:35:00 UTC
Also caused by this patch, when seeking between periods. The active_streams in the client are freed, but then later in the seeking code old active_stream is used.
Comment 8 Seungha Yang 2017-01-06 14:06:39 UTC
Created attachment 343022 [details] [review]
urisourcebin: Block demuxer's srcpad until get caps event

Unlike dashdemux, HLS demux needs delay to find type.
So, exposed pad might have NULL caps. For decision on slot reuse,
urisourcebin shouldn't push eos until getting caps event from pending pad.
Comment 9 Seungha Yang 2017-01-06 14:10:21 UTC
Hello slomo
I have trouble with same issue. I think that urisourcebin seems right element for handling this.
Comment 10 Sebastian Dröge (slomo) 2017-01-06 19:10:03 UTC
No, this should be done correctly in adaptivedemux so that it only exposes pads once it knows the caps. That's how other code expects demuxers to behave already.
Comment 11 Seungha Yang 2017-01-07 10:57:53 UTC
Created attachment 343078 [details] [review]
[REBASE] adaptivedemux: Preroll streams before exposing them
Comment 12 Seungha Yang 2017-01-07 11:00:18 UTC
Created attachment 343079 [details] [review]
adaptivedemux: Block prerolling pads until exposed

In download thread, event/buffer can be pushed before
the corresponding pad is exposed.
To ensure sequence, stream's srcpads will be blocked
until exposing newpads and removing oldpads are finished.
Comment 13 Seungha Yang 2017-01-07 11:00:57 UTC
Created attachment 343080 [details] [review]
adaptivedemux: Activates only necessary thread's task

Depending on current demuxer status, activates only needed thread.
For example, when demuxer is preroll state,
only new stream's downloading threads should be activated.
Comment 14 Seungha Yang 2017-01-07 11:05:47 UTC
(In reply to Sebastian Dröge (slomo) from comment #10)
> No, this should be done correctly in adaptivedemux so that it only exposes
> pads once it knows the caps. That's how other code expects demuxers to
> behave already.

On top of "adaptive demux: Preroll streams before exposing them" patch, my two more patches can fix this issue by adaptivedemux itself
Comment 15 Jan Schmidt 2017-01-09 13:05:54 UTC
Review of attachment 343079 [details] [review]:

I don't understand this patch. My previous patch split the prepare_streams and expose_streams steps into 2 functions, and only calls expose when a buffer is seen.

The problem with blocking inside expose_streams() as well is that it will block an application seek() thread (usually the main thread) for an unknown length of time until data has been downloaded from the server, or a timeout if data doesn't arrive for a long time.

The parts of the patch about storing events as sticky events seem OK as an optimisation, but shouldn't have fixed any actual bug afaict.

I suspect the only part we actually need is the part that moves clearing the do_block flag after removing old pads?
Comment 16 Jan Schmidt 2017-01-09 13:10:13 UTC
Review of attachment 343080 [details] [review]:

Generally seems OK. The other patches need to land first.

::: gst-libs/gst/adaptivedemux/gstadaptivedemux.c
@@ +278,3 @@
 
+static void gst_adaptive_demux_start_tasks (GstAdaptiveDemux * demux,
+    gboolean is_preroll);

Instead of 'is_preroll', call the variable 'start_preroll_streams' please - I think it's clearer.
Comment 17 Jan Schmidt 2017-01-09 13:10:36 UTC
Review of attachment 343079 [details] [review]:

I don't understand this patch. My previous patch split the prepare_streams and expose_streams steps into 2 functions, and only calls expose when a buffer is seen.

The problem with blocking inside expose_streams() as well is that it will block an application seek() thread (usually the main thread) for an unknown length of time until data has been downloaded from the server, or a timeout if data doesn't arrive for a long time.

The parts of the patch about storing events as sticky events seem OK as an optimisation, but shouldn't have fixed any actual bug afaict.

I suspect the only part we actually need is the part that moves clearing the do_block flag after removing old pads?
Comment 18 Seungha Yang 2017-01-10 05:36:26 UTC
(In reply to Jan Schmidt from comment #17)
> Review of attachment 343079 [details] [review] [review]:

> I suspect the only part we actually need is the part that moves clearing the
> do_block flag after removing old pads?
Not only clearing "do_block" parts, calling _expose_streams() in main thread seems to be needed.

Frankly speaking, I'm not sure why your original patch does not work on master version. Maybe, I suspect that calling _expose_streams() in downloading thread might causes some issues and always calling it in downloading thread seems not to be unsafe. I'm keep debugging now, though.

Main concept of my first patch is, calling _start_task() and _expose_streams() on main thread, and then, waiting until "preroll complete" (notifyed by download thread)

What is your opinion? Any way, I'll split my patch into several parts for easy review.
Comment 19 Jan Schmidt 2017-01-10 07:32:50 UTC
If there's a problem calling expose_streams() in the downloading thread, we should work out what it is. Can you explain how / when it goes wrong for you?

The problem with your patch is that it a) calls expose_streams() from the main thread and then b) that blocks until all the pads complete preroll anyway (preroll_pending reaches 0).

There's no way to know how long that might block - with a slow internet connection it could be a very long time. The call to expose_streams has to happen from the streaming thread IMO - or we could use an auxilliary thread if there's really no way to make that reliable.
Comment 20 Seungha Yang 2017-01-10 12:35:58 UTC
Created attachment 343232 [details] [review]
adaptivedemux: Prepare GstSegment on only streams which are being prepared

GstSegment is required for currently preparing stream,
not for already existing streams.
Comment 21 Seungha Yang 2017-01-10 12:36:31 UTC
Created attachment 343233 [details] [review]
adaptivedemux: Activates only necessary thread's task

Depending on current demuxer status, activates only needed thread.
For example, when demuxer is preroll state,
only new stream's downloading threads should be activated.
Comment 22 Seungha Yang 2017-01-10 12:36:59 UTC
Created attachment 343234 [details] [review]
adaptivedemux: Don't release manifest_lock before calling _expose_streams()

Inside of _expose_streams(), manifest_lock will be released.
Comment 23 Seungha Yang 2017-01-10 12:37:22 UTC
Created attachment 343235 [details] [review]
adaptivedemux: Remove duplicated calling of _expose_streams()

Because it will be called by _prepare_streams() in download thread
Comment 24 Seungha Yang 2017-01-10 12:37:56 UTC
Created attachment 343236 [details] [review]
adaptivedemux: Release block after removing oldstreams

In order for parentbin (e.g., uriosourcebin) to know it's stream change case,
nothing should be pushed to downstream until pushing eos
to oldstreams' pads or removing the pads
Comment 25 Seungha Yang 2017-01-10 12:38:23 UTC
Created attachment 343237 [details] [review]
adaptivedemux: Ensure setting caps before exposing pad

If not, exposed pad will have ANY caps
Comment 26 Seungha Yang 2017-01-10 12:42:48 UTC
(In reply to Jan Schmidt from comment #19)
> If there's a problem calling expose_streams() in the downloading thread, we
> should work out what it is. Can you explain how / when it goes wrong for you?

It was simple double mutex release issue :)
Please refer to attachment 343234 [details] [review]

> There's no way to know how long that might block - with a slow internet
> connection it could be a very long time. The call to expose_streams has to
> happen from the streaming thread IMO - or we could use an auxilliary thread
> if there's really no way to make that reliable.

OK, Thanks for your detailed comment :) I maintained your structure, and just fixed some other minor issues. Please review my patches.
Comment 27 Jan Schmidt 2017-01-10 12:55:49 UTC
Thanks, these all look good. If it's OK with you, I'd prefer to squash them all into my original commit and just add attribution when pushing them to git.

Thank you for splitting it up though, much easier to review.
Comment 28 Seungha Yang 2017-01-10 13:04:31 UTC
(In reply to Jan Schmidt from comment #27)
> Thanks, these all look good. If it's OK with you, I'd prefer to squash them
> all into my original commit and just add attribution when pushing them to
> git.
> 
> Thank you for splitting it up though, much easier to review.

Sure, you can squash them into yours.
Comment 29 Seungha Yang 2017-01-10 13:22:12 UTC
Created attachment 343242 [details] [review]
adaptivedemux: Start download task depending on target streams

Choose suitable target streams
Comment 30 Seungha Yang 2017-01-10 13:22:33 UTC
There is one more fix
Comment 31 Seungha Yang 2017-02-01 14:20:26 UTC
Hello Jan Schmidt

If there is no more known issue, can we merge this on master branch and open to other developers? I think this approach must be accepted for playbin3 pipeline :)
Comment 32 Jan Schmidt 2017-02-07 13:36:46 UTC
Squashed and pushed:

commit b2113f69c622c37c32d4336025f80a5c1d190897
Author: Jan Schmidt <jan@centricular.com>
Date:   Sat Jan 7 12:12:05 2017 +0900

    adaptivedemux: Preroll streams before exposing them
    
    To ensure that pads have caps when they are exposed, do
    the exposing when all pending streams have prerolled an
    output buffer, and only then EOS and remove any old pads.
    
    Improves the switching sequence by making caps available
    as soon as a pad appears.
    
    With fixes from Seungha Yang <sh.yang@lge.com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=758257

I think there's more things to fix - but this code seems OK for the dev branch. Thanks for fixing up my code, and for your persistence!