design: Update/Cleanup the stream-selection design doc
authorEdward Hervey <edward@centricular.com>
Mon, 11 May 2020 06:43:06 +0000 (08:43 +0200)
committerEdward Hervey <bilboed@bilboed.com>
Mon, 11 May 2020 07:59:50 +0000 (09:59 +0200)
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-docs/-/merge_requests/87>

markdown/additional/design/stream-selection.md

index 6c59461..033f257 100644 (file)
 # Stream selection
 
-This document describes the events and objects involved in stream
-selection in GStreamer pipelines, elements and applications
+This document describes the events and objects involved in stream selection in
+GStreamer pipelines, elements and applications
 
-## History
+## History / Availability
+
+Since 1.10:
+* `GstStream` and `GstStreamCollection`
+* `enum GstStreamType`
+* `GST_EVENT_SELECT_STREAMS`, `GST_EVENT_STREAM_COLLECTION`,
+  `GST_MESSAGE_STREAMS_SELECTED`, `GST_MESSAGE_STREAM_COLLECTION`
+* `GstStream` present in `GST_EVENT_STREAM_START`
+
+Initial version: June 2015 (Edward Hervey)
+
+Last reviewed: May 2020 (Edward Hervey)
 
-```
-v0.1: Jun 11th 2015
-   Initial Draft
-v0.2: Sep 18th 2015
-   Update to reflect design changes
-v1.0: Jun 28th 2016
-   Pre-commit revision
-```
 
 ##  Background
 
-This new API is intended to address the use cases described in
-this section:
+This new API is *intended* to address the use cases described in this section:
+
+1) As a user/app I want an overview and control of the media streams that can be
+  configured within a pipeline for processing, even when some streams are
+  mutually exclusive or logical constructs only.
 
-1) As a user/app I want an overview and control of the media streams
-  that can be configured within a pipeline for processing, even
-  when some streams are mutually exclusive or logical constructs only.
+2) The user/app can disable entirely streams it's not interested in so they
+  don't occupy memory or processing power - discarded as early as possible in
+  the pipeline. The user/app can also (re-)enable them at a later time.
 
-2) The user/app can disable entirely streams it's not interested
-  in so they don't occupy memory or processing power - discarded
-  as early as possible in the pipeline. The user/app can also
-  (re-)enable them at a later time.
+3) If the set of possible stream configurations is changing, the user/app should
+  be aware of the pending change and be able to make configuration choices for
+  the new set of streams, as well as possibly still reconfiguring the old set
 
-3) If the set of possible stream configurations is changing,
-  the user/app should be aware of the pending change and
-  be able to make configuration choices for the new set of streams,
-  as well as possibly still reconfiguring the old set
+4) Elements that have some other internal mechanism for triggering stream
+  selections (DVD, or maybe some scripted playback playlist) should be able to
+  trigger 'selection' of some particular stream.
 
-4) Elements that have some other internal mechanism for triggering
-  stream selections (DVD, or maybe some scripted playback
-  playlist) should be able to trigger 'selection' of some particular
-  stream.
+5) Indicate known relationships between streams - for example that 2 separate
+  video feeds represent the 2 views of a stereoscopic view, or that certain
+  streams are mutually exclusive.
 
-5) Indicate known relationships between streams - for example that
-  2 separate video feeds represent the 2 views of a stereoscopic
-  view, or that certain streams are mutually exclusive.
+> Note: the streams that are "available" are not automatically the ones active,
+> or present in the pipeline as pads. Think HLS/DASH alternate streams.
 
-> Note: the streams that are "available" are not automatically
-> the ones active, or present in the pipeline as pads. Think HLS/DASH
-> alternate streams.
 
 ## Example use cases
 
