mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 08:17:01 +00:00
8923a57a6f
Original commit message from CVS: * docs/design/part-block.txt: Further explain the use of flushing on blocked pads. * docs/gst/gstreamer-sections.txt: * gst/gstpad.c: (gst_pad_is_blocking), (handle_pad_block), (gst_pad_push_event): * gst/gstpad.h: Added new GstPadFlag : GST_PAD_BLOCKING. Adds the notion of pads really blocking, which enables to properly handle FLUSH_START/FLUSH_STOP events on blocked pads. Fixes #358999 API: gst_pad_is_blocking() API: GST_PAD_IS_BLOCKING() macro API: GST_PAD_BLOCKING GstPadFlag
164 lines
6.1 KiB
Text
164 lines
6.1 KiB
Text
Pad block
|
|
---------
|
|
|
|
The purpose of blocking a pad is to be notified of downstream dataflow
|
|
and events. The notification can be used for
|
|
|
|
- (Re)connecting/disconnecting the pad.
|
|
- performing a seek
|
|
- inspecting the data/events on the pad
|
|
|
|
The pad block is performed on a source pad (push based) or sink pad (pull based)
|
|
and will succeed when the following events happen on the pad:
|
|
|
|
- gst_pad_push()
|
|
- gst_pad_alloc_buffer()
|
|
- gst_pad_push_event() except for FLUSH_START and FLUSH_STOP events.
|
|
- gst_pad_pull_range () (on a sinkpad)
|
|
|
|
|
|
Flushing
|
|
--------
|
|
|
|
The flushing event is used to clear any data out of the
|
|
downstream elements.
|
|
|
|
* Generic case
|
|
|
|
Consider the following pipeline:
|
|
|
|
.-----. .-------. .-------.
|
|
| src | | elem1 |\/ | elem2 |
|
|
| src -> sink src -> sink src ....
|
|
'-----' '-------'/\ '-------'
|
|
|
|
Where elem1.src is blocked. If the pad block is taken (the callback
|
|
is called or the sync block returned) no data is flowing in elem2.sink.
|
|
In this situation, the streaming thread is blocked on a GCond and is
|
|
waiting to be unblocked.
|
|
|
|
When sending a flushing seek upstream on elem1.src, the FLUSH_START and
|
|
will temporary unblock the streaming thread and make all pad functions that
|
|
triggers a block (_push/_alloc_buffer/_push_event/_pull_range) return
|
|
GST_FLOW_WRONG_STATE. This will then eventually pause the streaming thread
|
|
and release the STREAM_LOCK.
|
|
|
|
Since no STREAM lock is taken after the pad block it is not needed to send
|
|
the FLUSH_START event further downstream.
|
|
|
|
The FLUSH_STOP will set the srcpad to non-flushing again and is dropped
|
|
fr the same reason. From then on, the new data after the flushing seek
|
|
will be queued when the pad block is taken again.
|
|
|
|
* Case where the stream is blocking downstream
|
|
|
|
The example above is only valid if the elem1.src pad is really blocking
|
|
(callback called or sync block returned).
|
|
|
|
In the case where the stream is blocking further downstream (on elem2.src
|
|
for example, or on a blocking queue), extra care has to be taken.
|
|
|
|
Consider the following pipeline:
|
|
|
|
.-----. .-------. .-------.
|
|
| src | | elem1 |\/ | elem2 |
|
|
| src -> sink src -> sink src .... Blocking somewhere downstream
|
|
'-----' '-------'/\ '-------'
|
|
|
|
A pad block has been requested by the user on elem1.src , but since the stream
|
|
is blocking somewhere downstream, the callback is not called or the sync block
|
|
does not return.
|
|
|
|
In order for the block to happen, a FLUSH_START needs to be:
|
|
_ either sent directly on the downstream blocking element/pad so that it
|
|
release the stream lock, and it gives a chance for the elem1.src pad to
|
|
block.
|
|
_ A FLUSH_START is sent downstream from an upstream element, causing all the
|
|
pads down to the blocking element/pad (including elem1.src) to go to the
|
|
FLUSHING state. A FLUSH_STOP can now be sent downstream, causing all the
|
|
pads down to the previously blocking element to unset their FLUSHING state.
|
|
The next push will then properly block on elem1.src.
|
|
|
|
In this case, the pads have to be careful when handling the FLUSH events
|
|
forwarding. Those events should only be forwarded downstream is the BLOCKED
|
|
pad was previously BLOCKING.
|
|
|
|
|
|
Use cases:
|
|
----------
|
|
|
|
* Prerolling a partial pipeline
|
|
|
|
.---------. .---------. .----------.
|
|
| filesrc | | demuxer | .-----. | decoder1 |
|
|
| src -> sink src1 ->|queue|-> sink src
|
|
'---------' | | '-----' '----------' X
|
|
| | .----------.
|
|
| | .-----. | decoder2 |
|
|
| src2 ->|queue|-> sink src
|
|
'---------' '-----' '----------' X
|
|
|
|
|
|
The purpose is to create the pipeline dynamically up to the
|
|
decoders but not yet connect them to a sink and without losing
|
|
any data.
|
|
|
|
To do this, the source pads of the decoders is blocked so that no
|
|
events or buffers can escape and we don't interrupt the stream.
|
|
|
|
When all of the dynamic pad are created (no-more-pads emited by the
|
|
branching point, ie, the demuxer or the queues filled) and the pads
|
|
are blocked (blocked callback received) the pipeline is completely
|
|
prerolled.
|
|
|
|
It should then be possible to perform the following actions on the
|
|
prerolled pipeline:
|
|
|
|
- query duration/position
|
|
- perform a flushing seek to preroll a new position
|
|
- connect other elements and unblock the blocked pads.
|
|
|
|
|
|
* dynamically switching an element in a PLAYING pipeline.
|
|
|
|
|
|
.----------. .----------. .----------.
|
|
| element1 | | element2 | | element3 |
|
|
... src -> sink src -> sink ...
|
|
'----------' '----------' '----------'
|
|
.----------.
|
|
| element4 |
|
|
sink src
|
|
'----------'
|
|
|
|
The purpose is to replace element2 with element4 in the PLAYING
|
|
pipeline.
|
|
|
|
1) block element1 src pad. This can be done async.
|
|
2) wait for block to happen. at this point nothing flowing between
|
|
element1 and element2 and nothing will flow until unblocked.
|
|
3) unlink element1 and element2
|
|
4) optional step: make sure data is flushed out of element2:
|
|
4a) pad event probe on element2 src
|
|
4b) send EOS to element2, this makes sure that element2 flushes
|
|
out the last bits of data it holds.
|
|
4c) wait for EOS to appear in the probe, drop the EOS.
|
|
5) unlink element2 and element3
|
|
5a) optionally element2 can now be set to NULL.
|
|
6) link element4 and element3
|
|
7) link element1 and element4 (FIXME, how about letting element4 know
|
|
about the currently running segment?)
|
|
8) unblock element1 src
|
|
|
|
The same flow can be used to replace an element in a PAUSED pipeline. Only
|
|
special care has to be taken when performing step 2) which has to be done
|
|
async or it might deadlock. In the async callback one can then perform the
|
|
steps from 3). In a playing pipeline one can of course use the async block
|
|
as well, so that there is a generic method for both PAUSED and PLAYING.
|
|
|
|
The same flow works as well for any chain of multiple elements and might
|
|
be implemented with a helper function in the future.
|
|
|
|
|
|
|
|
|