--- title: GStreamer --- # Internals ## RTP timestamp - Domain for `rtptime` is `clock-time` from SDP - 48000 in this case - So one tick is 1/48000 of a second - Meaning 20 milliseconds is 960 ## Discussion on threading internals ## Threads and probes [Probes](https://gstreamer.freedesktop.org/documentation/additional/design/probes.html?gi-language=c) [Threads](https://gstreamer.freedesktop.org/documentation/application-development/advanced/threads.html?gi-language=c) ## Audio decoders There is `max-errors` property on audio decoder elements which can be helpful in debugging. ## Autoplugging - [Auto plugging](https://gstreamer.freedesktop.org/documentation/application-development/advanced/autoplugging.html?gi-language=c) - [Playback components](https://gstreamer.freedesktop.org/documentation/application-development/highlevel/playback-components.html?gi-language=c) - [Decodebin design](https://gstreamer.freedesktop.org/documentation/additional/design/decodebin.html?gi-language=c) ## Why are queues required - [Demuxing mp4 and queues](http://gstreamer-devel.966125.n4.nabble.com/demuxing-mp4-and-queues-td4689905.html) This is a classical problem, and a good illustration why you usually need queues after elements with N source pads, and before elements with N sink pads. The demuxer is pushing to its source pads from the same thread, and if you have connected these source pads with sync=true sinks, their chain function blocks until pre-rolling is done, that's until each sink with sync=true has received a buffer. Adding queues decouples branches of the pipeline, as they start their own streaming thread. ## Dynamically remove or unlink elements - http://gstreamer-devel.966125.n4.nabble.com/Dynamically-adding-and-removing-branches-of-a-tee-td973635.html - https://gstreamer.freedesktop.org/documentation/application-development/advanced/pipeline-manipulation.html?gi-language=c See probes here. ## Webkit debugging - https://eocanha.org/blog/2021/05/25/gstreamer-webkit-debugging-by-using-external-tools-2-2/ ## Quark Quarks represent a different idea Quarks are basically an internal "registry" of strings. The idea is that if you want to compare strings often, that can be inefficient, so you make a GQuark of it (essentially a hash) that you can stably compare. So if there is a string comparison you are performing often, or you want to make faster, you convert the string to a quark (hashing it to an integer), and then use that instead. ## Flushing probe https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/274 # Elements ## GstDiscoverer - Internally uses `uridecodebin`. This element decodes data from a URI into raw media. It selects a source element that can handle the given URI scheme and connects it to a `decodebin` element. It acts like a demuxer, so it offers as many source pads as streams are found in the media. ``` bash gst-launch-1.0 uridecodebin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm ! videoconvert ! autovideosink ``` - Primary function seems to be `discoverer_collect` which gets called pipeline is pre-rolled - The next important function is `parse_stream_topology`. It can also be called recursively - Checks for `next` in `GstStructure` passed as argument to this function - If `next` is `NULL`, then it's the end of the stream, else one has a `GstValue` holding either a structure or a list - For the case of a `GstStructure`, `collect_information` is then called. It reads various fields in the caps to collect information like `rate`, `channels` and `channel-mask`. Something called `TAGS` and `QUARK` also come into picture here. Quarks seem to be a 2 way association between a string and a unique identifier - For the case of list, along with some things, walk over the list, calling `parse_stream_topology` for each item in the list, where the item seems to a sub stream ### Decodebin This element automatically constructs a decoding pipeline using available decoders and demuxers via auto plugging until raw media is obtained. It's used internally by `uridecodebin` which is often more convenient to use, as it creates a suitable source element as well. It replaces the old `decodebin` element. It acts like a demuxer, so it offers as many source pads as streams are found in the media. ``` bash gst-launch-1.0 souphttpsrc location=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm ! decodebin ! autovideosink ``` ### Thumbnails Can `GstDiscoverer` be used for thumbnails? Search with Google a bit, and land on this issue [discoverer should generated video/image thumbnails](https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/issues/58). This references [Thumbnailer Spec](https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html) and [Thumbnail Management DBus Specification](https://wiki.gnome.org/action/show/DraftSpecs/ThumbnailerSpec?action=show&redirect=ThumbnailerSpec). `GstDiscoverer` doesn't seem to have a thumbnailing API. There is a totem video thumbnailer which is the video thumbnailer for the **GNOME** desktop but seems not to be available as a separate library. [ffmpegthumbnailer](https://github.com/dirkvdb/ffmpegthumbnailer) based on ffmpeg is a lightweight video thumbnailer that can be used by file managers to create thumbnails for video files. However, packaging `ffmpeg` might be a concern here and `ffmpegthumbnailer` has a *GPL-2.0* license. FFmpeg is licensed under the LGPL license, however, if a particular build of FFmpeg is linked against any GPL libraries (notably x264), then the entire binary is licensed under the GPL. If this needs to be provided with GStreamer then `gstbasesink` has a note on `last-sample` property where it mentions that the property can be used to generate thumbnails. Also see `gst_base_sink_get_last_sample`. A related option seems to be `convertframe` which has two APIs for converting a raw video buffer into the specified output caps. See [convertframe](https://gstreamer.freedesktop.org/documentation/video/convertframe.html?gi-language=c#). Some links which have examples. - https://github.com/GStreamer/gst-editing-services/blob/master/examples/c/thumbnails.c - https://stackoverflow.com/questions/15789652/how-to-create-video-thumbnails-with-python-and-gstreamer - https://gist.github.com/dplanella/5563018 ### Tracker miner `GstDiscoverer` is used in Tracker Miner though not for everything. From [Into the Pyramid](https://samthursfield.wordpress.com/2019/12/01/into-the-pyramid/). - Tracker has a ‘generic image extraction’ rule that tries to find metadata for any image/\* MIME type that isn’t a .bmp, .jpg, .gif, or .png. This codepath uses the GstDiscoverer API, the same as for video and audio files, in the hope that a GStreamer plugin on the system can give useful info about the image. - The GstDiscoverer instance is created with a timeout of 5 seconds. (This seems high, the typefind utility that ships with GStreamer uses a timeout of 1 second). - GStreamer’s GstDiscoverer API feeds any file where the type is unknown into an MPEG decoder, which is an unwanted fuzz test and can trigger periods of high CPU and memory usage. - 5 seconds of processing non-MPEG data with an MPEG decoder is somehow enough to cause Linux’s scheduler to lock up the entire system. ## Rank [Modify the elements rank](https://developer.ridgerun.com/wiki/index.php?title=GStreamer_modify_the_elements_rank) Each GStreamer element has a detail called rank that defines the priority used by the autoplugger when it wants to connect a new element but has multiple options. # Pipeline examples ## Opus RTP encoding decoding pipeline Note that in place of `rtpjitterbuffer`, `rtpbin` also works. ``` bash export AUDIO_CAPS="application/x-rtp,media=(string)audio,clock-rate=(int)48000,encoding-name=(string)OPUS" gst-launch-1.0 -v audiotestsrc ! audioconvert ! audioresample ! opusenc ! rtpopuspay ! udpsink host=localhost port=50004 gst-launch-1.0 udpsrc caps=$AUDIO_CAPS address=localhost port=50004 ! rtpjitterbuffer latency=20 do-lost=true ! rtpopusdepay ! opusdec plc=true ! pulsesink ``` ## Tearing down a branch of *tee* ``` python tee = pipe.get_by_name(RTMP_TEE) srcPad = tee.get_static_pad("src_" + str(idx)) srcPad.add_probe( Gst.PadProbeType.BLOCK, rtmp_tee_srcpad_block_probe, rtmpUrl ) def rtmp_tee_srcpad_block_probe( pad: Gst.Pad, info: Gst.PadProbeInfo, rtmpUrl ) -> Gst.PadProbeReturn: tee = pipe.get_by_name(RTMP_TEE) queue = pipe.get_by_name(MUX_OUTPUT_QUEUE + "-" + rtmpUrl) rtmpSink = pipe.get_by_name(RTMP_SINK + "-" + rtmpUrl) sinkPad = queue.get_static_pad("sink") pad.unlink(sinkPad) rtmpSink.set_state(Gst.State.NULL) queue.set_state(Gst.State.NULL) tee.remove_pad(pad) pipe.remove(queue) pipe.remove(rtmpSink) return Gst.PadProbeReturn.REMOVE ``` ## Check camera capabilities ``` bash gst-device-monitor-1.0 Video/Source v4l2-ctl --list-formats-ext -d0 ``` # Annotations [Annotation Glossary](https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html//annotation-glossary.html) # AAC test samples - https://samples.mplayerhq.hu/A-codecs/AAC/ # Debugger If `SIGSEGV` occurs, to use `gdb` and `gst-launch` to debug the crashed process, first run ``` bash echo 0 > /proc/sys/kernel/yama/ptrace_scope echo -1 > /proc/sys/kernel/perf_event_paranoid ``` Arch enables the Yama LSM by default, which provides a `kernel.yama.ptrace_scope` kernel parameter. This parameter is set to 1 (restricted) by default which prevents tracers from performing a `ptrace` call on traces outside of a restricted scope unless the tracer is privileged or has the `CAP_SYS_PTRACE` capability. # Terminology ## Transmuxing - Referred to as repackaging or packetizing, is a process in which audio and video files are repackaged into different delivery formats without changing the files' contents. # Yocto [Enable RTMP plugin](https://www.toradex.cn/community/questions/13303/gstreamer-rtmp-plugin.html) # RTP [Some FAQs about RTP](https://www.cs.columbia.edu/~hgs/rtp/faq.html) # Basics of time and synchronization - https://www.youtube.com/watch?v=EOHl1ktWwp4 - https://www.youtube.com/watch?v=OKTfNAmFTo4 - `running_time` is the amount of time "spent" in playing - Playing => Paused: Remember running time - Paused => Playing: base_time = current absolutetime - running_time # Live pipeline ## Live sources - [Live source](https://gstreamer.freedesktop.org/documentation/additional/design/live-source.html?gi-language=c) - [Element source](https://gstreamer.freedesktop.org/documentation/additional/design/element-source.html?gi-language=c) - [gstbasesrc](https://gstreamer.freedesktop.org/documentation/base/gstbasesrc.html?gi-language=c) ## Pipeline to check base time gets updated after PAUSE -> PLAY transition ``` bash env GST_DEBUG=basesink:6 gst-play-1.0 /usr/share/sounds/alsa/Front_Left.wav --audiosink="fakesink sync=true" -q 2>&1 | grep base_time ``` # Running test suite with gdb ``` bash ninja -C build && env CK_FORK=no meson test --gdb -C build --suite gst-plugins-good elements_splitmuxsink ``` # Re-timestamping frames - [Timestamping frames in GStreamer](https://kaustav.space/2018-09-20/retimestamping-frames-in-gstreamer) # H264 - [Kurento docs - H264](https://doc-kurento.readthedocs.io/en/latest/knowledge/h264.html) # Video mp4 - https://bitmovin.com/container-formats-fun-1 - https://docs.unified-streaming.com/documentation/live/subtitles.html#embedded-subtitles-captions - https://stackoverflow.com/questions/24884827/possible-locations-for-sequence-picture-parameter-sets-for-h-264-stream - https://stackoverflow.com/questions/10185474/gstreamer-how-to-get-audio-and-video-to-play-at-the-same-rate - https://bitmovin.com/fun-with-container-formats-2/ - https://www.ramugedia.com/mp4-container - https://gpac.github.io/mp4box.js/test/filereader.html - https://en.wikipedia.org/wiki/Video_compression_picture_types - https://en.wikipedia.org/wiki/Group_of_pictures - https://observablehq.com/@benjamintoofer/iso-base-media-file-format - https://streaminglearningcenter.com/blogs/open-and-closed-gops-all-you-need-to-know.html