-1) Playing an MPEG-TS multi-program stream, we want to tell the
- app that there are multiple programs that could be extracted
- from the incoming feed. Further, we want to provide a mechanism
- for the app to select which program(s) to decode, and once
- that is known to further tell the app which elementary streams
- are then available within those program(s) so the app/user can
- choose which audio track(s) to decode and/or use.
-
-2) A new PMT arrives for an MPEG-TS stream, due to a codec or
- channel change. The pipeline will need to reconfigure to
- play the desired streams from new program. Equally, there
- may be multiple seconds of content buffered from the old
- program and it should still be possible to switch (for example)
- subtitle tracks responsively in the draining out data, as
- well as selecting which subs track to play from the new feed.
- This same scenario applies when doing gapless transition to a
- new source file/URL, except that likely the element providing
- the list of streams also changes as a new demuxer is installed.
-
-3) When playing a multi-angle DVD, the DVD Virtual Machine needs to
- extract 1 angle from the data for presentation. It can publish
- the available angles as logical streams, even though only one
- stream can be chosen.
-
-4) When playing a DVD, the user can make stream selections from the
- DVD menu to choose audio or sub-picture tracks, or the DVD VM
- can trigger automatic selections. In addition, the player UI
- should be able to show which audio/subtitle tracks are available
- and allow direct selection in a GUI the same as for normal
- files with subtitle tracks in them.
-
-5) Playing a SCHC (3DTV) feed, where one view is MPEG-2 and the other
- is H.264 and they should be combined for 3D presentation, or
- not bother decoding 1 stream if displaying 2D.
- (bug https://bugzilla.gnome.org/show_bug.cgi?id=719333)
-
-FIXME - need some use cases indicating what alternate streams in
- HLS might require - what are the possibilities?
+1. Playing an MPEG-TS multi-program stream, we want to tell the app that there
+   are multiple programs that could be extracted from the incoming
+   feed.
+   
+   Furthermore, we want to provide a mechanism for the app to select which
+   program(s) to decode, and once that is known to further tell the app which
+   elementary streams are then available within those program(s) so the app/user
+   can choose which audio track(s) to decode and/or use.
+
+
+2. A new PMT arrives for an MPEG-TS stream, due to a codec or channel
+   change. The pipeline will need to reconfigure to play the desired streams
+   from new program. Equally, there may be multiple seconds of content buffered
+   from the old program and it should still be possible to switch (for example)
+   subtitle tracks responsively in the draining out data, as well as selecting
+   which subs track to play from the new feed.
+   
+   This same scenario applies when doing gapless transition to a new source
+   file/URL, except that likely the element providing the list of streams also
+   changes as a new demuxer is installed.
+
+
+3. When playing a multi-angle DVD, the DVD Virtual Machine needs to extract 1
+   angle from the data for presentation. It can publish the available angles as
+   logical streams, even though only one stream can be chosen.
+
+
+4. When playing a DVD, the user can make stream selections from the DVD menu to
+   choose audio or sub-picture tracks, or the DVD VM can trigger automatic
+   selections.
+   
+   In addition, the player UI should be able to show which audio/subtitle tracks
+   are available and allow direct selection in a GUI the same as for normal
+   files with subtitle tracks in them.
+
+
+5. Playing a SCHC (3DTV) feed, where one view is MPEG-2 and the other is H.264
+   and they should be combined for 3D presentation, or not bother decoding 1
+   stream if displaying 2D.  (bug
+   https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/118)
+
+
+**FIXME** - need some use cases indicating what alternate streams in HLS might
+ require - what are the possibilities?
+
 
 ## Design Overview
 
 Stream selection in GStreamer is implemented in several parts:
-1) Objects describing streams : `GstStream`
-2) Objects describing a collection of streams : `GstStreamCollection`
-3) Events from the app allowing selection and activation of some streams:
+
+1. Objects describing streams : `GstStream`
+2. Objects describing a collection of streams : `GstStreamCollection`
+3. Events from the app allowing selection and activation of some streams:
    `GST_EVENT_SELECT_STREAMS`
-4) Messages informing the user/application about the available
-   streams and current status: `GST_MESSAGE_STREAM_COLLECTION` and
+4. Messages informing the user/application about the available streams and
+   current status: `GST_MESSAGE_STREAM_COLLECTION` and
    `GST_MESSAGE_STREAMS_SELECTED`
 
+
 ##  GstStream objects
 
 API:
 
-```
-GstStream
+``` c
+typedef enum {
+  GST_STREAM_TYPE_UNKNOWN   = 1 << 0,
+  GST_STREAM_TYPE_AUDIO     = 1 << 1,
+  GST_STREAM_TYPE_VIDEO     = 1 << 2,
+  GST_STREAM_TYPE_CONTAINER = 1 << 3,
+  GST_STREAM_TYPE_TEXT      = 1 << 4
+} GstStreamType;
+
+struct {
+       const gchar *stream_id;
+} GstStream;
 
-gst_stream_new(...)
-gst_stream_get_*(...)
-gst_stream_set_*(...)
-gst_event_set_stream(...)
-gst_event_parse_stream(...)
+GstStream *gst_stream_new(...);
+
+GstStream *gst_stream_get_*(...);
+
+GstStream *gst_stream_set_*(...);
+
+GstStream *gst_event_set_stream(GstEvent *stream_start, GstStream *stream)
+
+void gst_event_parse_stream (GstEvent * event, GstStream ** stream);
 ```
 
-`GstStream` objects are a high-level convenience object containing
-information regarding a possible data stream that can be exposed by
-GStreamer elements.
+`GstStream` objects are a high-level convenience object containing information
+regarding a possible data stream that can be exposed by GStreamer elements.
+
+They are mostly the aggregation of information present in other GStreamer
+components (`STREAM_START`, `CAPS`, `TAGS` events) but are not tied to the
+presence of a `GstPad`, and for some use-cases provide information that the
+existing components don't provide.
 
-They are mostly the aggregation of information present in other
-GStreamer components (`STREAM_START`, `CAPS`, `TAGS` events) but are not
-tied to the presence of a `GstPad`, and for some use-cases provide
-information that the existing components don't provide.
 
-The various properties of a `GstStream` object are:
+The various properties (available via setters/getters) of a `GstStream` object
+are:
   - stream_id (from the `STREAM_START` event)
   - flags (from the `STREAM_START` event)
   - caps
   - tags
   - type (high-level type of stream: Audio, Video, Container,...)
 
-`GstStream` objects can be subclassed so that they can be re-used by
-elements already using the notion of stream (which is common for
-example in demuxers).
+
+`GstStream` objects can be subclassed so that they can be re-used by elements
+already using the notion of stream (which is common for example in demuxers).
+
+**Note**: While the intent of the design was indeed to allow providers to
+subclass `GstStream`, it turns out it is better to *not* subclass it. Stream
+providers should instead have separate structures to track their internal
+properties of streams, and use a separate `GstStream` for storing information
+they want to share.
+
 
 Elements that create `GstStream` should also set it on the
-`GST_EVENT_STREAM_START` event of the relevant pad. This helps
-downstream elements to have all information in one location.
+`GST_EVENT_STREAM_START` event of the relevant pad. This helps downstream
+elements have all information in one location.
+
 
 ## Exposing collections of streams
 
 API:
 
-```
-GstStreamCollection
+``` c
+struct GstStreamCollection;
+
+gst_stream_collection_new(...);
+gst_stream_collection_add_stream(...);
+gst_stream_collection_get_size(...);
+gst_stream_collection_get_stream(...);
 
-gst_stream_collection_new(...)
-gst_stream_collection_add_stream(...)
-gst_stream_collection_get_size(...)
-gst_stream_collection_get_stream(...)
 GST_MESSAGE_STREAM_COLLECTION
 gst_message_new_stream_collection(...)
 gst_message_parse_stream_collection(...)
+
 GST_EVENT_STREAM_COLLECTION
 gst_event_new_stream_collection(...)
 gst_event_parse_stream_collection(...)
 ```
 
