| 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 event |
| 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 |
| for 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 sent directly on |
| the downstream blocking element/pad so that it releases the stream lock, and it |
| gives a chance for the elem1.src pad to block. |
| |
| |
| 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 that point nothing is 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. |
| 4d) remove the EOS pad event probe. |
| 5) unlink element2 and element3 |
| 5a) optionally element2 can now be set to NULL and/or removed from the |
| pipeline. |
| 6) link element4 and element3 |
| 7) link element1 and element4 (FIXME, how about letting element4 know |
| about the currently running segment?, see issues.) |
| 8) make sure element4 is in the same state as the rest of the elements. The |
| element should at least be PAUSED. |
| 9) 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. |
| |