-Elements that create new streams (such as demuxers) or can create
-new streams (like the HLS/DASH alternative streams) can list the
-streams they can make available with the `GstStreamCollection` object.
+Elements that create new streams (such as demuxers) or can create new streams
+(like the HLS/DASH alternative streams) can list the streams they can make
+available with the `GstStreamCollection` object.
+
+Other elements that might generate `GstStreamCollections` are the DVD-VM, which
+handles internal switching of tracks, or `parsebin` and `decodebin3` when it
+aggregates and presents multiple internal stream sources as a single
+configurable collection.
 
-Other elements that might generate `GstStreamCollections` are the
-DVD-VM, which handles internal switching of tracks, or parsebin and
-decodebin3 when it aggregates and presents multiple internal stream
-sources as a single configurable collection.
 
 The `GstStreamCollection` object is a flat listing of `GstStream` objects.
 
 The various properties of a `GstStreamCollection` are:
   - 'identifier'
-      - the identifier of the collection (unique name)
-      - Generated from the 'upstream stream id' (or stream ids, plural)
+    - the identifier of the collection (unique name)
+    - Generated from the 'upstream stream id' (or stream ids, plural)
+
   - the list of `GstStreams` in the collection.
-  - (Not implemented) : Flags -
-      For now, the only flag is `INFORMATIONAL` - used by container parsers to
-      publish information about detected streams without allowing selection of
-      the streams.
-  - (Not implemented yet) : The relationship between the various streams
-    This specifies which streams are exclusive (can not be selected at the
-    same time), are related (such as `LINKED_VIEW` or `ENHANCEMENT`), or need to
-    be selected together.
 
-An element will inform outside components about that collection via:
+  - **Not implemented** : Flags
+  
+    For now, the only flag is `INFORMATIONAL` - used by container parsers to
+    publish information about detected streams without allowing selection of the
+    streams. *Solving this might be possible through different means and needs
+    more investigation.*
+
+  - **Not implemented yet** : The relationship between the various streams
+  
+    This specifies which streams are exclusive (can not be selected at the same
+    time), are related (such as `LINKED_VIEW` or `ENHANCEMENT`), or need to be
+    selected together. *This requires more investigation*
+
+
+An element will inform outside components about that collection of streams via:
 
 * a `GST_MESSAGE_STREAM_COLLECTION` message on the bus.
 * a `GST_EVENT_STREAM_COLLECTION` on each source pads.
 
-Applications and container bin elements can listen and collect the
-various stream collections to know the full range of streams
-available within a bin/pipeline.
+Applications and container bin elements can listen and collect the various
+stream collections to know the full range of streams available within a
+bin/pipeline.
+
+
+Once posted on the bus, a `GstStreamCollection` is immutable. It is updated by
+subsequent messages with a matching identifier.
+
 
-Once posted on the bus, a `GstStreamCollection` is immutable. It is
-updated by subsequent messages with a matching identifier.
+If the element that provided the collection goes away, there is no way to know
+that the streams are no longer valid (without having the user/app track that
+element). The exception to that is if the bin containing that element (such as
+`parsebin` or `decodebin3`) informs that the next collection is a replacement of
+the former one.
 
-If the element that provided the collection goes away, there is no way
-to know that the streams are no longer valid (without having the
-user/app track that element). The exception to that is if the bin
-containing that element (such as parsebin or decodebin3) informs that
-the next collection is a replacement of the former one.
+The mutual exclusion and relationship lists use stream-ids rather than
+`GstStream` references in order to avoid circular referencing problems.
 
-The mutual exclusion and relationship lists use stream-ids
-rather than `GstStream` references in order to avoid circular
-referencing problems.
 
 ### Usage from elements
 
-When a demuxer knows the list of streams it can expose, it
-creates a new `GstStream` for each stream it can provide with the
-appropriate information (stream id, flag, tags, caps, ...).
+When a demuxer knows the list of streams it can expose, it creates a new
+`GstStream` for each stream it can provide with the appropriate information
+(stream id, flag, tags, caps, ...).
 
-The demuxer then creates a `GstStreamCollection` object in which it
-will put the list of `GstStream` it can expose.  That collection is
-then both posted on the bus (via a `GST_MESSAGE_COLLECTION`) and on
-each pad (via a `GST_EVENT_STREAM_COLLECTION`).
+The demuxer then creates a `GstStreamCollection` object in which it will put the
+list of `GstStream` it can expose.  That collection is then both posted on the
+bus (via a `GST_MESSAGE_COLLECTION`) and on each pad (via a
+`GST_EVENT_STREAM_COLLECTION`).
 
-That new collection must be posted on the bus *before* the changes
-are made available. i.e. before pads corresponding to that selection
-are added/removed.
+That new collection must be posted on the bus *before* the changes are made
+available. i.e. before pads corresponding to that selection are added/removed.
+
+In order to be backwards-compatible and support elements that don't create
+streams/collection yet, the `parsebin` element (used by `decodebin3`) will
+automatically create the stream and collection if not provided by the elements
+within.
 
-In order to be backwards-compatible and support elements that don't
-create streams/collection yet, the new 'parsebin' element used by
-decodebin3 will automatically create those if not provided.
 
 ### Usage from application
 
 Applications can know what streams are available by listening to the
 `GST_MESSAGE_STREAM_COLLECTION` messages posted on the bus.
 
-The application can list the available streams per-type (such as all
-the audio streams, or all the video streams) by iterating the
-streams available in the collection by `GST_STREAM_TYPE`.
+The application can list the available streams per-type (such as all the audio
+streams, or all the video streams) by iterating the streams available in the
+collection by `GST_STREAM_TYPE`.
+
+The application will also be able to use these stream information to decide
+which streams should be activated or not (see the stream selection event below).
 
-The application will also be able to use these stream information to
-decide which streams should be activated or not (see the stream
-selection event below).
 
 ### Backwards compatibility
 
-Not all demuxers will create the various `GstStream` and
-`GstStreamCollection` objects. In order to remain backwards
-compatible, a parent bin (parsebin in decodebin3) will create the
-`GstStream` and `GstStreamCollection` based on the pads being
-added/removed from an element.
+Not all demuxers will create the various `GstStream` and `GstStreamCollection`
+objects. In order to remain backwards compatible, a parent bin (parsebin in
+decodebin3) will create the `GstStream` and `GstStreamCollection` based on the
+pads being added/removed from an element.
+
+This allows providing stream listing/selection for any demuxer-like element even
+if it doesn't implement the `GstStreamCollection` usage.
 
-This allows providing stream listing/selection for any demuxer-like
-element even if it doesn't implement the `GstStreamCollection` usage.
 
 ## Stream selection event
 
 API:
 
-```
-
+``` c
 GST_EVENT_SELECT_STREAMS
+
 gst_event_new_select_streams(...)
 gst_event_parse_select_streams(...)
 ```
@@ -260,89 +304,95 @@ Stream selection events are generated by the application and sent into the
 pipeline to configure the streams.
 
 The event carries:
-  * List of `GstStreams` to activate - a subset of the `GstStreamCollection`
-  * (Not implemented) - List of `GstStreams` to be kept discarded - a
-    subset of streams for which hot-swapping will not be desired,
-    allowing elements (such as decodebin3, demuxers, ...) to not parse or
-    buffer those streams at all.
+
+  * List of `GstStreams` to activate
+    * a subset of the `GstStreamCollection`
+
+  * **Not implemented** List of `GstStreams` to be kept discarded
+    * a subset of streams for which hot-swapping will not be desired, allowing
+    elements (such as decodebin3, demuxers, ...) to not parse or buffer those
+    streams at all. *This will be solved in a different fashion.*
+
 
 ### Usage from application
 
-There are two use-cases where an application needs to specify in a
-generic fashion which streams it wants in output:
+There are two use-cases where an application needs to specify in a generic
+fashion which streams it wants in output:
+
+1. When there are several present streams of which it only wants a subset (such
+   as one audio, one video and one subtitle stream). Those streams are demuxed
+   and present in the pipeline.
+  
+2. When the stream the user wants require some element to undertake some action
+   to expose that stream in the pipeline (such as DASH/HLS alternative streams).
 
-1) When there are several present streams of which it only wants a
-  subset (such as one audio, one video and one subtitle
-  stream). Those streams are demuxed and present in the pipeline.
-2) When the stream the user wants require some element to undertake
-  some action to expose that stream in the pipeline (such as
-  DASH/HLS alternative streams).
 
-From the point of view of the application, those two use-cases are
-treated identically.  The streams are all available through the
-`GstStreamCollection` posted on the bus, and it will select a subset.
+From the point of view of the application, those two use-cases are treated
+identically.  The streams are all available through the `GstStreamCollection`
+posted on the bus, and the applications selects a subset.
 
 The application can select the streams it wants by creating a
-`GST_EVENT_SELECT_STREAMS` event with the list of stream-id of the
-streams it wants. That event is then sent on the pipeline,
-eventually traveling all the way upstream from each sink.
+`GST_EVENT_SELECT_STREAMS` event with the list of stream-id of the streams it
+wants. That event is then sent on the pipeline, eventually traveling all the way
+upstream from each sink.
+
+In some cases, selecting one stream may trigger the availability of other
+dependent streams, resulting in new `GstStreamCollection` messages. This can
+happen in the case where choosing a different DVB channel would create a new
+single-program collection.
 
-In some cases, selecting one stream may trigger the availability of
-other dependent streams, resulting in new `GstStreamCollection`
-messages. This can happen in the case where choosing a different DVB
-channel would create a new single-program collection.
 
 ### Usage in elements
 
-Elements that receive the `GST_EVENT_SELECT_STREAMS` event and that
-can activate/deactivate streams need to look at the list of
-stream-id contained in the event and decide if they need to do some
-action.
+Elements that receive the `GST_EVENT_SELECT_STREAMS` event and that can
+activate/deactivate streams need to look at the list of stream-id contained in
+the event and decide if they need to do some action.
+
+In the standard demuxer case (demuxing and exposing all streams), there is
+nothing to do by default.
 
-In the standard demuxer case (demuxing and exposing all streams),
-there is nothing to do by default.
+In `decodebin3`, activating or deactivating streams is taken care of by linking
+only the streams present in the event to decoders and output ghostpad.
 
-In decodebin3, activating or deactivating streams is taken care of by
-linking only the streams present in the event to decoders and output
-ghostpad.
+In the case of elements that can expose alternate streams that are not present
+in the pipeline as pads, they will take the appropriate action to add/remove
+those streams.
 
-In the case of elements that can expose alternate streams that are
-not present in the pipeline as pads, they will take the appropriate
-action to add/remove those streams.
+Containers that receive the event (via `GstElement::send_event()`) should pass
+it to any elements with no downstream peers, so that streams can be configured
+during pre-roll before a pipeline is completely linked down to sinks.
 
-Containers that receive the event should pass it to any elements
-with no downstream peers, so that streams can be configured during
-pre-roll before a pipeline is completely linked down to sinks.
 
 ## decodebin3 usage and example
 
-This is an example of how decodebin3 works by using the
-above-mentioned objects/events/messages.
+This is an example of how decodebin3 works by using the above-mentioned
+objects/events/messages.
+
+For clarity/completeness, we will consider a MPEG-TS stream that has multiple
+audio streams. Furthermore that stream might have changes at some point
+(switching video codec, or adding/removing audio streams).
 
-For clarity/completeness, we will consider a MPEG-TS stream that has
-multiple audio streams. Furthermore that stream might have changes
-at some point (switching video codec, or adding/removing audio
-streams).
 
-### Initial differences
+### Initial differences with `decodebin2`
 
-decodebin3 is different, compared to decodebin2, in the sense that, by
+`decodebin3` is different, compared to `decodebin2`, in the sense that, by
 default:
-* it will only expose as output ghost source pads one stream of each
-  type (one audio, one video, ..).
+
+* it will only expose as output ghost source pads one stream of each type (one
+  audio, one video, ..).
 * It will only decode the exposed streams
 
-The multiqueue element is still used and takes in all elementary
-(non-decoded) streams. If parsers are needed/present they are placed
-before the multiqueue. This is needed in order for multiqueue to
-work only with packetized and properly timestamped streams.
 
-Note that the whole typefinding of streams, and optional depayloading,
-demuxing and parsing are done in a new 'parsebin' element.
+The `multiqueue` element is still used and takes in all elementary (non-decoded)
+streams. If parsers are needed/present they are placed before the
+multiqueue. This is needed in order for multiqueue to work only with packetized
+and properly timestamped streams.
+
+Note that the whole typefinding of streams, and optional depayloading, demuxing
+and parsing are done in a new `parsebin` element.
 
-Just like the current implementation, demuxers will expose all
-streams present within a program as source pads. They will connect
-to parsers and multiqueue.
+Just like the current implementation, demuxers will expose all streams present
+within a program as source pads. They will connect to parsers and multiqueue.
 
 Initial setup. 1 video stream, 2 audio streams.
 
@@ -357,125 +407,140 @@ Initial setup. 1 video stream, 2 audio streams.
   +---------------------+
 ```
 
-### GstStreamCollection
+### Generating GstStreamCollection
 
 When parsing the initial PAT/PMT, the demuxer will:
-1) create the various GstStream objects for each stream.
-2) create the GstStreamCollection for that initial PMT
-3) post the `GST_MESSAGE_STREAM_COLLECTION` Decodebin will intercept that
-message and know what the demuxer will be exposing.
-4) The demuxer creates the various pads and sends the corresponding
-`STREAM_START` event (with the same stream-id as the corresponding
-`GstStream` objects), `CAPS` event, and `TAGS` event.
-
-  * parsebin will add all relevant parsers and expose those streams.
-
-  * Decodebin will be able to correlate, based on `STREAM_START` event
-stream-id, what pad corresponds to which stream. It links each stream
-from parsebin to multiqueue.
-
-  * Decodebin knows all the streams that will be available. Since by
-default it is configured to only expose a stream of each type, it
-will pick a stream of each for which it will complete the
-auto-plugging (finding a decoder and then exposing that stream as a
-source ghostpad.
-
-> Note: If the demuxer doesn't create/post the `GstStreamCollection`,
-> parsebin will create it on itself, as explained in section 2.3
-> above.
+
+1. create the various `GstStream` objects for each stream.
+
+2. create the `GstStreamCollection` for that initial PMT
+
+3. post the `GST_MESSAGE_STREAM_COLLECTION`. Decodebin will intercept that
+   message and know what the demuxer will be exposing.
+
+4. The demuxer creates the various pads and sends the corresponding
+   `STREAM_START` event (with the same stream-id as the corresponding
+   `GstStream` objects), `CAPS` event, and `TAGS` event.
+
+  * `parsebin` will add all relevant parsers and expose those streams.
+
+  * `decodebin3` will be able to correlate, based on `STREAM_START` event
+    stream-id, what pad corresponds to which stream. It links each stream from
+    parsebin to multiqueue.
+
+  * `decodebin3` knows all the streams that will be available. Since by default
+    it is configured to only expose a stream of each type, it will pick a stream
+    of each for which it will complete the auto-plugging (finding a decoder and
+    then exposing that stream as a source ghostpad.
+
+> Note: If the demuxer doesn't create/post the `GstStreamCollection`, `parsebin`
+> will create it on itself, as explained in the previous sections above.
+
 
 ### Changing the active selection from the application
 
-The user wants to change the audio track. The application received
-the `GST_MESSAGE_STREAM_COLLECTION` containing the list of available
-streams. For clarity, we will assume those stream-ids are
-"video-main", "audio-english" and "audio-french".
+The user wants to change the audio track. The application received the
+`GST_MESSAGE_STREAM_COLLECTION` containing the list of available streams. For
+clarity, we will assume those stream-ids are `"video-main"`, `"audio-english"`
+and `"audio-french"`.
 
-The user prefers to use the french soundtrack (which it knows based
-on the language tag contained in the `GstStream` objects).
+
+The user prefers to use the french soundtrack (which it knows based on the
+language tag contained in the `GstStream` objects).
 
 The application will create and send a `GST_EVENT_SELECT_STREAM` event
-containing the list of streams: "video-main", "audio-french".
-
-That event gets sent on the pipeline, the sinks send it upstream and
-eventually reach decodebin.
-
-Decodebin compares:
-* The currently active selection ("video-main", "audio-english")
-* The available stream collection ("video-main", "audio-english",
-  "audio-french")
-* The list of streams in the event ("video-main", "audio-french")
-
-Decodebin determines that no change is required for "video-main",
-but sees that it needs to deactivate "audio-english" and activate
-"audio-french".
-
-It unlinks the multiqueue source pad connected to the audiodec. Then
-it queries audiodec, using the `GST_QUERY_ACCEPT_CAPS`, whether it can
-accept as-is the caps from the "audio-french" stream.
-1) If it does, the multiqueue source pad corresponding to
-   "audio-french" is linked to the decoder.
-2) If it does not, the existing audio decoder is removed,
-   a new decoder is selected (like during initial
-   auto-plugging), and replaces the old audio decoder element.
-
-The newly selected stream gets decoded and output through the same
-pad as the previous audio stream.
-
-Note:
-The default behaviour would be to only expose one stream of each
-type. But nothing prevents decodebin from outputting more/less of
-each type if the `GST_EVENT_SELECT_STREAM` event specifies that. This
-allows covering more use-case than the simple playback one.
-Such examples could be :
+containing the list of streams: `"video-main", "audio-french"`.
+
+That event gets sent on the pipeline, the sinks send it upstream and eventually
+reach `decodebin3`.
+
+`decodebin3` compares:
+
+* The currently active selection (`"video-main", "audio-english"`)
+* The available stream collection (`"video-main", "audio-english",
+  "audio-french"`)
+* The list of streams in the event (`"video-main", "audio-french"`)
+
+`decodebin3` determines that no change is required for `"video-main"`, but sees
+that it needs to deactivate `"audio-english"` and activate `"audio-french"`.
+
+
+It unlinks the `multiqueue` source pad connected to the current audio
+decoder. Then it queries that audio decoder, using the `GST_QUERY_ACCEPT_CAPS`,
+whether it can accept as-is the caps from the `"audio-french"` stream.
+
+1. If it does, the multiqueue source pad corresponding to `"audio-french"` is
+   linked to the decoder.
+   
+2. If it does not, the existing audio decoder is removed, a new decoder is
+   selected (like during initial auto-plugging), and replaces the old audio
+   decoder element.
+
+The newly selected stream gets decoded and output through the same pad as the
+previous audio stream.
+
+
+*Note:* The default behavior is to only expose one stream of each type. But
+nothing prevents `decodebin3` from outputting more/less of each type if the
+`GST_EVENT_SELECT_STREAM` event specifies that. This allows covering more
+use-case than the simple playback one. Such examples could be :
   * Wanting just a video stream or just an audio stream
   * Wanting all decoded streams
   * Wanting all audio streams
   ...
 
+
 ### Changes coming from upstream
 
-At some point in time, a PMT change happens. Let's assume a change
-in video-codec and/or PID.
+At some point in time, a PMT change happens. Let's assume a change in
+video-codec and/or PID.
+
+The demuxer creates a new `GstStream` for the changed/new stream, creates a new
+`GstStreamCollection` for the updated PMT and posts it.
+
+
+`decodebin3` sees the new `GstStreamCollection` message.
+
+The demuxer (and `parsebin`) then adds and removes pads:
 
-The demuxer creates a new `GstStream` for the changed/new stream,
-creates a new GstStreamCollection for the updated PMT and posts it.
+1. `decodebin3` will match the new pads to `GstStream` in the *new*
+   `GstStreamCollection` the [same way it did](#generating-gststreamcollection)
+   for the initial pads previously.
+  
+2. `decodebin3` will see whether the new stream can re-use a `multiqueue` slot
+   used by a stream of the same type no longer present (it compares the old
+   collection to the new collection).  In this case, `decodebin3` sees that the
+   new video stream can re-use the same slot as the previous video stream.
+  
+3. If the new stream is going to be active by default (in this case it does
+   because we are replacing the only video stream, which was active), it will
+   check whether the caps are compatible with the existing video decoder (in the
+   same way it was done for the [audio decoder
+   switch](#changing-the-active-selection-from-the-application)).
 
-Decodebin sees the new `GstStreamCollection` message.
 
-The demuxer (and parsebin) then adds and removes pads.
-1) decodebin will match the new pads to `GstStream` in the "new"
-  `GstStreamCollection` the same way it did for the initial pads in
-  section 4.2 above.
-2) decodebin will see whether the new stream can re-use a multiqueue
-  slot used by a stream of the same type no longer present (it
-  compares the old collection to the new collection).
-  In this case, decodebin sees that the new video stream can re-use
-  the same slot as the previous video stream.
-3) If the new stream is going to be active by default (in this case
-  it does because we are replacing the only video stream, which was
-  active), it will check whether the caps are compatible with the
-  existing videodec (in the same way it was done for the audio
-  decoder switch in section 4.3).
+Finally, the stream that switched will be decoded and output through the same
+pad as the previous video stream in a gapless fashion.
 
-Eventually, the stream that switched will be decoded and output
-through the same pad as the previous video stream in a gapless fashion.
 
 ### Further examples
 
 ##### HLS alternates
 
-There is a main (multi-bitrate or not) stream with audio and
-video interleaved in MPEG-TS. The manifest also indicates the
-presence of alternate language audio-only streams.
-HLS would expose one collection containing:
-1) The main A+V CONTAINER stream (MPEG-TS), initially active,
- downloaded and exposed as a pad
-2) The alternate A-only streams, initially inactive and not exposed as pads
-the tsdemux element connected to the first stream will also expose
-a collection containing
-1.1) A video stream
-1.2) An audio stream
+**NOTE:** Not properly handled yet.
+
+There is a main (multi-bitrate or not) stream with audio and video interleaved
+in MPEG-TS. The manifest also indicates the presence of alternate language
+audio-only streams. `hlsdemux` would expose one collection containing:
+
+1. The main A+V CONTAINER stream (MPEG-TS), initially active, downloaded and
+   exposed as a pad
+2. The alternate audio-only streams, initially inactive and not exposed as
+   pads. The `tsdemux` element connected to the first stream will also expose a
+   collection containing:
+   * A video stream
+   * An audio stream
 
 ```
     [ Collection 1 ]         [ Collection 2 ]
@@ -487,35 +552,40 @@ a collection containing
     [ "kor"  (A)   ]         [              ]
 ```
 
-The user might want to use the korean audio track instead of the
-default english one.
+The user might want to use the korean audio track instead of the default english
+one.
 
 ```
   => SELECT_STREAMS ("video", "kor")
 ```
 
-1) decodebin3 receives and sends the event further upstream
-2) tsdemux sees that "video" is part of its current upstream,
-  so adds the corresponding stream-id ("main") to the event
-  and sends it upstream ("main", "video", "kor")
-3) hlsdemux receives the event
+1) `decodebin3` receives and sends the event further upstream
+
+2) `tsdemux` sees that "video" is part of its current upstream, so adds the
+  corresponding stream-id ("main") to the event and sends it upstream ("main",
+  "video", "kor")
+
+3) `hlsdemux` receives the event
   => It activates "kor" in addition to "main"
-4) The event travels back to decodebin3 which will remember the
-  requested selection. If "kor" is already present it will switch
-  the "eng" stream from the audio decoder to the "kor" stream.
-  If it appears a bit later, it will wait until that "kor" stream
-  is available before switching
 
-#### multi-program MPEG-TS
+4) The event travels back to `decodebin3` which will remember the requested
+  selection. If "kor" is already present it will switch the "eng" stream from
+  the audio decoder to the "kor" stream.  If it appears a bit later, it will
+  wait until that "kor" stream is available before switching
+
+
+#### Multi-program MPEG-TS
+
+**NOTE:** Not properly handled yet.
+
+Assuming the case of a MPEG-TS stream which contains multiple programs.
 
-Assuming the case of a MPEG-TS stream which contains multiple
-programs.
 There would be three "levels" of collection:
-   1) The collection of programs presents in the stream
-   2) The collection of elementary streams presents in a stream
-   3) The collection of streams decodebin can expose
+1. The collection of programs presents in the stream
+2. The collection of elementary streams presents in a stream
+3. The collection of streams decodebin can expose
 
-Initially tsdemux exposes the first program present (default)
+Initially `tsdemux` exposes the first program present (default)
 
 ```
     [ Collection 1 ]         [ Collection 2     ]        [ Collection 3    ]
@@ -528,23 +598,30 @@ Initially tsdemux exposes the first program present (default)
     [ "NBC"  (C)   ]         [                  ]        [                 ]
 ```
 
-At some point the user wants to switch to ITV (of which we do not
-know the topology at this point in time. A `SELECT_STREAMS` event
-is sent with "ITV" in it and the pointer to the Collection1.
-1) The event travels up the pipeline until tsdemux receives it
-   and begins the switch.
-2) tsdemux publishes a new 'Collection 2a/ITV' and marks 'Collection 2/BBC'
-   as replaced.
-2a) App may send a `SELECT_STREAMS` event configuring which demuxer output
-   streams should be selected (parsed)
-3) tsdemux adds/removes pads as needed (flushing pads as it removes them?)
-4) Decodebin feeds new pad streams through existing parsers/decoders as
+At some point the user wants to switch to ITV (of which we do not know the
+topology at this point in time. A `SELECT_STREAMS` event is sent with "ITV" in
+it and the pointer to the Collection1.
+
+1. The event travels up the pipeline until `tsdemux` receives it and begins the
+   switch.
+
+2. `tsdemux` publishes a new 'Collection 2a/ITV' and marks 'Collection 2/BBC' as
+   replaced.
+
+   1. App may send a `SELECT_STREAMS` event configuring which demuxer output
+      streams should be selected (parsed)
+
+3. `tsdemux` adds/removes pads as needed (flushing pads as it removes them?)
+
+4. `decodebin3` feeds new pad streams through existing parsers/decoders as
    needed. As data from the new collection arrives out each decoder,
-   decodebin sends new `GstStreamCollection` messages to the app so it
-   can know that the new streams are now switchable at that level.
-4a) As new `GstStreamCollections` are published, the app may override
-   the default decodebin stream selection to expose more/fewer streams.
-   The default is to decode and output 1 stream of each type.
+   `decodebin3` sends new `GstStreamCollection` messages to the app so it can
+   know that the new streams are now switchable at that level.
+   
+   1. As new `GstStreamCollections` are published, the app may override the
+      default decodebin stream selection to expose more/fewer streams.  The
+      default is to decode and output 1 stream of each type.
+
 
 Final state:
 
@@ -559,40 +636,50 @@ Final state:
     [ "NBC"  (C)   ]         [                  ]        [                 ]
 ```
 
+
 ### TODO
 
-- Add missing implementation
-
-  - Add flags to `GstStreamCollection`
-
-  - Add mutual-exclusion and relationship API to `GstStreamCollection`
-
-- Add helper API to figure out whether a collection is a replacement
-of another or a completely new one. This will require a more generic
-system to know whether a certain stream-id is a replacement of
-another or not.
-
-### OPEN QUESTIONS
-
-- Is a `FLUSHING` flag for stream-selection required or not? This would
-make the handler of the `SELECT_STREAMS` event send `FLUSH START/STOP`
-before switching to the other streams. This is tricky when dealing
-where situations where we keep some streams and only switch some
-others. Do we flush all streams? Do we only flush the new streams,
-potentially resulting in delay to fully switch? Furthermore, due to
-efficient buffering in decodebin3, the switching time has been
-minimized extensively, to the point where flushing might not bring a
-noticeable improvement.
-
-- Store the stream collection in bins/pipelines? A Bin/Pipeline could
-store all active collection internally, so that it could be queried
-later on. This could be useful to then get, on any pipeline, at any
-point in time, the full list of collections available without having
-to listen to all COLLECTION messages on the bus. This would require
-fixing the "is a collection a replacement or not" issue first.
-
-- When switching to new collections, should decodebin3 make any effort
-to *map* corresponding streams from the old to new PMT - that is,
-try and stick to the *english* language audio track, for example?
-Alternatively, rely on the app to do such smarts with stream-select
-messages?
+- Figure out how to handle *mutual-exclusion* and *relationship* API with
+  collection of streams.
+
+- ~~Add flags to `GstStreamCollection`~~
+
+- Add helper API to figure out whether a collection is a replacement of another
+  or a completely new one. This will require a more generic system to know
+  whether a certain stream-id is a replacement of another or not.
+  
+
+### Open Questions
+
+- ~~Is a `FLUSHING` flag for stream-selection required or not?~~
+
+  This would make the handler of the `SELECT_STREAMS` event send `FLUSH
+  START/STOP` before switching to the other streams. This is tricky when dealing
+  where situations where we keep some streams and only switch some others. Do we
+  flush all streams? Do we only flush the new streams, potentially resulting in
+  delay to fully switch?  Furthermore, due to efficient buffering in
+  `decodebin3`, the switching time has been minimized extensively, to the point
+  where flushing might not bring a noticeable improvement.
+  
+  **Note:** This flushing capability was not needed in the end. Leveraging
+  minimal buffering in `decodebin3` and various other elements allows
+  *almost-instantaneous* stream switching without this.
+
+
+- Store the stream collection in bins/pipelines?
+
+  A Bin/Pipeline could store all active collection internally, so that it could
+  be queried later on. This could be useful to then get, on any pipeline, at any
+  point in time, the full list of collections available without having to listen
+  to all COLLECTION messages on the bus. This would require fixing the "is a
+  collection a replacement or not" issue first.
+
+
+- When switching to new collections, should `decodebin3` make any effort to
+  *map* corresponding streams from the old to new PMT - that is, try and stick
+  to the *english* language audio track, for example?  Alternatively, rely on
+  the app to do such smarts with stream-select messages?
+
+  **Note:** If an application listens synchronously to the collection bus
+  messages, it can indeed decide which streams it wants to select. And therefore
+  stick to the (new) english audio track.