From bc416770be233cbe582b241a16e5683d46247da4 Mon Sep 17 00:00:00 2001
From: Apertis CI <devel@lists.apertis.org>
Date: Wed, 26 Feb 2025 12:30:35 +0000
Subject: [PATCH 1/3] Import Upstream version 1.24.12

---
 .gitlab/issue_templates/Bug.md                |   32 -
 ChangeLog                                     | 4921 +++++++++++------
 NEWS                                          | 3944 +++++++++----
 README.md                                     |   12 +-
 RELEASE                                       |   34 +-
 docs/gst-hotdoc-plugins-scanner.c             |    4 +-
 docs/gst-plugins-doc-cache-generator.py       |   56 +-
 docs/gst/running.md                           |   12 +-
 docs/index.md                                 |    6 +-
 docs/meson.build                              |   46 +-
 docs/plugins/gst_plugins_cache.json           |   44 +
 gst/gst.c                                     |   35 +-
 gst/gst.h                                     |    1 +
 gst/gst_private.h                             |   10 +-
 gst/gstallocator.c                            |   48 +-
 gst/gstallocator.h                            |   18 +
 gst/gstandroid.c                              |    2 +-
 gst/gstbin.c                                  |   40 +-
 gst/gstbuffer.c                               |  137 +-
 gst/gstbuffer.h                               |    3 +
 gst/gstbufferlist.c                           |   16 +-
 gst/gstbufferpool.c                           |    6 +
 gst/gstbus.c                                  |   41 +-
 gst/gstbytearrayinterface.h                   |  129 +
 gst/gstcaps.c                                 |   11 +-
 gst/gstcapsfeatures.c                         |    4 +-
 gst/gstclock.c                                |   10 +-
 gst/gstclock.h                                |   43 +-
 gst/gstcontext.c                              |   25 +-
 gst/gstcontext.h                              |    9 +
 gst/gstcontrolbinding.c                       |    2 +-
 gst/gstdatetime.c                             |    8 +-
 gst/gstdebugutils.c                           |   10 +-
 gst/gstdevicemonitor.c                        |   13 +-
 gst/gstdeviceprovider.c                       |    8 +-
 gst/gstelement.c                              |  108 +-
 gst/gstelementfactory.c                       |    8 +-
 gst/gstelementfactory.h                       |    8 +
 gst/gstevent.c                                |    8 +-
 gst/gstformat.c                               |    2 +-
 gst/gstinfo.c                                 |   32 +-
 gst/gstiterator.c                             |    8 +-
 gst/gstmacos.m                                |   81 +-
 gst/gstmessage.c                              |    8 +-
 gst/gstmeta.c                                 |  420 +-
 gst/gstmeta.h                                 |  128 +-
 gst/gstobject.c                               |    2 +
 gst/gstobject.h                               |   48 +
 gst/gstpad.c                                  |  118 +-
 gst/gstpad.h                                  |   28 +
 gst/gstparse.c                                |    4 +-
 gst/gstpipeline.c                             |   68 +-
 gst/gstpipeline.h                             |    6 +
 gst/gstplugin.c                               |  168 +-
 gst/gstplugin.h                               |   18 +
 gst/gstpluginfeature.c                        |   13 +-
 gst/gstpluginloader-win32.c                   | 1368 +++++
 gst/gstpluginloader.c                         |  173 +-
 gst/gstpoll.c                                 |    4 +-
 gst/gstpromise.c                              |   33 +-
 gst/gstpromise.h                              |   10 +
 gst/gstprotection.c                           |    9 +
 gst/gstquery.c                                |    7 +-
 gst/gstregistry.c                             |   96 +-
 gst/gstregistrybinary.c                       |   14 +-
 gst/gstregistrybinary.h                       |    2 +-
 gst/gstregistrychunks.c                       |   61 +-
 gst/gstregistrychunks.h                       |    4 +-
 gst/gstsample.c                               |   32 +-
 gst/gstsample.h                               |   15 +-
 gst/gstsegment.c                              |   11 +-
 gst/gststreamcollection.c                     |   14 +-
 gst/gststructure.c                            |   45 +-
 gst/gststructure.h                            |   18 +-
 gst/gstsystemclock.c                          |  319 +-
 gst/gsttaglist.c                              |   13 +-
 gst/gsttaglist.h                              |   12 +
 gst/gsttagsetter.c                            |    4 +-
 gst/gsttask.c                                 |   26 +-
 gst/gsttaskpool.c                             |   11 +-
 gst/gsttoc.c                                  |    8 +-
 gst/gsttocsetter.c                            |    4 +-
 gst/gsttracerutils.c                          |   20 +-
 gst/gsttypefind.c                             |    2 +-
 gst/gsturi.c                                  |  117 +-
 gst/gsturi.h                                  |    6 +
 gst/gstutils.c                                |  403 +-
 gst/gstutils.h                                |   21 +
 gst/gstvalue.c                                |  131 +-
 gst/meson.build                               |   26 +-
 gst/parse/grammar.y.in                        |  218 +-
 gst/parse/types.h                             |   12 +-
 gst/printf/asnprintf.c                        |    2 +-
 gst/printf/vasnprintf.c                       |    4 +-
 gstreamer.doap                                |  160 +
 libs/gst/base/gstadapter.c                    |    2 +-
 libs/gst/base/gstaggregator.c                 |  267 +-
 libs/gst/base/gstbaseparse.c                  |   20 +-
 libs/gst/base/gstbasesink.c                   |   42 +-
 libs/gst/base/gstbasesink.h                   |   14 +
 libs/gst/base/gstbasesrc.c                    |  132 +-
 libs/gst/base/gstbasesrc.h                    |   16 +-
 libs/gst/base/gstbasetransform.c              |    4 +-
 libs/gst/base/gstbitreader.c                  |    4 +-
 libs/gst/base/gstbitwriter.c                  |   12 +-
 libs/gst/base/gstbytereader.c                 |    4 +-
 libs/gst/base/gstbytewriter.c                 |    8 +-
 libs/gst/base/gstcollectpads.c                |    2 +-
 libs/gst/base/gstflowcombiner.c               |    4 +-
 libs/gst/base/gstindex.c                      |   16 +-
 libs/gst/base/gstmemindex.c                   |    8 +-
 libs/gst/base/gstpushsrc.h                    |    4 +-
 libs/gst/base/gstqueuearray.c                 |  221 +-
 libs/gst/base/gstqueuearray.h                 |   17 +
 libs/gst/base/gsttypefindhelper.c             |   15 +-
 libs/gst/base/meson.build                     |    1 +
 libs/gst/check/gstcheck.c                     |   11 +-
 libs/gst/check/gstharness.c                   |  100 +-
 libs/gst/check/gstharnesslink.c               |  230 +
 libs/gst/check/gstharnesslink.h               |   57 +
 libs/gst/check/gsttestclock.c                 |    4 +-
 libs/gst/check/libcheck/check_run.c           |    6 +-
 libs/gst/check/libcheck/libcompat/getline.c   |    2 +-
 libs/gst/check/meson.build                    |    2 +
 .../gstinterpolationcontrolsource.c           |   17 +-
 libs/gst/controller/gstlfocontrolsource.c     |   20 +-
 .../controller/gsttimedvaluecontrolsource.c   |   10 +-
 libs/gst/controller/meson.build               |    1 +
 libs/gst/helpers/glib_gobject_helper.py       |   97 +-
 libs/gst/helpers/gst-plugin-scanner.c         |   22 +-
 libs/gst/helpers/gst-ptp-helper.c             |  687 ---
 libs/gst/helpers/gst_gdb.py                   |  108 +-
 libs/gst/helpers/meson.build                  |  162 +-
 libs/gst/helpers/ptp/args.rs                  |   76 +
 libs/gst/helpers/ptp/clock.rs                 |  119 +
 libs/gst/helpers/ptp/conf_lib.rs.in           |    2 +
 libs/gst/helpers/ptp/error.rs                 |  219 +
 libs/gst/helpers/ptp/ffi.rs                   | 1077 ++++
 libs/gst/helpers/ptp/io.rs                    | 1402 +++++
 libs/gst/helpers/ptp/log.rs                   |  109 +
 libs/gst/helpers/ptp/main.rs                  |  422 ++
 libs/gst/helpers/ptp/meson.build              |  125 +
 libs/gst/helpers/ptp/net.rs                   | 1176 ++++
 libs/gst/helpers/ptp/parse.rs                 |  605 ++
 libs/gst/helpers/ptp/privileges.rs            |  245 +
 .../{ => ptp}/ptp_helper_post_install.sh      |    4 +-
 libs/gst/helpers/ptp/rand.rs                  |  246 +
 libs/gst/helpers/ptp/thread.rs                |   54 +
 libs/gst/net/gstnetclientclock.c              |  124 +-
 libs/gst/net/gstptp_private.h                 |   19 -
 libs/gst/net/gstptpclock.c                    | 1245 ++++-
 libs/gst/net/gstptpclock.h                    |    4 +
 libs/gst/net/meson.build                      |    3 +-
 meson.build                                   |   59 +-
 meson_options.txt                             |    2 +
 plugins/elements/gstclocksync.c               |  260 +-
 plugins/elements/gstclocksync.h               |   17 +
 plugins/elements/gstconcat.c                  |    2 -
 plugins/elements/gstdownloadbuffer.c          |   14 +-
 plugins/elements/gstelements_private.c        |    8 +
 plugins/elements/gstfilesink.c                |   53 +-
 plugins/elements/gstfilesink.h                |   19 +-
 plugins/elements/gstfilesrc.c                 |   36 +-
 plugins/elements/gstfunnel.c                  |    2 -
 plugins/elements/gstidentity.c                |   18 +-
 plugins/elements/gstinputselector.c           |   28 +-
 plugins/elements/gstinputselector.h           |    1 +
 plugins/elements/gstmultiqueue.c              |  271 +-
 plugins/elements/gstqueue.c                   |  164 +-
 plugins/elements/gstqueue.h                   |    1 +
 plugins/elements/gstqueue2.c                  |  261 +-
 plugins/elements/gstqueue2.h                  |    2 +-
 plugins/elements/gstsparsefile.c              |   32 +-
 plugins/elements/gsttypefindelement.c         |    2 +-
 plugins/tracers/gstleaks.c                    |    9 +-
 plugins/tracers/gstlog.c                      |   83 +-
 plugins/tracers/gstrusage.c                   |    8 +-
 plugins/tracers/gststats.c                    |    8 +-
 po/LINGUAS                                    |    2 +-
 po/af.po                                      |   27 +-
 po/ast.po                                     |   27 +-
 po/az.po                                      |   24 +-
 po/be.po                                      |   27 +-
 po/bg.po                                      |   36 +-
 po/ca.po                                      |   27 +-
 po/cs.po                                      |   28 +-
 po/da.po                                      |   28 +-
 po/de.po                                      |   33 +-
 po/el.po                                      |   27 +-
 po/en_GB.po                                   |   28 +-
 po/eo.po                                      |   28 +-
 po/es.po                                      |   36 +-
 po/eu.po                                      |   27 +-
 po/fi.po                                      |   27 +-
 po/fr.po                                      |   49 +-
 po/fur.po                                     |  432 +-
 po/gl.po                                      |   27 +-
 po/gstreamer-1.0.pot                          |  326 +-
 po/gstreamer.pot                              |  326 +-
 po/hr.po                                      |   43 +-
 po/hu.po                                      |   28 +-
 po/id.po                                      |   32 +-
 po/it.po                                      |   30 +-
 po/ja.po                                      |   24 +-
 po/ka.po                                      |   27 +-
 po/ko.po                                      |   27 +-
 po/lt.po                                      |   27 +-
 po/lv.po                                      | 1424 +++++
 po/nb.po                                      |   55 +-
 po/nl.po                                      |   43 +-
 po/pl.po                                      |   30 +-
 po/pt_BR.po                                   |   70 +-
 po/ro.po                                      |  111 +-
 po/ru.po                                      |   28 +-
 po/rw.po                                      |   29 +-
 po/sk.po                                      |   28 +-
 po/sl.po                                      |  168 +-
 po/sq.po                                      |   27 +-
 po/sr.po                                      |   40 +-
 po/sv.po                                      |   48 +-
 po/tr.po                                      |  293 +-
 po/uk.po                                      |   35 +-
 po/vi.po                                      |   28 +-
 po/zh_CN.po                                   |   28 +-
 po/zh_TW.po                                   |   27 +-
 scripts/gen-changelog.py                      |    1 -
 scripts/git-version.sh                        |    1 -
 tests/check/elements/fakesink.c               |  170 +
 tests/check/elements/filesink.c               |   84 +
 tests/check/elements/multiqueue.c             |   75 +
 tests/check/elements/queue.c                  |  248 +-
 tests/check/elements/queue2.c                 |  209 +
 tests/check/elements/tee.c                    |    3 +-
 tests/check/gst/gstbin.c                      |    2 +-
 tests/check/gst/gstbuffer.c                   |   34 +-
 tests/check/gst/gstbufferpool.c               |  110 +
 tests/check/gst/gstdevice.c                   |    1 -
 tests/check/gst/gstelementfactory.c           |    3 +-
 tests/check/gst/gstinfo.c                     |    4 +-
 tests/check/gst/gstiterator.c                 |   58 +
 tests/check/gst/gstmemory.c                   |    4 +-
 tests/check/gst/gstmeta.c                     |   48 +
 tests/check/gst/gstobject.c                   |    6 +
 tests/check/gst/gstplugin.c                   |   79 +-
 tests/check/gst/gstpromise.c                  |    8 +-
 tests/check/gst/gststructure.c                |   28 +-
 tests/check/gst/gsturi.c                      |   49 +
 tests/check/gst/gstutils.c                    |   82 +-
 tests/check/gst/gstvalue.c                    |  141 +-
 tests/check/gstreamer.supp                    |   21 +
 tests/check/libs/aggregator.c                 |   74 +
 tests/check/libs/basesink.c                   |   64 +
 tests/check/libs/gsttestclock.c               |    4 +-
 tests/check/libs/queuearray.c                 |  282 +-
 tests/check/meson.build                       |    5 +-
 tests/check/pipelines/parse-launch.c          |    4 +
 tests/check/tools/gstinspect.c                |   48 +-
 tests/examples/memory/my-memory.c             |    6 +-
 tests/examples/memory/my-vidmem.c             |    6 +-
 tests/examples/streams/testrtpool.c           |    6 +-
 tests/meson.build                             |    6 +-
 tests/misc/meson.build                        |    3 +-
 tests/misc/network-clock-utils.scm            |   29 +-
 tests/misc/network-clock.scm                  |   29 +-
 tests/validate/gst-tester.c                   |    4 +-
 tests/validate/meson.build                    |    2 +-
 tools/gst-inspect-1.0.1                       |    4 -
 tools/gst-inspect.c                           |  217 +-
 tools/gst-launch-1.0.1                        |    4 -
 tools/gst-launch.c                            |   45 +-
 tools/gst-stats.c                             |  169 +-
 tools/gst-typefind-1.0.1                      |    4 -
 tools/gst-typefind.c                          |   27 +-
 tools/meson.build                             |    2 +-
 274 files changed, 25385 insertions(+), 6914 deletions(-)
 delete mode 100644 .gitlab/issue_templates/Bug.md
 create mode 100644 gst/gstbytearrayinterface.h
 create mode 100644 gst/gstpluginloader-win32.c
 create mode 100644 libs/gst/check/gstharnesslink.c
 create mode 100644 libs/gst/check/gstharnesslink.h
 delete mode 100644 libs/gst/helpers/gst-ptp-helper.c
 create mode 100644 libs/gst/helpers/ptp/args.rs
 create mode 100644 libs/gst/helpers/ptp/clock.rs
 create mode 100644 libs/gst/helpers/ptp/conf_lib.rs.in
 create mode 100644 libs/gst/helpers/ptp/error.rs
 create mode 100644 libs/gst/helpers/ptp/ffi.rs
 create mode 100644 libs/gst/helpers/ptp/io.rs
 create mode 100644 libs/gst/helpers/ptp/log.rs
 create mode 100644 libs/gst/helpers/ptp/main.rs
 create mode 100644 libs/gst/helpers/ptp/meson.build
 create mode 100644 libs/gst/helpers/ptp/net.rs
 create mode 100644 libs/gst/helpers/ptp/parse.rs
 create mode 100644 libs/gst/helpers/ptp/privileges.rs
 rename libs/gst/helpers/{ => ptp}/ptp_helper_post_install.sh (80%)
 create mode 100644 libs/gst/helpers/ptp/rand.rs
 create mode 100644 libs/gst/helpers/ptp/thread.rs
 delete mode 100644 libs/gst/net/gstptp_private.h
 create mode 100644 po/lv.po

diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md
deleted file mode 100644
index 71c79ac..0000000
--- a/.gitlab/issue_templates/Bug.md
+++ /dev/null
@@ -1,32 +0,0 @@
-### Describe your issue
-<!-- a clear and concise summary of the bug. -->
-<!-- For any GStreamer usage question, please contact the community using the #gstreamer channel on IRC https://www.oftc.net/ or the mailing list on https://gstreamer.freedesktop.org/lists/ -->
-
-#### Expected Behavior
-<!-- What did you expect to happen -->
-
-#### Observed Behavior
-<!-- What actually happened -->
-
-#### Setup
-- **Operating System:**
-- **Device:** Computer / Tablet / Mobile / Virtual Machine <!-- Delete as appropriate !-->
-- **GStreamer Version:**
-- **Command line:**
-
-### Steps to reproduce the bug
-<!-- please fill in exact steps which reproduce the bug on your system, for example: -->
-1. open terminal
-2. type `command`
-
-### How reproducible is the bug?
-<!-- The reproducibility of the bug is Always/Intermittent/Only once after doing a very specific set of steps-->
-
-### Screenshots if relevant
-
-### Solutions you have tried
-
-### Related non-duplicate issues
-
-### Additional Information
-<!-- Any other information such as logs. Make use of <details> for long output -->
diff --git a/ChangeLog b/ChangeLog
index e40f242..8228fb4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,56 +1,270 @@
-=== release 1.22.0 ===
+=== release 1.24.12 ===
 
-2023-01-23 19:29:34 +0000  Tim-Philipp Müller <tim@centricular.com>
+2025-01-29 20:12:29 +0000  Tim-Philipp Müller <tim@centricular.com>
 
 	* NEWS:
 	* RELEASE:
 	* gstreamer.doap:
 	* meson.build:
-	  Release 1.22.0
+	  Release 1.24.12
 
-2023-01-23 16:27:36 +0000  Tim-Philipp Müller <tim@centricular.com>
+2025-01-27 07:45:22 -0700  Jordan Yelloz <jordan.yelloz@collabora.com>
 
-	* po/bg.po:
-	* po/de.po:
-	* po/es.po:
-	* po/hr.po:
-	* po/id.po:
-	* po/nb.po:
-	* po/pl.po:
-	* po/ro.po:
-	* po/ru.po:
-	* po/uk.po:
-	* po/zh_CN.po:
-	  gstreamer: update translations
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3773>
+	* gst/gstiterator.c:
+	* tests/check/gst/gstiterator.c:
+	  gstiterator: Added error handling to filtered iterators
+	  Otherwise, if the underlying iterator returns GST_ITERATOR_ERROR, the filtered
+	  iterator will crash.
+	  With this change, the filtered iterator propagates the error back to the caller.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8370>
 
-2023-01-19 16:01:21 +0200  Sebastian Dröge <sebastian@centricular.com>
+2025-01-22 12:34:31 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gstquery.c:
-	  gst: Mark caps parameters in ALLOCATION query API as nullable
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3752>
+	* libs/gst/net/gstnetclientclock.c:
+	  netclientclock: Don't stop searching the clock cache when the first corrupted clock is found
+	  The clock we're looking for might be working fine and be available afterwards.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8364>
 
-2023-01-18 16:07:39 +0100  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
+2025-01-22 12:32:24 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-	* plugins/elements/gstinputselector.c:
-	  input-selector: Take the object lock while iterating sinkpads
-	  Otherwise we can race with pad removal and crash from use-after-free.
-	  Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1717
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3745>
+	* libs/gst/net/gstnetclientclock.c:
+	  netclientclock: Don't ever store failed internal clocks in the cache
+	  If starting the internal clock fails we would still store a broken clock in the
+	  cache despite it being unusable and never recovering.
+	  Not storing it allows the application to simply create a new one at a later time
+	  and have starting it retried.
+	  Also signal to the application that such a clock is not synced.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8364>
+
+2025-01-23 19:48:28 +0000  Rares Branici <rares.branici@senstar.com>
+
+	* gst/gstpluginloader-win32.c:
+	  pluginloader-win32: create no window
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8357>
+
+2025-01-23 16:52:30 +0100  Silvio Lazzeretti <silviola@amazon.it>
+
+	* gst/gstpluginloader-win32.c:
+	  gstpluginloader-win32: fix use after free in find_helper_bin_location
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8356>
+
+2025-01-20 10:48:04 +0100  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* plugins/elements/gstsparsefile.c:
+	  sparsefile: ensure error is set when read_buffer() returns 0
+	  gst_sparse_file_read() is supposed to set @error when returning 0 but
+	  in some cases was not.
+	  Hopefully fix a crash in gst_download_buffer_read_buffer() which is
+	  checking error->code when 0 is returned.
+	  I'm not totally sure when this happens as I debugged this from a post
+	  mortem crash but returning a generic error here seems the safe thing to
+	  do.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8331>
+
+2025-01-20 10:47:34 +0100  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* plugins/elements/gstsparsefile.c:
+	  sparsefile: fix typo in doc
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8331>
+
+2025-01-15 03:36:07 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/gstdevicemonitor.c:
+	  gstdevice: Fetch device provider from message source
+	  The GstDevice removed may not have a parent anymore when we check
+	  whether the provider is hidden. Let's fetch the provider from the
+	  message source, which is more reliable.
+	  Fixes a racy nullptr deref on macOS when a device is unplugged:
+	  ```
+	  libgstreamer-1.0.0.dylib!is_provider_hidden (gstreamer/subprojects/gstreamer/gst/gstdevicemonitor.c:240)
+	  libgstreamer-1.0.0.dylib!bus_sync_message (gstreamer/subprojects/gstreamer/gst/gstdevicemonitor.c:286)
+	  libgstreamer-1.0.0.dylib!gst_bus_post (gstreamer/subprojects/gstreamer/gst/gstbus.c:358)
+	  libgstreamer-1.0.0.dylib!gst_device_provider_device_remove (gstreamer/subprojects/gstreamer/gst/gstdeviceprovider.c:685)
+	  libgstosxaudio.dylib!gst_osx_audio_device_provider_update_devices ([...]/sys/osxaudio/gstosxaudiodeviceprovider.c:539)
+	  libgstosxaudio.dylib!_audio_devices_changed_cb ([...]/sys/osxaudio/gstosxaudiodeviceprovider.c:313)
+	  CoreAudio!HALObject::PropertiesChanged(unsigned int, AudioObjectPropertyAddress const*) (Unknown Source:0)
+	  CoreAudio!HALSystem::PropertiesChanged(unsigned int, AudioObjectPropertyAddress const*) (Unknown Source:0)
+	  CoreAudio!HALSystem::ObjectsPublishedAndDied(...) (Unknown Source:0)
+	  CoreAudio!HALSystem::AudioObjectsPublishedAndDied(...) (Unknown Source:0)
+	  CoreAudio!HALC_ShellPlugIn::ReconcileDeviceList(bool, bool) (Unknown Source:0)
+	  CoreAudio!HALC_ShellPlugIn::CreateAggregateDevice(__CFDictionary const*, unsigned int&) (Unknown Source:0)
+	  CoreAudio!AudioHardwareCreateAggregateDevice_mac_imp (Unknown Source:0)
+	  AudioDSP!___lldb_unnamed_symbol15046 (Unknown Source:0)
+	  AudioDSP!___lldb_unnamed_symbol15038 (Unknown Source:0)
+	  AudioDSP!___lldb_unnamed_symbol33307 (Unknown Source:0)
+	  AudioToolboxCore!APComponent::newInstance(...) (Unknown Source:0)
+	  AudioToolboxCore!instantiate(...) (Unknown Source:0)
+	  AudioToolboxCore!__AudioComponentInstanceNew_block_invoke (Unknown Source:0)
+	  AudioToolboxCore!Synchronously (Unknown Source:0)
+	  ```
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8323>
+
+2024-08-20 00:40:06 +0900  Andrew Yooeun Chun <aychun00@gmail.com>
 
-=== release 1.21.90 ===
+	* libs/gst/base/gstbasetransform.c:
+	  basetransform: fix incorrect logging inside gst_base_transform_query_caps
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8289>
+
+2024-09-19 14:06:51 -0700  Alan Coopersmith <alan.coopersmith@oracle.com>
+
+	* tests/misc/meson.build:
+	  gstreamer: netclock-replay: use gst_c_args when building
+	  Need HAVE_CONFIG_H to avoid build failure on Solaris 11.4 with gcc 14.1:
+	  ../subprojects/gstreamer/tests/misc/../../libs/gst/net/gstnetutils.c:71:7:
+	  error: implicit declaration of function ‘setsockopt’
+	  [-Wimplicit-function-declaration]
+	  71 |   if (setsockopt (fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0) {
+	  |       ^~~~~~~~~~
+	  Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8264>
+
+2025-01-06 20:11:58 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2023-01-13 19:08:48 +0000  Tim-Philipp Müller <tim@centricular.com>
+	* meson.build:
+	  Back to development after 1.24.11
+
+=== release 1.24.11 ===
+
+2025-01-06 19:48:08 +0000  Tim-Philipp Müller <tim@centricular.com>
 
 	* NEWS:
 	* RELEASE:
 	* gstreamer.doap:
 	* meson.build:
-	  Release 1.21.90
+	  Release 1.24.11
 
-2023-01-11 15:40:49 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-12-03 23:39:54 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* meson.build:
+	  Back to development after 1.24.10
+
+=== release 1.24.10 ===
+
+2024-12-03 23:29:07 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.24.10
+
+2024-08-30 13:21:30 +0200  Stéphane Cerveau <scerveau@igalia.com>
+
+	* gst/gstutils.c:
+	* tests/check/gst/gstutils.c:
+	  utils: improve gst_util_ceil_log2
+	  According to the following comparison of algorithms, the value
+	  for 0 and 1 was giving an incorrect result.
+	  https://gist.github.com/ceyusa/6061b33ac109a68bcd222f6919968c9a
+	  More information here:
+	  https://github.com/rofrol/codeforces/blob/master/ceil_log2.c
+	  Use a different algorithm which offers better result and keep the
+	  performance.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7905>
+
+2024-09-26 22:07:22 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstallocator.c:
+	  allocator: Avoid integer overflow when allocating sysmem
+	  Thanks to Antonio Morales for finding and reporting the issue.
+	  Fixes GHSL-2024-166
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3851
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8044>
+
+2024-11-28 16:06:17 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstsystemclock.c:
+	  systemclock: Don't keep the clock entry locked while getting the time from the clock
+	  gst_clock_get_time() will take the clock mutex, which would then result in a lock
+	  order violation and possible deadlocks. If both mutexes are to be locked, the
+	  clock must always be locked first.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8019>
+
+2024-11-28 15:49:24 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstsystemclock.c:
+	  systemclock: Get rid of conditional unlocking of the clock entries
+	  At every point it is known whether the entry needs to be unlocked or not.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8019>
+
+2024-11-28 15:43:08 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstsystemclock.c:
+	  systemclock: Remove confusing conditional unlock
+	  At this point the entry is always locked and needs to be unlocked.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8019>
+
+2024-11-28 15:25:47 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstsystemclock.c:
+	  systemclock: Use a flag while waiting for the async thread to start
+	  Otherwise there can be spurious wakeups.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8019>
+
+2024-10-09 13:35:33 -0400  Alicia Boya García <aboya@igalia.com>
+
+	* gst/gstpad.c:
+	  pad: Never push sticky events in response to a FLUSH_STOP
+	  FLUSH_STOP is meant to clear the flushing state of pads and elements
+	  downstream, not to process data. Hence, a FLUSH_STOP should not
+	  propagate sticky events. This is also consistent with how flushes are a
+	  special case for probes.
+	  Currently this is almost always the case, since a FLUSH_STOP is
+	  __usually__ preceded by a FLUSH_START, and events (sticky or not) are
+	  discarded while a pad has the FLUSHING flag active (set by FLUSH_START).
+	  However, it is currently assumed that a FLUSH_STOP not preceded by a
+	  FLUSH_START is correct behavior, and this will occur while autoplugging
+	  pipelines are constructed. This leaves us with an unhandled edge case!
+	  This patch explicitly disables sending sticky events when pushing a
+	  FLUSH_STOP, instead of relying on the flushing flag of the pad, which
+	  will break in the edge case of a FLUSH_STOP not preceded by a
+	  FLUSH_START.
+	  If sticky events are propagated in response to a FLUSH_STOP, the
+	  flushing thread can end up deadlocked in blocking code of a downstream
+	  pad, such as a blocking probe. Instead, those events should be
+	  propagated from the streaming thread of the pad when handling a
+	  non-flushing synchronized event or buffer.
+	  This fixes a deadlock found in WebKit with playbin3 when seeks occur
+	  before preroll, where the seeking thread ended up stuck in the blocking
+	  probe of playsink:
+	  https://github.com/WebPlatformForEmbedded/WPEWebKit/issues/1367
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8003>
+
+2024-11-27 11:19:02 +0100  wbartel <wilhelm.bartel@streamonkey.de>
+
+	* gst/gstdebugutils.c:
+	  gstreamer: prefix debug dot node names to prevent splitting
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7998>
+
+2024-11-25 16:28:51 +0100  wbartel <wilhelm.bartel@streamonkey.de>
+
+	* plugins/tracers/gstleaks.c:
+	  tracers: unlock leaks tracer if already tracking
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7960>
+
+2024-11-18 08:47:12 +0100  Robert Rosengren <robertr@axis.com>
+
+	* gst/gstdeviceprovider.c:
+	  gstdeviceprovider: fix leaking hidden providers
+	  Free list of hidden providers upon stop and dispose.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7915>
+
+2024-11-07 15:44:25 +0530  Taruntej Kanakamalla <taruntej@asymptotic.io>
+
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/net.rs:
+	  ptp: use ip_mreq instead of ip_mreqn for macOS
+	  To join a multicast the macOS still uses the interface address
+	  from the ip_mreq instead of the ip_mreqn unlike other Linux systems.
+	  So add a new conditional block for macOS to use ip_mreq for IP_ADD_MEMBERSHIP
+	  and ip_mreqn for IP_MULTICAST_IF
+	  This is similar to the fix in the glib for multicast join/leave
+	  operation on macOS
+	  https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4333
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7864>
+
+2024-11-03 17:36:22 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* po/LINGUAS:
 	* po/af.po:
 	* po/ast.po:
 	* po/az.po:
@@ -77,6 +291,7 @@
 	* po/ka.po:
 	* po/ko.po:
 	* po/lt.po:
+	* po/lv.po:
 	* po/nb.po:
 	* po/nl.po:
 	* po/pl.po:
@@ -95,2207 +310,3309 @@
 	* po/zh_CN.po:
 	* po/zh_TW.po:
 	  gstreamer: update translations
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3711>
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7820>
 
-2023-01-11 14:53:39 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-10-30 20:40:12 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* scripts/dist-translations.py:
-	* scripts/meson.build:
-	  Fix translation pot files when creating dist tarballs
-	  Add version as per Translation Project requirements and
-	  also add a .pot file without the ABI suffix.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3711>
+	* meson.build:
+	  Back to development after 1.24.9
 
-2023-01-11 12:17:13 +0200  Sebastian Dröge <sebastian@centricular.com>
+=== release 1.24.9 ===
 
-	* tools/gst-inspect.c:
-	* tools/gst-launch.c:
-	* tools/gst-typefind.c:
-	  tools: Use `gst_macos_main()` on macOS
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1673
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3709>
+2024-10-30 20:33:30 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2023-01-04 21:37:55 +0100  Mathieu Duponchelle <mathieu@centricular.com>
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.24.9
 
-	* docs/meson.build:
-	  docs: explicitly declare gir build dependencies
-	  As the path to the gir file is passed to hotdoc.generate_doc() and
-	  not the build target itself, meson doesn't know about the dependency.
-	  In turn, as the CI doesn't build everything before building the
-	  documentation target, some gir files might not exist, for instance
-	  in the case of gst-rtsp-server, causing the output documentation to
-	  be empty.
-	  The error occurred silently because hotdoc accepts wildcards for
-	  *-sources arguments, thus it won't warn about a missing gir file as
-	  it is legitimate for glob matching to resolve to nothing.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3686>
-
-2022-12-29 18:16:31 +0000  Philippe Normand <philn@igalia.com>
+2024-10-28 10:41:08 -0300  Thibault Saunier <tsaunier@igalia.com>
 
-	* gst/gstevent.c:
-	  event: Fix gst_event_parse_stream_collection annotation
-	  The output parameter ownership is passed to the caller.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3659>
+	* plugins/elements/gstmultiqueue.c:
+	  multiqueue: Do not unref the query we get in pad->query
+	  We do not own any ref to queries when running them.
+	  If we end up processing the query from the streaming thread, it means that it was
+	  a serialized query, and the query is being waited to be processed on the sinkpad
+	  streaming thread, thread which owns the reference.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7796>
+
+2024-10-25 19:12:17 +0200  Mathieu Duponchelle <mathieu@centricular.com>
 
-2022-12-28 17:42:31 +0000  Philippe Normand <philn@igalia.com>
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: fix start time selection first with force-live
+	  When force-live is true, we don't want to wait for a first buffer
+	  to select a start time.
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1783
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7778>
 
-	* tests/check/gst/gstelement.c:
-	  tests: gstelement: Fix test_add_pad_while_paused flakiness
-	  `gst_element_remove_pad()` doesn't automatically deactivate the pad, it has to
-	  be done explicitly beforehand, otherwise the pad task might be left dangling,
-	  exposed to undefined behaviour.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3653>
+2024-10-23 16:14:45 +0200  Mathieu Duponchelle <mathieu@centricular.com>
 
-2019-05-04 03:54:44 +0200  Alicia Boya García <aboya@igalia.com>
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: fix live query when force-live is TRUE
+	  When force-live is TRUE, aggregator will correctly change its state with
+	  NO_PREROLL, but unless something upstream is live did not previously set
+	  live to TRUE on the latency query.
+	  Fix this by or'ing force_live into the result.
+	  Also improve debug
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7723>
 
-	* gst/gstelement.c:
-	* tests/check/gst/gstelement.c:
-	  gstelement: fix deadlock in gst_element_add_pad() when >=PAUSED
-	  gst_element_add_pad() is supposed to activate the pad if the element
-	  state is >= PAUSED and the pad is not already active.
-	  Unfortunately, before this patch, the activation was performed while the
-	  element lock was still taken, which ended causing a deadlock in
-	  gst_pad_start_task() as it attempted to post `stream-status` message in
-	  the element, which also requires the element lock.
-	  Elements could work around this bug by activating the pad manually
-	  before adding it to the element.
-	  This patch fixes the problem by performing pad activation only after the
-	  element lock has been released.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3635>
-
-2022-12-14 23:30:54 +0200  Mart Raudsepp <mart.raudsepp@globalm.media>
+2024-10-01 12:26:40 +0000  Corentin Damman <c.damman@intopix.com>
 
-	* plugins/elements/gstmultiqueue.c:
-	  multiqueue: Fix potential deadlock with parallel release_pad calls
-	  Commit d3a66f9851ea introduced a potential deadlock with two parallel release_pad
-	  calls, where one could release the main multiqueue lock (qlock) while still
-	  holding the reconf_lock and then calling other routines which in some conditions
-	  may try to acquire qlock again. The second release_pad could already acquire the
-	  qlock and then start waiting on reconf_lock, which may never be possible because
-	  because the first one isn't releasing it until it can acquire qlock.
-	  Fix it by holding reconf_lock for the whole durationg of qlock, making this
-	  particular deadlock impossible.
-	  Fixes #1642
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3571>
-
-2022-12-20 03:54:46 +0900  Hiero32 <unnoh@tkd.att.ne.jp>
-
-	* plugins/elements/gstfdsink.c:
-	* plugins/elements/gstfdsrc.c:
-	  fdsrc,fdsink: Set binary mode on FD
-	  Default mode of STD handles on Windows is text mode, and OS will
-	  insert CRLF sequence by default.
-	  Co-authored-by: Seungha Yang <seungha@centricular.com>
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3070>
-
-2022-12-20 03:51:45 +0900  Hiero32 <unnoh@tkd.att.ne.jp>
-
-	* plugins/elements/gstcoreelementselements.h:
-	* plugins/elements/gstcoreelementsplugin.c:
-	* plugins/elements/gstelements_private.c:
-	* plugins/elements/gstfdsink.c:
-	* plugins/elements/gstfdsrc.c:
-	  coreelements: Use G_OS_WIN32 macro
-	  * HAVE_WIN32 is not defined elsewhere
-	  * Enables fdsrc/fdsink for MinGW build as well
-	  Co-authored-by: Seungha Yang <seungha@centricular.com>
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3070>
-
-2022-12-13 08:58:43 -0500  Xavier Claessens <xavier.claessens@collabora.com>
-
-	* gst/gstconfig.h.in:
-	* libs/gst/check/libcheck/meson.build:
-	* meson.build:
-	  Fix API visibility macros
-	  This copies the logic from GLib discussed there:
-	  https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2936
-	  Beside being simpler, it also fix all public symbols being annotated
-	  with dllexport when doing a static build, as discovered there:
-	  https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3540#note_1678335
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3567>
+	* gst/gstmacos.m:
+	  macos: Fix race conditions
+	  This commit fixes two issues:
+	  - The event must be posted *after* calling stop, otherwise a race condition can occur and the app never stops
+	  - isFinishedLaunching and applicationDidFinishLaunching are not always synchronized, causing sometimes
+	  a deadlock on the g_cond_wait never catching the g_cond_signal
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7608>
 
-2022-12-17 00:36:49 +0000  Mathieu Duponchelle <mathieu@centricular.com>
+2024-09-16 08:48:47 -0400  Arun Raghavan <arun@asymptotic.io>
 
-	* libs/gst/base/gstbasesrc.c:
-	  basesrc: respect FIXED_CAPS flag in caps query implementation
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3590>
+	* gst/parse/grammar.y.in:
+	  gstreamer: parse: Use child proxy for deferred property setting
+	  We use that mechanism for the non-deferred path, and this makes sure we are
+	  consistent for deferred set too.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7561>
 
-2022-07-28 00:43:42 +0900  Hosang Lee <hosang10.lee@lge.com>
+2024-09-15 06:39:40 -0400  Arun Raghavan <arun@asymptotic.io>
 
-	* gst/gststreams.c:
-	* tests/check/gst/gststream.c:
-	  gst: handle combinations in gst_stream_type_get_name()
-	  This should handle the majority of the valid stream cases.
-	  The element setting the stream type may set each type separately.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2804>
+	* gst/parse/grammar.y.in:
+	  gstreamer: parse: Minor whitespace fixups
+	  Mostly replacing some tabs with spaces.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7561>
 
-2022-12-13 18:42:11 +0100  Piotr Brzeziński <piotr@centricular.com>
+2024-09-13 13:55:27 -0400  Arun Raghavan <arun@asymptotic.io>
+
+	* gst/parse/grammar.y.in:
+	  gstreamer: parse: Make sure children are bins before recursing in
+	  A deferred set of the form parentbin::childelement::pad works in the
+	  non-deferred property setting path, but the deferred path assumes that all
+	  non-root non-leaf children specify bins. We already have a bin check on the
+	  root, so let's add one for other non-leaves to avoid a critical.
+	  Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3806
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7561>
+
+2024-09-19 12:12:53 +0200  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gst.h:
-	* gst/gstmacos.h:
-	* gst/gstmacos.m:
-	* gst/meson.build:
 	* meson.build:
-	  macos: Add wrapper API to run a NSApplication in the main thread
-	  On macOS, a Cocoa event loop is needed in the main thread to ensure
-	  things like opening a GL window work correctly. In the past, this was
-	  patched into glib via Cerbero, but that prevented us from updating it.
-	  This workaround simply runs an NSApplication and then calls the
-	  main function on a secondary thread, allowing GStreamer to correctly
-	  display windows and/or system permission prompts, for example.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3532>
+	  Back to development after 1.24.8
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7549>
 
-2022-12-12 11:34:51 +0200  Sebastian Dröge <sebastian@centricular.com>
+=== release 1.24.8 ===
 
-	* gst/gstsystemclock.c:
+2024-09-19 12:01:21 +0200  Tim-Philipp Müller <tim@centricular.com>
+
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
 	* meson.build:
-	  systemclock: Use `futex_time64` syscall if available (32-bit systems) and use correct `struct timespec` definition
-	  See also https://gitlab.gnome.org/GNOME/glib/-/issues/2634
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1648
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3561>
+	  Release 1.24.8
 
-2020-08-15 12:53:13 +0000  sezanzeb <to.213692@protonmail.ch>
+2024-09-14 04:01:42 +0200  Peter Kjellerstedt <pkj@axis.com>
 
-	* gst/gst.c:
-	  gst_init: Removed wrong warning in docstring
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3562>
+	* gst/gstmeta.h:
+	  meta: Add missing include of gststructure.h
+	  This avoids the following error when only including gstmeta.h:
+	  /usr/include/gstreamer-1.0/gst/gstmeta.h:146:3: error: unknown type
+	  name 'GstStructure'
+	  146 |   GstStructure *structure;
+	  |   ^~~~~~~~~~~~
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7525>
 
-2022-12-07 21:57:31 +0000  Hugo Svirak <hugosvirak@gmail.com>
+2024-09-13 10:58:27 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gstbuffer.c:
-	* gst/gstbuffer.h:
-	* gst/gstmemory.c:
-	* gst/gstmemory.h:
-	* gst/gstminiobject.c:
-	  docs: specify possibility of a NULL return
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3546>
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: Immediately return NONE from simple_get_next_time() on non-TIME segments
+	  Otherwise this gives critical warnings.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7514>
 
-2022-12-10 11:33:38 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-09-10 16:03:05 -0400  Arun Raghavan <arun@asymptotic.io>
 
-	* plugins/elements/gstmultiqueue.c:
-	  multiqueue: update for renamed log id macros
-	  See #1635.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3553>
+	* gst/gstpad.c:
+	  pad: Check data NULL-ness when probes are stopped
+	  We were correctly handling this for buffers, but not events and queries.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7506>
 
-2022-12-10 11:32:25 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-08-26 19:13:11 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gstinfo.h:
-	  info: rename new log macros from GST_*_OBJECT_ID -> GST_*_ID
-	  Fixes #1635
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3553>
+	* gst/gstutils.c:
+	  clock: Fix calculation for number of bits needed to store a 64 bit value
+	  It was using log2(n) but what actually is needed is log2(n) + 1. Also add a
+	  fast-path that uses __builtin_clzll() on gcc/clang.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7431>
 
-2022-12-10 03:54:23 +1100  Jan Schmidt <jan@centricular.com>
+2024-08-23 15:56:41 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gstplugin.c:
-	  gstplugin: Handle static plugins in gst_plugin_load_by_name()
-	  gst_plugin_load_by_name() assumed a plugin has a filename,
-	  which isn't true for static plugins, leading to criticals.
-	  If a plugin is already loaded, just return the loaded plugin,
-	  which makes it work for static plugins as well as saving a
-	  moment for already-loaded dynamic plugins.
-	  Add locking in gst_plugin_is_loaded(), as a plugin may be
-	  still being loaded in another thread.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3552>
-
-2022-12-07 11:49:40 +0000  Tim-Philipp Müller <tim@centricular.com>
+	* gst/gstutils.c:
+	* tests/check/gst/gstutils.c:
+	  clock: Fix unchecked overflows in linear regression code
+	  The initial calculation for the precision shift was wrong and would allow for
+	  overflows during the calculations which were not detected and lead to wrong
+	  results.
+	  Also add a test for a case where overflows where previously not detected and
+	  caused a completely wrong result.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7431>
+
+2024-08-21 12:33:28 +0100  Tim-Philipp Müller <tim@centricular.com>
 
 	* meson.build:
-	  meson: fix check for pthread_setname_np()
-	  Need to define _GNU_SOURCE.
-	  Fixes #1542
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3538>
+	  Back to development after 1.24.7
 
-2022-11-29 15:12:51 +0100  Edward Hervey <edward@centricular.com>
+=== release 1.24.7 ===
 
-	* gst/gstinfo.c:
-	  gstinfo: Minor modification to avoid gst-indent pain
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3483>
+2024-08-21 12:25:15 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.24.7
 
-2022-11-29 10:03:14 +0100  Edward Hervey <edward@centricular.com>
+2024-05-28 16:27:39 +0300  Jan Schmidt <jan@centricular.com>
 
-	* plugins/elements/gstmultiqueue.c:
-	  multiqueue: Use new id-based debugging methods
-	  Clarifies the debug logs
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3483>
+	* gst/gstutils.c:
+	  core: Log pad name, not just the pointer
+	  Change a debug statement that was just logging a pad pointer where
+	  it could log the pad name more usefully.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7336>
 
-2022-11-29 09:37:00 +0100  Edward Hervey <edward@centricular.com>
+2024-08-05 17:34:15 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	  gstinfo: Allow passing a string identifier for debugging
-	  This adds "id" variants to most debugging functions, and allows providing a
-	  string identifier instead of a GObject.
-	  This allows providing unified and clearer debug logs for all the
-	  non-gobject-based items, and opens the way for more unified logging.
-	  As an extension, copying the object name is avoided as much as possible, by
-	  using it directly instead of going through another copy.
-	  * API : gst_debug_message_get_object_id
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3483>
+	* gst/gstbin.c:
+	  bin: Don't keep the object lock while setting a GstContext when handling NEED_CONTEXT
+	  This can potentially deadlock.
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3707
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7310>
 
-2022-12-05 02:29:08 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-07-29 16:48:02 +0100  Tim-Philipp Müller <tim@centricular.com>
 
 	* meson.build:
-	  Back to development
+	  Back to development after 1.24.6
 
-=== release 1.21.3 ===
+=== release 1.24.6 ===
 
-2022-12-05 01:28:21 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-07-29 16:41:37 +0100  Tim-Philipp Müller <tim@centricular.com>
 
 	* NEWS:
 	* RELEASE:
 	* gstreamer.doap:
 	* meson.build:
-	  Release 1.21.3
-
-2022-12-04 12:25:41 +0000  Tim-Philipp Müller <tim@centricular.com>
-
-	* ChangeLog:
-	* docs/random/ChangeLog-0.8:
-	* docs/random/old/ChangeLog.gst-plugins:
-	* docs/random/old/ChangeLog.gstreamer:
-	  Remove ChangeLog files from git repository
-	  This information is tracked fully in the git repository, so
-	  no point having the ChangeLog duplicate it, and it interferes
-	  with grepping the repository.
-	  We are going to create the ChangeLogs on the fly when generating
-	  tarballs going forward (with a limited history), since it's still
-	  valuable for tarball consumers to be able to easily see a list of
-	  recent changes.
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-project/-/issues/73
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3521>
-
-2022-11-07 00:10:39 +0000  Tim-Philipp Müller <tim@centricular.com>
+	  Release 1.24.6
 
-	* meson.build:
-	* scripts/gen-changelog.py:
-	  meson: Generate ChangeLog files for release tarballs on dist
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3521>
+2024-07-03 09:05:06 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
 
-2022-11-30 16:16:53 +0100  Edward Hervey <edward@centricular.com>
+	* plugins/elements/gstdownloadbuffer.c:
+	  downloadbuffer: send EOS in push mode
+	  gst_download_buffer_read_buffer() returns FLOW_EOS but it was not
+	  handled in the 'out_flushing' goto block which uses srcresult,
+	  so EOS was not sent downstream.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7140>
 
-	* plugins/elements/gstmultiqueue.c:
-	  multiqueue: Handle gapless with flushing
-	  Don't reset the stream-start group-id when stop/pausing single queues. They are
-	  only resetted when re-used (in READY->PAUSED).
-	  Fixes #1586
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3487>
+2024-07-03 09:16:47 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* plugins/elements/gstdownloadbuffer.c:
+	  downloadbuffer: initialize upstream_size when activated in push mode
+	  Push mode flow relies on upstream_size but it was not initialized when
+	  activated as it is when activated in pull mode.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7140>
 
-2022-12-01 08:16:45 +0100  Edward Hervey <edward@centricular.com>
+2024-07-03 09:13:27 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* plugins/elements/gstdownloadbuffer.c:
+	  downloadbuffer: init upstream_size to -1
+	  Code in check_upstream_size() is checking for -1 to check if
+	  upstream_size has been set or not.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7140>
+
+2024-07-03 09:03:59 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* plugins/elements/gstdownloadbuffer.c:
+	  downloadbuffer: properly log when receiving events
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7140>
+
+2024-07-02 15:56:12 +0100  Tim-Philipp Müller <tim@centricular.com>
 
 	* gst/gstinfo.c:
-	  gstinfo: Optimize color escape code creation
-	  When coloring is in use, those escape codes are going to be created many times
-	  for almost all debug lines.
-	  Don't create plenty of temporary allocations, and instead build the escape code
-	  ourselves statically
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3498>
+	  info: remove unused valgrind header include
+	  Follow-up to commit a2cbf75523cdf8a4df1baa7007d86ef455972245.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7129>
 
-2022-11-30 09:59:09 +0100  Edward Hervey <edward@centricular.com>
+2024-07-01 09:24:28 +0200  Edward Hervey <edward@centricular.com>
 
-	* tools/gst-inspect.c:
-	  gst-inspect: Don't leak list
-	  Just iterate the list instead of trying to be smart...
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3497>
+	* tests/validate/gst-tester.c:
+	  gstreamer/gst-tester: Don't leak thread
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7123>
 
-2022-10-24 18:02:27 +0300  Vivia Nikolaidou <vivia@ahiru.eu>
+2024-06-29 17:12:12 +0200  Edward Hervey <edward@centricular.com>
 
-	* docs/plugins/gst_plugins_cache.json:
-	* plugins/elements/gstinputselector.c:
-	* plugins/elements/gstinputselector.h:
-	  inputselector: Add drop-backwards property
-	  When sync-streams=true, drop backwards buffers on pad switch.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3256>
+	* tools/gst-inspect.c:
+	  gst-inspect: Fix leak of plugin/feature
+	  Reordering changes the initial list head
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7123>
 
-2022-10-24 16:49:47 +0300  Vivia Nikolaidou <vivia@ahiru.eu>
+2024-06-20 15:13:27 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* plugins/elements/gstinputselector.c:
-	* plugins/elements/gstinputselector.h:
-	  inputselector: Fix waiting on sync-mode=clock
-	  Basically copy over what clocksync does, but taking into account that we
-	  have multiple upstream latencies.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3256>
+	* plugins/elements/gstmultiqueue.c:
+	* plugins/elements/gstqueue.c:
+	* plugins/elements/gstqueue2.c:
+	  queue, queue2, multiqueue: Timestamps of gap events must be valid
+	  This is checked in gst_event_new_gap() so doesn't have to be checked again here,
+	  but simply can be asserted with a g_return_if_fail().
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7075>
 
-2022-11-19 02:04:13 +1100  Jan Schmidt <jan@centricular.com>
+2024-06-20 15:10:07 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gstevent.c:
-	  event: Add transfer none annotation to gst_event_new_stream_collection()
-	  Update the documentation
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3387>
+	* plugins/elements/gstmultiqueue.c:
+	* plugins/elements/gstqueue.c:
+	* plugins/elements/gstqueue2.c:
+	  queue: queue2: multiqueue: Don't work with segment.position if buffers have no timestamps
+	  If the first buffers have no timestamp then the sink position would be
+	  initialized to 0. The source pad might output this buffer, which would then
+	  initialize the source position to 0 too.
+	  Afterwards two buffers with a valid but huge timestamp might arrive before any
+	  of them are output on the source pad. The first one would set the sink position
+	  to a huge value, the second one would notice that the difference between the
+	  huge value and 0 is certainly larger than max-size-time and consider the queue
+	  as full.
+	  Instead, simply don't update the times from buffers without timestamps and
+	  assume whatever was set before is still valid, i.e. the buffer has the same
+	  timestamp as the previous one.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7075>
+
+2024-06-20 13:02:19 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-2022-11-11 22:57:38 +1100  Jan Schmidt <jan@centricular.com>
+	* meson.build:
+	  Back to development after 1.24.5
 
-	* gst/gstevent.c:
-	* gst/gstevent.h:
-	* gst/gstpad.c:
-	* tests/check/gst/gstpad.c:
-	  pad: Fix sticky event ordering for instant-rate-change
-	  The event type for instant-rate-change events was poorly chosen,
-	  leading to them being re-sent too late and even after EOS.
-	  Add a mechanism in GstPad for the sticky event order to be
-	  different to the value of the event type to fix that up.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3387>
+=== release 1.24.5 ===
 
-2022-11-18 16:57:16 +0100  Célestin Marot <c.marot@intopix.com>
+2024-06-20 12:54:15 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-	* plugins/elements/gstfakesrc.c:
-	  fakesrc: avoid time overflow with datarate
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3433>
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.24.5
 
-2022-09-01 18:57:58 +0100  Colin Kinloch <colin.kinloch@collabora.com>
+2024-06-05 10:38:57 +0200  Edward Hervey <edward@centricular.com>
 
-	* gst/gstvalue.c:
-	  gst: serialization of GLibDateTime
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2980>
+	* gst/gstpromise.c:
+	* tests/check/gst/gstpromise.c:
+	  gstpromise: Don't use g_return_* for internal checks
+	  If assertion/checks are disabled bad things will happen and the function won't
+	  return as expected
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6998>
 
-2022-11-18 14:24:30 +0100  Mathieu Duponchelle <mathieu@centricular.com>
+2024-05-30 12:08:57 +0200  Martin Nordholts <martn@axis.com>
 
-	* libs/gst/base/gstaggregator.c:
-	* libs/gst/base/gstaggregator.h:
-	* tests/check/libs/aggregator.c:
-	  aggregator: Implement force_live API
-	  Setting force_live lets aggregator behave as if it had at least one of
-	  its sinks connected to a live source, which should let us get rid of the
-	  fake live test source hack that is probably present in dozens of
-	  applications by now.
-	  + Expose API for subclasses to set and get force_live
-	  + Expose force-live properties in GstVideoAggregator and GstAudioAggregator
-	  + Adds a simple test
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3008>
-
-2022-09-28 03:08:39 +1000  Jan Schmidt <jan@centricular.com>
+	* gst/gstinfo.c:
+	  gst_debug: Add missing gst_debug_log_id_literal() dummy with gst_debug=false
+	  E.g. gst_debug_log_literal() already has a dummy variant.
+	  gst_debug_log_id_literal() is simply missing, which can
+	  cause link errors for project using gstreamer with
+	  gst_debug=false.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6979>
 
-	* plugins/elements/gstmultiqueue.c:
-	* plugins/elements/gstmultiqueue.h:
-	  multiqueue: Protect reconfiguration with a lock
-	  Add a lock to prevent overlapping of request and release
-	  pads, to close a race where multiqueue might try and
-	  add a slot with an id that hasn't quite finished being
-	  removed yet by another thread.
-	  Fix for https://gitlab.freedesktop.org/bilboed/gstreamer/-/issues/5
-	  and https://gitlab.freedesktop.org/bilboed/gstreamer/-/issues/11
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2784>
-
-2022-07-21 15:26:14 +0200  Edward Hervey <edward@centricular.com>
+2024-05-30 01:07:30 +0200  Samuel Thibault <samuel.thibault@ens-lyon.org>
 
-	* plugins/elements/gstmultiqueue.c:
-	  multiqueue: Handle gapless input
-	  When dealing with gapless input (i.e. streams with changing group-id in
-	  GST_EVENT_STREAM_START), we need to take into account the elapsed
-	  running-time (if applicable) in order to properly calculate levels and output
-	  time. Without doing this all incoming data from future groups would be
-	  considered as being "late" and would be consumed immediately.
-	  This does **NOT** modify the actual segment and buffer times, and is only used
-	  internally.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2784>
-
-2022-10-27 14:30:30 +0200  Edward Hervey <edward@centricular.com>
+	* libs/gst/helpers/ptp/clock.rs:
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/meson.build:
+	* libs/gst/helpers/ptp/net.rs:
+	  ptp-helper: Add GNU/Hurd support
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6974>
 
-	* gst/gstpad.c:
-	  urisourcebin: Remove pending pad handling
-	  This was needed to support the legacy handling of changing streams (add new
-	  pads, send EOS and remove old pads).
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2784>
+2024-05-29 13:51:27 +0300  Tim-Philipp Müller <tim@centricular.com>
 
-2022-11-15 19:14:14 +0200  Sebastian Dröge <sebastian@centricular.com>
+	* meson.build:
+	  Back to development after 1.24.4
 
-	* libs/gst/base/gsttypefindhelper.c:
-	  typefindhelper: Fix docs/annotations for the new functions
-	  Follow-up for https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3296
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3418>
+=== release 1.24.4 ===
 
-2022-11-09 16:57:15 -0300  Thibault Saunier <tsaunier@igalia.com>
+2024-05-29 13:44:50 +0300  Tim-Philipp Müller <tim@centricular.com>
 
-	* tools/gst-inspect.c:
-	  inspect: Print default value of ValueArray properties
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3377>
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.24.4
 
-2022-10-31 19:09:06 +0530  Sanchayan Maity <sanchayan@asymptotic.io>
+2024-05-28 13:17:39 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* libs/gst/base/gsttypefindhelper.c:
-	  typefindhelper: Use the new GstTypeFind * API
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3296>
+	* gst/parse/grammar.y.in:
+	  gstreamer: parse: Don't assume that child proxy child objects are GstObjects
+	  The name is already passed via the signal parameters so it doesn't have
+	  to be retrieved again via GstObject API, which would crash on other
+	  GObjects. Child proxy child objects can be any kind of GObject and the
+	  code here otherwise handles this correctly already.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6951>
 
-2022-10-31 18:33:19 +0530  Sanchayan Maity <sanchayan@asymptotic.io>
+2024-05-28 09:06:57 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* libs/gst/base/gsttypefindhelper.c:
-	* libs/gst/base/gsttypefindhelper.h:
-	  typefindhelper: Introduce a new API for working with a GstTypeFind *
-	  Introduce a new API that can return a GstTypeFind * with helper functions
-	  and data set around buffer data.
-	  While at it, drop factory field from GstTypeFindBufHelper. While it was
-	  useful for logging, it was not passed through function arguments and keeping
-	  it for logging would require an additional API increasing the API surface
-	  and making it harder to use.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3296>
-
-2022-11-15 14:45:56 +0530  Sanchayan Maity <sanchayan@asymptotic.io>
+	* libs/gst/helpers/ptp/ffi.rs:
+	  gstreamer: ptp-helper: Use u64 instead of c_ulong for ifa_flags on Solaris/Illumos
+	  See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3553#note_2429400
+	  Patch by Marcel Telka <marcel@telka.sk>.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6950>
 
-	* libs/gst/base/gsttypefindhelper.c:
-	* libs/gst/base/gsttypefindhelper.h:
-	  typefindhelper: Add helpers to improve type finding given the caps
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3296>
+2024-05-26 12:33:02 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-2022-10-30 13:07:14 +0530  Sanchayan Maity <sanchayan@asymptotic.io>
+	* libs/gst/helpers/ptp/ffi.rs:
+	  gstreamer: ptp-helper: Use `if_nametoindex` and `setsockopt` on Solaris / Illumos too
+	  Patch by Marcel Telka <marcel@telka.sk>.
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3552
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6947>
 
-	* libs/gst/base/gsttypefindhelper.c:
-	  typefindhelper: Update annotation for function parameters
-	  Fix the nullable/optional situation. allow-none is deprecated and
-	  replaced by either or both of the others.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3296>
+2024-05-26 12:31:33 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-2022-11-12 09:57:18 +0100  Edward Hervey <edward@centricular.com>
+	* libs/gst/helpers/ptp/net.rs:
+	  gstreamer: ptp-helper: Don't import `Context` trait multiple times unnecessarily
+	  This only affected the Solaris / Illumos code path.
+	  Patch by Marcel Telka <marcel@telka.sk>.
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3551
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6947>
 
-	* gst/gststreams.c:
-	  streams: Reset stream id field on finalize
-	  If debugging is activated, the parent class finalize might attempt to read it
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3390>
+2024-05-26 12:27:54 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-2022-11-09 09:28:37 +0100  Edward Hervey <edward@centricular.com>
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/net.rs:
+	  gstreamer: ptp-helper: Use `c_ulong` for `ifa_flags` on Solaris/Illumos
+	  Based on a patch by Marcel Telka <marcel@telka.sk>.
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3553
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6947>
 
-	* gst/gstchildproxy.c:
-	  childproxy: Fix documentation
-	  Warning: Gst: gst_child_proxy_get_child_by_name_recurse: unknown parameter
-	  'parent' in documentation comment, should be 'child_proxy'
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3370>
+2024-05-26 12:24:33 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-2022-11-08 17:45:37 +0200  Sebastian Dröge <sebastian@centricular.com>
+	* gst/meson.build:
+	* libs/gst/net/meson.build:
+	* meson.build:
+	* tests/check/meson.build:
+	* tests/misc/meson.build:
+	  gstreamer: Solaris/Illumos require linking to libnsl / libsocket for various socket APIs
+	  Patch by Tim Mooney <Tim.Mooney@ndsu.edu> from OpenIndiana/oi-userland
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6947>
+
+2024-05-17 11:03:51 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstclock.h:
+	  clock: Fix 32 bit assertions in GST_TIME_TO_TIMEVAL and GST_TIME_TO_TIMESPEC
+	  On various 32 bit systems, time_t is actually 64 bits while long is
+	  still only 32 bits. The macro would wrongly trigger its assertion in
+	  this case if a value with more than 68 years worth of seconds is
+	  converted.
+	  Examples are various newer 32 bit platforms and old ones that are
+	  compiled with -D_TIME_BITS=64.
+	  Also statically assert that time_t is either 32 or 64 bits. Other values
+	  might need adjustments in the macro.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6919>
+
+2024-05-21 21:50:47 +0300  Jordan Petridis <jordan@centricular.com>
 
-	* gst/gstallocator.c:
-	  allocator: Switch `allow-none` annotations to `nullable` / `optional`
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3364>
+	* tests/check/gst/gststructure.c:
+	  tests/check: Avoid using "bool" for the variable name
+	  Glib 2.82 will be aliasing [1] TRUE and FALSE to the C99
+	  definitions, which means it will be including stdbool.h
+	  As such, having variables named "bool" causes issues
+	  since it conflicts with the symbol defined in stdbool.h
+	  [1] https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4001
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6896>
 
-2022-11-08 17:44:54 +0200  Sebastian Dröge <sebastian@centricular.com>
+2024-05-17 23:03:19 +0900  Seungha Yang <seungha@centricular.com>
 
-	* gst/gstallocator.c:
-	  allocator: Copy allocator name in gst_allocator_register()
-	  The parameter is not marked as `transfer full` and stays around in the
-	  hash table, so we will have to copy it ourselves.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3364>
+	* meson.build:
+	* plugins/elements/gstfilesrc.c:
+	  filesrc: Don't abort on _get_osfhandle()
+	  _get_osfhandle() expects valid fd and CRT will abort program
+	  if given paramerter is invalid. The fd can be invalidated
+	  in various way, file was deleted by other process after
+	  we open a file. To avoid it, our own exception
+	  handler must be installed so that _get_osfhandle() can return
+	  INVALID_HANDLE_VALUE if fd is invalid.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6879>
 
-2022-11-08 08:56:47 +0100  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+2024-05-14 23:30:56 +0200  Alexander Slobodeniuk <aslobodeniuk@fluendo.com>
 
-	* plugins/tracers/gstlatency.c:
-	  tracers: latency: document the 'reported' flag
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3359>
+	* gst/gstsystemclock.c:
+	  systemclock: fix usage of __STDC_NO_ATOMICS__
+	  __STDC_NO_ATOMICS doesn't seem to exist. In fact the only compiler
+	  I've found that sets any of those is msvc, but it sets
+	  __STDC_NO_ATOMICS__, not __STDC_NO_ATOMICS.
+	  __STDC_NO_ATOMICS__ is the one documented by C11 standard.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6856>
 
-2022-11-08 02:08:08 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-04-30 00:36:59 +0100  Tim-Philipp Müller <tim@centricular.com>
 
 	* meson.build:
-	  Back to development
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3358>
+	  Back to development after 1.24.3
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6772>
 
-=== release 1.21.2 ===
+=== release 1.24.3 ===
 
-2022-11-07 23:53:59 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-04-30 00:15:23 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-	* ChangeLog:
 	* NEWS:
 	* RELEASE:
 	* gstreamer.doap:
 	* meson.build:
-	  Release 1.21.2
+	  Release 1.24.3
 
-2022-11-07 23:53:57 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-04-10 16:29:15 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* ChangeLog:
-	  Update ChangeLogs for 1.21.2
+	* libs/gst/helpers/ptp/parse.rs:
+	  ptp: Silence warning about some unused trait methods
+	  These are not used yet but will likely be useful in the future.
+	  Rust 1.79 (nightly) is warning about them being unused.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6606>
 
-2022-11-07 09:27:09 -0500  Xavier Claessens <xavier.claessens@collabora.com>
+2024-04-10 00:04:02 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-	* docs/meson.build:
-	  hotdoc: gst-hotdoc-plugins-scanner is not needed for libraries
-	  Meson >= 0.64.0 does not allow any more to add executables into
-	  hotdoc.generate_doc(..., dependencies: ...) and it should not be needed
-	  any way.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3352>
+	* meson.build:
+	  Back to development after 1.24.2
 
-2020-09-01 16:01:08 +0200  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
+=== release 1.24.2 ===
 
-	* tests/check/gst/gstinfo.c:
-	  tests: gstinfo: Test set_threshold_from_string's new reset behavior
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/605>
+2024-04-09 21:48:55 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-2020-08-22 23:42:40 +0200  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.24.2
 
-	* tests/check/gst/gstinfo.c:
-	  tests: gstinfo: Make logging tests pass when GST_DEBUG is set
-	  Use gst_debug_set_threshold_from_string's new reset behavior to undo
-	  GST_DEBUG and ensure the logging tests have a known configuration.
-	  `gst_debug_set_threshold_from_string ("LOG", TRUE)` has the same effect
-	  as `gst_debug_set_threshold_from_string ("", TRUE)` followed by
-	  `gst_debug_set_default_threshold (GST_LEVEL_LOG)`.
-	  Don't bother remembering the default log level set when the test
-	  started. It will get reset by the next test, anyway.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/605>
-
-2020-08-22 22:41:15 +0200  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
+2024-04-02 11:54:52 -0400  Xavier Claessens <xavier.claessens@collabora.com>
 
-	* gst/gstinfo.c:
-	  info: Reset patterns with set_threshold_from_string
-	  TLDR: Make `gst_set_threshold_from_string ("", TRUE)` reset *all*
-	  threshold settings, including those set by previous invocations of
-	  `gst_debug_set_threshold_from_string`.
-	  The docs say:
-	  @reset: %TRUE to clear all previously-set debug levels before setting
-	  new thresholds
-	  What actually happens is it sets the default threshold to `ERROR`,
-	  leaves the patterns in place and calls
-	  `gst_debug_category_reset_threshold` on each category.
-	  In effect, any category that is matched by a pattern gets reset to that
-	  threshold if the app changed it by directly invoking
-	  `gst_debug_category_set_threshold`. All other categories are reset to
-	  `ERROR`.
-	  In my opinion this parameter currently has little value, as the same
-	  effect can be achieved by including `ERROR` (without a pattern) in the
-	  string, as in `"foo*:WARNING,*bar:INFO,ERROR"`.
-	  What I actually expect it to do is reset *all* threshold settings,
-	  including those set by previous invocations of
-	  `gst_debug_set_threshold_from_string`, starting off with a clean slate
-	  for the patterns provided with the call.
-	  Otherwise there is no API to do this, besides:
-	  - Painfully removing patterns one-by-one via
-	  `gst_debug_unset_threshold_for_name` *if* you know what the patterns
-	  are.
-	  - Adding a `*:FOO` pattern to affect all categories, which makes the
-	  default threshold useless and practically leaks all the old
-	  patterns.
-	  In my opinion this also makes it fit better into the layers of threshold
-	  config, which is:
-	  1. Temporary:
-	  - `gst_debug_category_set_threshold`
-	  - `gst_debug_category_reset_threshold`
-	  2. Patterns:
-	  - `gst_debug_set_threshold_for_name`
-	  - `gst_debug_unset_threshold_for_name`
-	  - `gst_debug_set_threshold_from_string`
-	  - `GST_DEBUG`
-	  3. Default:
-	  - `gst_debug_set_default_threshold`
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/605>
-
-2022-09-21 10:05:05 +0200  Edward Hervey <edward@centricular.com>
+	* plugins/elements/gstclocksync.c:
+	  clocksync: Proxy allocation queries
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6525>
 
-	* gst/gstpad.c:
-	  gstpad: Avoid race in (un)setting EOS flag on sinkpads
-	  The scenario is the following:
-	  * Thread 1 is pushing an EOS event on a sinkpad
-	  * Thread 2 is pushing a STREAM_START event on the same sinkpad before Thread 1
-	  returns. Note : It starts pushing the event after Thread 1 took the object lock.
-	  There is a potential race between:
-	  * The moment Thread 1 sets the EOS flag once it has finished sending the
-	  event (via store_sticky_event). When it does that it has both the STREAM and
-	  OBJECT lock
-	  * The moment Thread 2 sends the STREAM_START event (Which should release that
-	  EOS status), but removing the EOS flag is only done while holding the OBJECT
-	  lock and not the STREAM_LOCK, which means it could be re-set by Thread 1 before
-	  it then checks again the EOS flag (without the STREAM lock taken).
-	  The EOS flag unsetting by STREAM_START should be done with the STREAM lock
-	  taken, otherwise it will be racy.
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1452
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3320>
-
-2022-11-06 18:10:44 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-03-27 16:55:10 +0000  L. E. Segovia <amy@centricular.com>
 
-	* tools/gst-inspect.c:
-	  gst-inspect: print doc urls for Rust plugins
-	  We have documentation for them now after all.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3346>
+	* gst/gstsystemclock.c:
+	* meson.build:
+	  gst: clock: Block futex_time64 usage on Android API level < 30
+	  This syscall is seccomp blocked on all lower API levels:
+	  https://github.com/aosp-mirror/platform_bionic/commit/ee7bc3002dc3127faac110167d28912eb0e86a20
+	  While at it, also fix all direct tests on __NR_futex_time64 and
+	  __NR_futex so that they refer to the results available in
+	  config.h.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6518>
 
-2022-11-05 00:06:25 +0000  Tim-Philipp Müller <tim@centricular.com>
+2024-03-26 19:40:04 +0530  Taruntej Kanakamalla <taruntej@asymptotic.io>
 
-	* plugins/elements/gstidentity.c:
-	  identity: fix "handoff" signal docs
-	  The docs list an extra pad argument, which doesn't
-	  match the actual signal function signature. Probably
-	  a copy'n'paste mistake when copying things from fakesink.
-	  Fixes #1546
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3337>
+	* libs/gst/net/gstptpclock.c:
+	  net/gstptpclock: fix double free of domain data during deinit
+	  The attempt to free the domain data is happeing twice during the ptp deinit.
+	  Once while iterating through the list domain_data and second while iterating
+	  through the list domain_clocks, so this is crashing the application
+	  trying to gst_ptp_deinit
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6457>
 
-2022-10-24 12:13:14 +0200  Edward Hervey <edward@centricular.com>
+2024-03-27 17:05:09 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gstpad.c:
-	  gstpad: Fix non-serialized sticky event push
-	  With non-serialized sticky events, such as GST_EVENT_INSTANT_RATE, we both want
-	  to store the event (for later re-linking) *AND* push the event in a non-blocking
-	  way.
-	  We therefore must *not* propagate pending sticky events if the event is "sticky
-	  or serialized" but only if it's "serialized"
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3254>
+	* libs/gst/base/gstbasesrc.c:
+	  basesrc: Clear submitted buffer lists consistently with buffers
+	  And handle the case of a NULL buffer being returned cleanly, which is
+	  valid as long as a buffer list is returned instead. Previously this
+	  would cause an assertion because of calling gst_buffer_unref() with
+	  NULL.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6463>
 
-2022-08-17 22:34:35 -0600  Michael Gruner <michael.gruner@ridgerun.com>
+2024-03-26 14:28:28 +0100  Arnaud Vrac <avrac@freebox.fr>
 
-	* gst/parse/grammar.y.in:
-	  parse: do delayed set only if the target child was not found and fail otherwise
-	  When using the child proxy notation (child::property=value) it may
-	  happen that the target child does not exist at the time of parsing
-	  (i.e: decodebin creates the encoder according to the contents of the
-	  stream). On this cases, we want to delay the setting of the property
-	  to later, when new elements are added. Previous logic performed a
-	  delayed set even if the target child was found but the property
-	  was not found in it. This should be treated as a failure because,
-	  unlike missing elements, properties should not appear dynamically.
-	  By not failing, typos in property names may go unnoticed to the end
-	  user.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2908>
-
-2022-10-18 18:15:12 +0200  Michael Gruner <michael.gruner@ridgerun.com>
-
-	* gst/gstchildproxy.c:
-	* gst/gstchildproxy.h:
-	  childproxy: Implement a new ::get_child_by_name_recurse() API
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2908>
-
-2022-10-27 15:13:36 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* plugins/elements/gstinputselector.c:
+	  inputselector: fix possible clock leak on shutdown
+	  Avoid leaking a GstClock object on shutdown, bail out before taking the ref when
+	  not playing.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6455>
 
-	* libs/gst/base/gstaggregator.c:
-	* libs/gst/base/gstbaseparse.c:
-	  core/base: Only post latency messages if the latency values have actually changed
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1525
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3282>
+2024-03-22 01:38:06 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-2022-10-27 11:18:24 +0200  Edward Hervey <edward@centricular.com>
+	* meson.build:
+	  Back to development
 
-	* plugins/elements/gstconcat.c:
-	  concat: Properly propagate EOS seqnum
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3284>
+=== release 1.24.1 ===
 
-2022-10-25 09:39:07 +0300  Sebastian Dröge <sebastian@centricular.com>
+2024-03-21 21:47:53 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gsturi.c:
-	* libs/gst/net/gstnettimepacket.c:
-	* libs/gst/net/gstntppacket.c:
-	  Fix various warnings from gobject-introspection
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3261>
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.24.1
 
-2022-10-22 01:43:22 +0900  Seungha Yang <seungha@centricular.com>
+2024-03-19 08:57:43 -0400  Thomas Goodwin <thomas.goodwin@laerdal.com>
 
+	* tests/check/tools/gstinspect.c:
 	* tools/gst-inspect.c:
-	  gst-inspect: Hide GST_PARAM_DOC_SHOW_DEFAULT flag
-	  It's known flag but only for documentation purpose. Don't show
-	  its (and user cannot understand) value 0x2000
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3241>
+	  gst-inspect: fix --atleast-version to be implicitly applied to --exists
+	  The --atleast-version implies --exists, but the implementation in
+	  earlier commits had the version check applied any time the --exists was
+	  checked, and the default value of the major and minor versions were set
+	  to the GStreamer major and minor versions.  The resulting behavior would
+	  have gst-inspect return '1' if the plugin's version didn't match
+	  gstreamer's even when --atleast-version was not specified in the command
+	  line args.  The change in this patch removes that behavior and adds
+	  tests to verify that if --exists is specified WITHOUT --atleast-version
+	  the version check will NOT be applied.  If both arguments are specified
+	  and the version does not match the arg-supplied version number, a new
+	  return code of '2' is used to uniquely identify the failure.
+	  Fixes #3246
+	  Signed-off-by: Thomas Goodwin <thomas.goodwin@laerdal.com>
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6414>
+
+2024-03-13 19:12:48 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-2022-10-22 18:34:14 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Initialize expected DELAY_REQ seqnum to an invalid value
+	  This allows distinguishing pending syncs that didn't have a DELAY_REQ
+	  sent from ones that did but used a seqnum of 0, like the very first one.
+	  Specifically, if the first one or more syncs are still pending and we
+	  send the first DELAY_REQ for a later pending sync, then the DELAY_RESP
+	  would've been wrongly associated to the very first pending sync because
+	  of the seqnum.
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3383
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6365>
+
+2024-03-11 15:10:25 +0100  Antonio Larrosa <alarrosa@suse.com>
 
-	* libs/gst/net/gstnetclientclock.c:
-	  net: Add missing nullable annotation on the name parameter in the net/NTP clock constructors
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3249>
+	* gst/gstregistry.c:
+	* libs/gst/net/gstptpclock.c:
+	  registry, ptp: Canonicalize the library path returned by dladdr
+	  On systems using UsrMerge (like openSUSE or Fedora), /lib64 is
+	  a symlink to /usr/lib64. So dladdr is returning the path to
+	  the gstreamer library in /lib64 in priv_gst_get_relocated_libgstreamer.
+	  Later gst_plugin_loader_spawn tries to build the path to the
+	  gst-plugin-scanner helper from /lib64 and ends up trying to use
+	  /lib64/../libexec/gstreamer-1.0/gst-plugin-scanner which doesn't exist.
+	  By canonicalizing the path with a call to realpath, gst-plugin-scanner
+	  is found correctly under
+	  /usr/lib64/../libexec/gstreamer-1.0/gst-plugin-scanner
+	  Similar change applied to gstreamer/libs/gst/net/gstptpclock.c
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6343>
+
+2024-02-27 18:59:41 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
 
-2022-10-22 22:04:57 +0900  Seungha Yang <seungha@centricular.com>
+	* gst/gsturi.c:
+	  gsturi: Sort by feature name to break a feature rank tie
+	  This matches autoplug in other places such as decodebin, otherwise we
+	  will pick "randomly" based on the order in which plugins are
+	  registered, which is mostly dependent on the order in which readdir()
+	  returns items.
+	  So let's make it predictable.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6342>
 
-	* gst/gstpadtemplate.c:
-	  padtemplate: Fix annotations
-	  gst_caps_replace() does not take ownership of the new caps
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3248>
+2024-03-08 17:05:34 +1100  Jan Schmidt <jan@centricular.com>
 
-2022-10-22 05:29:59 +0900  Seungha Yang <seungha@centricular.com>
+	* plugins/elements/gstidentity.c:
+	  identity: Don't refuse seeks unless single-segment=true
+	  identity only needs to configure the internal seek segment if it's
+	  aggregating upstream segments into 1. If it's not, don't break
+	  other seek behaviour by refusing (for example) instant-rate change
+	  seeks.
+	  Fixes: #3363
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6314>
+
+2024-02-25 04:26:21 +1100  Jan Schmidt <jan@centricular.com>
+
+	* gst/gstsegment.c:
+	  gstsegment: Don't use g_return_val_if_fail()
+	  Don't use g_return_val_if_fail() to catch the
+	  open-ended segment or empty segment cases in
+	  gst_segment_to_running_time_full()
+	  g_return_val_if_fail() is for programmer errors,
+	  and can be compiled out with a flag.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6275>
+
+2024-03-05 15:10:45 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/meson.build:
+	  ptp: Don't install test executable
+	  And handle it like all our other test executables.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6268>
+
+2024-03-05 13:45:27 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* tools/gst-inspect.c:
-	  gst-inspect: Don't print link to doc if it's known to be unavailable
-	  "gst_element_factory_get_skip_documentation() == true" means
-	  documentation was intentionally skipped for the element feature
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3243>
+	* meson.build:
+	  Back to development
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6264>
 
-2022-10-21 11:47:11 +0200  François Laignel <fengalin@free.fr>
+=== release 1.24.0 ===
 
-	* gst/gstquery.c:
-	  gst: uri query: fix inconsistent `uri` nullability  assertion
-	  Functions `gst_query_set_uri` and `gst_query_set_uri_redirection`
-	  can both set a `NULL` `uri`, as annotated in the documentation.
-	  However the functions bodies reject `NULL` `uri`s.
-	  See [1] for a discussion on that matter.
-	  [1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1134#note_1600988
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3237>
+2024-03-04 23:51:42 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-10-21 11:11:13 +0200  Thibault Saunier <tsaunier@igalia.com>
+	* NEWS:
+	* README.md:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.24.0
 
-	* docs/gst-hotdoc-plugins-scanner.c:
-	  docs: plugins-scanner: Handle interface used for plugin API properties
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3236>
+2024-02-26 09:27:40 +0100  Edward Hervey <edward@centricular.com>
 
-2022-10-18 03:08:44 +0900  Seungha Yang <seungha@centricular.com>
+	* README.md:
+	* RELEASE:
+	  docs: Use Discourse and Matrix as prefered communication channels
+	  Part of: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6220
 
-	* docs/gst-hotdoc-plugins-scanner.c:
-	  docs: plugin-scanner: Stop updating "long-name" metadata
-	  The "long-name" value can be environment dependent, and it's not
-	  actually used by our documentation.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3208>
+2024-02-26 09:26:44 +0100  Edward Hervey <edward@centricular.com>
 
-2022-10-19 22:30:38 +0900  Seungha Yang <seungha@centricular.com>
+	* .gitlab/issue_templates/Bug.md:
+	  gitlab_template: Remove duplicate entry and remove mention of IRC
+	  Part of: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6220
 
-	* gst/parse/grammar.y.in:
-	  parse: Adjust debug log level
-	  That's not an error case at all
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3228>
+2024-02-21 12:20:19 +0100  Arnaud Vrac <avrac@freebox.fr>
 
-2022-10-19 13:34:28 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* plugins/elements/gstqueue2.c:
+	  queue2: post 100% buffering message even when waiting for space to be freed
+	  In the case where the queue shrinks due to a property change and the queue
+	  becomes full, we would set the waiting_del flag, which would prevent posting the
+	  100% buffering message on the bus. Since the pipeline is not aware of the new
+	  buffering value, in the common case where the pipeline is paused during
+	  buffering, it would never resume.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6165>
 
-	* gst/gstdeviceproviderfactory.c:
-	* gst/gstelementfactory.c:
-	  {element,deviceprovider}factory: g_object_new() can't ever return NULL
-	  So treat it as the assertion it is.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3226>
+2024-02-21 12:17:45 +0100  Arnaud Vrac <avrac@freebox.fr>
 
-2022-10-19 13:33:39 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* plugins/elements/gstqueue2.c:
+	  queue2: move gst_queue2_get_buffering_message code to the only call site
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6165>
 
-	* gst/gstelementfactory.c:
-	  elementfactory: Handle element factory loading failure in gst_element_factory_create_valist() not as assertion
-	  In gst_element_factory_create_with_properties() it is a normal error
-	  path so let's keep this consistent.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3226>
+2024-02-21 12:05:18 +0100  Arnaud Vrac <avrac@freebox.fr>
 
-2022-10-19 13:28:06 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* plugins/elements/gstqueue2.c:
+	* plugins/elements/gstqueue2.h:
+	  queue2: remove redundant check to avoid posting the same buffering value twice
+	  Remove the percent_changed check to determine whether a buffering message should
+	  be posted. The check on the last posted buffering value is sufficient, and the
+	  removal doesn't introduce additional complexity.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6165>
 
-	* gst/gstdeviceproviderfactory.c:
-	* gst/gstelementfactory.c:
-	* gst/gstmeta.c:
-	* gst/gstregistry.c:
-	* gst/gsttaglist.c:
-	* gst/gstvalue.c:
-	  gst: Use G_TYPE_INVALID instead of 0 for GTypes
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3226>
+2024-02-21 11:41:32 +0100  Arnaud Vrac <avrac@freebox.fr>
 
-2022-09-15 00:06:49 +0200  Mathieu Duponchelle <mathieu@centricular.com>
+	* plugins/elements/gstqueue2.c:
+	  queue2: consolidate buffering message posting code
+	  No need to copy paste the code, simply call the common gst_queue2_post_buffering
+	  function.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6165>
 
-	* tests/check/pipelines/parse-launch.c:
-	  tests: parse-launch: remove assignment order tests
-	  These tests relied on setting the name of an element twice to verify
-	  that the last one set took precedence, however name is a CONSTRUCT property
-	  and the parser now errors out when such properties are set twice, in
-	  g_object_new_with_properties .
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3026>
+2024-02-21 11:17:13 +0100  Arnaud Vrac <avrac@freebox.fr>
 
-2022-09-13 23:16:08 +0200  Mathieu Duponchelle <mathieu@centricular.com>
+	* plugins/elements/gstqueue2.c:
+	  queue2: make sure update_buffering is called with the lock taken
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6165>
+
+=== release 1.23.90 ===
+
+2024-02-23 18:20:11 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.23.90
+
+2024-02-21 16:56:48 +0100  Jochen Henneberg <jh@henneberg-systemdesign.com>
+
+	* libs/gst/helpers/ptp/main.rs:
+	  ptp-helper: Allow sync to master clock on same host
+	  If we drop all messages with the same clock id as ours we will also
+	  drop all messages coming from a PTP clock on our host since both clock
+	  ids are build from the same MAC address.
+	  At least for Linux we do not see our own messages anyway since the
+	  network stack can well distinguish between multicast send from our
+	  socket or from another socket on the same machine. To make sure that
+	  this works for all supported platforms just drop delay requests since
+	  this is the only message that is sent from the GStreamer PTP clock.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6172>
+
+2023-01-28 01:11:45 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tools/gst-inspect.c:
+	  gst-inspect: print plugin error/warning/info status messages
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3832>
+
+2023-01-27 19:08:37 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/gst_private.h:
+	* gst/gstplugin.c:
+	* gst/gstplugin.h:
+	* gst/gstregistrybinary.h:
+	* gst/gstregistrychunks.c:
+	* tests/check/gst/gstplugin.c:
+	  plugin: add API for plugins to provide status info messages
+	  This can be used to store informational messages, errors or
+	  warnings which can later be shown to the user in gst-inspect-1.0,
+	  which can be useful for plugins that expose elements dynamically
+	  based on external libraries or hardware capabilities.
+	  Status messages can then provide an indication as to why a
+	  plugin doesn't have any elements listed, for example.
+	  Plus unit test to make sure code paths are exercised a little.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3832>
+
+2024-01-29 19:47:11 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/parse/grammar.y.in:
-	* gst/parse/types.h:
-	* tests/check/pipelines/parse-launch.c:
-	  parse: refactor to make use of gst_element_factory_make_with_properties
-	  Instead of creating the element first, then setting properties and
-	  presets, we gather those and construct the element with the properties.
-	  This means users of gst_parse_launch can now set construct-only
-	  properties.
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1380
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3026>
-
-2022-10-18 16:41:36 +0200  Bunio_FH <buniofh@gmail.com>
-
-	* gst/gstminiobject.c:
-	  gstminiobject: shares capacity increase
-	  during the MSE (WebKit) tests from Apple suite:
-	  https://hls-streaming.cdn-apple.com/hls_conformance/dist/v1.1/index.html?pretty=true&whitelist=MSE%20Suite
-	  webkit attempts to add a single audio buffer containing ~35.5k frames.
-	  when corresponding GstSamples are pulled buffer is being referenced
-	  more than object capacity allows: 2^15-1. since the case could be considered
-	  malformed a surgical patch is applied to increase the capacity.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3221>
-
-2022-10-15 12:31:17 +0300  Sebastian Dröge <sebastian@centricular.com>
-
-	* gst/gstatomicqueue.c:
-	* gst/gstbuffer.c:
-	* gst/gstbufferpool.c:
-	* gst/gstbufferpool.h:
-	* gst/gstelement.c:
-	* gst/gstevent.c:
-	* gst/gstinfo.c:
-	* gst/gstmessage.c:
 	* gst/gstobject.c:
-	* gst/gstparse.c:
-	* gst/gstpipeline.c:
-	* gst/gstquery.c:
-	* gst/gststructure.c:
-	* gst/gsttaglist.c:
-	* gst/gsttoc.c:
-	* gst/gsturi.c:
-	* gst/gstutils.c:
-	  core: Add/fix various annotations
-	  And fix memory leaks/null pointer dereferences in GstUri in error cases.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3194>
+	* gst/gstobject.h:
+	* tests/check/gst/gstbin.c:
+	  gstobject: add CONSTRUCTED flag
+	  This can be used later by base class APIs to know whether they're
+	  called from a subclass instance init function (where the object
+	  isn't properly constructed yet and one should only really poke
+	  at the instance structure but not much else) or after object
+	  construction has been finished.
+	  Fix up GstBin unit test for CONSTRUCTED flag addition.
+	  See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2794
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6150>
+
+2024-02-20 08:54:11 +0100  Edward Hervey <edward@centricular.com>
 
-2022-10-15 12:24:46 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* gst/gstmeta.c:
+	  meta: Skip gst_meta_info_new in gir
+	  ```
+	  gstmeta.c:500: Warning: Gst: gst_meta_info_new: return value: Invalid
+	  non-constant return of bare structure or union; register as boxed type or (skip)
+	  ```
+	  Skip this for now
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6147>
 
-	* libs/gst/check/gstharness.c:
-	  check: Add/fix various annotations
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3194>
+2024-02-19 12:25:01 +0000  Philippe Normand <philn@igalia.com>
 
-2022-10-15 12:20:08 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* gst/gstprotection.c:
+	  protection: Document `original-media-type` caps field
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6142>
 
-	* libs/gst/net/gstnetaddressmeta.c:
-	* libs/gst/net/gstnettimepacket.c:
-	* libs/gst/net/gstnettimeprovider.c:
-	* libs/gst/net/gstntppacket.c:
-	  net: Add/fix various annotations
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3194>
+2024-02-16 17:06:52 +0100  Guillaume Desmottes <guillaume.desmottes@onestream.live>
 
-2022-10-15 12:18:28 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* docs/gst-hotdoc-plugins-scanner.c:
+	  docs: initialize values when GST_PLUGIN_API_FLAG_IGNORE_ENUM_MEMBERS is set
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5491>
 
-	* libs/gst/base/gstqueuearray.c:
-	  base: Add/fix annotations in GstQueueArray
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3194>
+2024-02-15 09:21:15 -0500  Xavier Claessens <xavier.claessens@collabora.com>
 
-2022-10-14 23:48:09 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* gst/gstbus.c:
+	  bus: do not leak message on invalid handler return value
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6124>
 
-	* libs/gst/controller/gsttimedvaluecontrolsource.c:
-	  controller: Add/fix various annotations
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3194>
+2024-02-15 09:15:50 -0500  Xavier Claessens <xavier.claessens@collabora.com>
 
-2022-10-07 14:39:47 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+	* gst/gstbus.c:
+	  bus: do not leak messages if there is no async handler
+	  This does not typically happen because "enable-async" property is TRUE
+	  by default. The only place where it is set to FALSE is in GstBin where a
+	  sync handler is used and always returns GST_BUS_DROP.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6124>
 
-	* libs/gst/base/gstaggregator.c:
-	  aggregator: fix input buffering
-	  We need to be able to buffer at least the aggregator latency +
-	  upstream latency, which is the value used to compute the aggregator
-	  deadline.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3138>
+2024-02-15 09:18:20 -0500  Xavier Claessens <xavier.claessens@collabora.com>
 
-2022-10-01 04:58:04 +1000  Jan Schmidt <jan@centricular.com>
+	* gst/gstbus.c:
+	  bus: warn when message queue grows too much
+	  It usually means application is not handling messages causing memory
+	  consumption to grow infinitely.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3313>
 
-	* gst/gstbin.c:
-	  gstbin: Use g_queue_clear_full()
-	  Use g_queue_clear_full() to release the child list
-	  instead of iterating over the list twice.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3101>
+2024-02-15 16:38:53 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-10-01 04:55:49 +1000  Jan Schmidt <jan@centricular.com>
+	* meson.build:
+	  Back to development
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6126>
 
-	* gst/gstbin.c:
-	  gstbin: Fix a potential leak in gst_bin_do_deep_add_remove()
-	  If a child element of a bin is unparented while
-	  gst_bin_do_deep_add_remove() is iterating the children,
-	  don't leak a ref to it.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3101>
+=== release 1.23.2 ===
 
-2022-10-01 04:54:20 +1000  Jan Schmidt <jan@centricular.com>
+2024-02-15 15:37:17 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstiterator.c:
-	  gstiterator: Don't use gst_object_unref() for a GObject
-	  The owner of a GstIterator is a plain GObject. Don't unref it
-	  with gst_object_unref(), or it will be logged in tracer
-	  info incorrectly.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3101>
+	* NEWS:
+	* RELEASE:
+	* gstreamer.doap:
+	* meson.build:
+	  Release 1.23.2
+
+2024-02-14 00:35:55 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* po/LINGUAS:
+	* po/fr.po:
+	* po/lv.po:
+	* po/nl.po:
+	* po/sv.po:
+	* po/tr.po:
+	  gstreamer: update translations
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6113>
 
-2022-10-04 03:57:31 +0100  Tim-Philipp Müller <tim@centricular.com>
+2024-02-03 11:51:27 +0000  Philippe Normand <philn@igalia.com>
+
+	* gst/gsttaglist.c:
+	* gst/gsttaglist.h:
+	  taglist: Register new tag for container specific track ID
+	  Unique identifier for the audio, video or text track this tag is associated
+	  with. The mappings for several container formats are defined in the [Sourcing
+	  In-band Media Resource Tracks from Media Containers into HTML
+	  specification](https://dev.w3.org/html5/html-sourcing-inband-tracks).
+	  Based on previous patch by Brendan Long.
+	  Fixes #45
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6041>
+
+2024-02-10 00:34:18 +0900  Seungha Yang <seungha@centricular.com>
+
+	* gst/gstpluginloader-win32.c:
+	  pluginloader-win32: Early terminate if plugin loader binary is not installed
+	  External plugin loader support for Windows is introduced
+	  in this dev cycle. Since helper binary was not required (useless)
+	  before this version, people may not ship the binary
+	  with new GStreamer version, then they will observe warning message.
+	  Instead of displaying the warning at plugin loading time,
+	  checks helper bin earlier and disable external plugin loader
+	  if helper binary is not installed.
+	  Fixes: https://gitlab.freedesktop.org/gstreamer/cerbero/-/issues/448
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6083>
+
+2023-12-18 15:39:07 -0500  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/gstmeta.c:
+	* gst/gststructure.c:
+	* gst/gststructure.h:
+	* gst/gstvalue.c:
+	* tests/check/gst/gststructure.c:
+	  structure: Allow STRICT flag only in _serialize_full()
+	  The STRICT flag makes _serialize() nullable which is an API break for
+	  bindings. Forbid it and add _serialize_full() that accepts it and is
+	  properly annotated.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5829>
+
+2021-11-10 13:26:33 +0100  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* libs/gst/base/gstbasesrc.c:
+	  basesrc: add FIXME 2.0 about automatic_eos
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1334>
+
+2024-02-06 18:09:02 +0000  Tim-Philipp Müller <tim@centricular.com>
 
 	* meson.build:
 	  Back to development
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3115>
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6066>
 
-=== release 1.21.1 ===
+=== release 1.23.1 ===
 
-2022-10-04 01:14:01 +0100  Tim-Philipp Müller <tim@centricular.com>
+2024-02-06 16:37:19 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* ChangeLog:
 	* NEWS:
 	* RELEASE:
 	* gstreamer.doap:
 	* meson.build:
-	  Release 1.21.1
+	  Release 1.23.1
 
-2022-10-04 01:13:59 +0100  Tim-Philipp Müller <tim@centricular.com>
+2024-02-05 09:27:54 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-	* ChangeLog:
-	  Update ChangeLogs for 1.21.1
+	* meson_options.txt:
+	  meson_options.txt: fix meson warning about default bool values being a string
 
-2022-10-03 11:16:25 +0200  Edward Hervey <edward@centricular.com>
+2024-02-05 18:37:59 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-	* plugins/elements/gstqueue2.c:
-	  queue2: Hold the lock when modifying sinkresult
-	  As it's done elsewhere. Avoids a potential race of the field being modified in
-	  the meantime.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3110>
+	* gst/gstpad.c:
+	  pad: Copy over seqnum when creating a new segment event for applying pad offset
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6057>
+
+2024-02-06 10:02:03 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstutils.c:
+	  utils: Remove unnecessary const-removal casts from gst_util_filename_compare()
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6063>
+
+2024-02-06 09:48:17 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstutils.c:
+	  utils: Annotate gst_util_filename_compare() parameters as filenames
+	  They're not UTF-8 strings.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6063>
+
+2024-01-26 19:12:18 +0100  Piotr Brzeziński <piotr@centricular.com>
+
+	* gst/gstmacos.m:
+	  macos: Fix gst_macos_main() terminating whole process before returning a value
+	  Removes the usage of [NSApp terminate] to avoid killing the process and thus never actually returning a value.
+	  The new way is just to use [NSApp stop] and send an event, since stop only happens after an event is processed.
+	  Unlike terminate, stop will only halt the event loop, not the whole process.
+	  This uses an NSApplicationDelegate to listen for NSApp finishing the launch process, and then signals the 'main' thread
+	  to proceed. That makes sure to never call [NSApp stop] before NSApp is actually running, which could happen if the
+	  provided 'main' function finished quickly enough.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6005>
+
+2024-01-29 16:10:38 -0300  Thibault Saunier <tsaunier@igalia.com>
+
+	* libs/gst/base/gstbasesrc.c:
+	  basesrc: Lower verbosity  of often happening warning
+	  decodebin(3) runs a scheduling query before pads are activated which
+	  ultimately triggers basesrc->start which will automatically call
+	  `gst_base_src_start_complete` for any source that is not marked as
+	  'async'. This calls will harmlessly bail out in `not_activated_yet`
+	  so we should not warn in that case.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6011>
+
+2024-01-23 15:28:50 +0100  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* gst/gstpad.c:
+	  core: pad: call tracer query-post hook after probes
+	  Tracers are likely interested about the end result of the query, so
+	  after probes have been caled.
+	  Fix a bug where the buffer-lateness tracer was reporting a wrong latency
+	  when pad probes increased the latency.
+	  Also call the tracer hook if the pad has no query function.
+	  Fix https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/issues/486
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5963>
+
+2023-11-21 19:54:32 -0300  Thibault Saunier <tsaunier@igalia.com>
+
+	* libs/gst/base/gstbasesink.c:
+	  basesink: Preroll on out of segment buffers when not dropping them
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5980>
+
+2024-01-28 11:15:01 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* meson.build:
+	  meson: bump Meson requirement to >= 1.1 for all modules
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6002>
+
+2023-08-31 18:55:58 -0400  Thibault Saunier <tsaunier@igalia.com>
+
+	* libs/gst/helpers/gst_gdb.py:
+	  gdb: Fix the way we wrap segments
+	  Without that we end up with a reference to a GBoxed instead of the actual segment making the rest of the code fail
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5986>
+
+2023-08-31 18:55:14 -0400  Thibault Saunier <tsaunier@igalia.com>
+
+	* libs/gst/helpers/gst_gdb.py:
+	  gdb: Fix issue with undeclared variable
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5986>
+
+2023-08-31 18:53:46 -0400  Thibault Saunier <tsaunier@igalia.com>
+
+	* libs/gst/helpers/glib_gobject_helper.py:
+	* libs/gst/helpers/gst_gdb.py:
+	  gdb: Handle the case where the fundamental type table is optimized out
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5986>
+
+2023-08-31 18:52:58 -0400  Thibault Saunier <tsaunier@igalia.com>
+
+	* libs/gst/helpers/glib_gobject_helper.py:
+	* libs/gst/helpers/gst_gdb.py:
+	  gdb: Fix python style
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5986>
+
+2023-08-31 18:43:46 -0400  Thibault Saunier <tsaunier@igalia.com>
+
+	* libs/gst/helpers/glib_gobject_helper.py:
+	  gdb: Workaround optimized out quark_seq_id
+	  On fedora 38 (and it was the case in previous releases), the
+	  quark_seq_id is optimized out so getting quarks from the
+	  global variable always failed. This patch works around that by assuming
+	  it is a valid quark whenever the quark_seq_id is not accessible.
+	  This issue often manifested as Python Exception <class 'TypeError'>:
+	  can only concatenate str (not "NoneType") to str when debugging as
+	  other parts of the code assume that getting the quark for a GType name
+	  will work.
+	  Same as https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3559
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5986>
+
+2024-01-17 15:57:43 +0100  Jonas K Danielsson <jonas.danielsson@spiideo.com>
+
+	* gst/gstutils.c:
+	* gst/gstutils.h:
+	  gstutils: Add g_util_filename_compare
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4491>
+
+2023-04-24 09:28:22 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* gst/gstpipeline.c:
+	* gst/gstpipeline.h:
+	  core: pipeline: add gst_pipeline_get_configured_latency()
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4472>
+
+2023-04-21 17:49:50 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* gst/gstpipeline.c:
+	* gst/gstpipeline.h:
+	  core: pipeline: add gst_pipeline_is_live()
+	  Convenient API for applications wanting to check if a pipeline is live
+	  or not. Save them from checking the change_state return value or sending
+	  latency queries.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4472>
+
+2023-04-21 17:44:43 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* gst/gstpipeline.c:
+	  core: pipeline: protect priv->is_live with object lock
+	  It's supposed to be according to the comment where it's defined.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4472>
+
+2023-08-30 10:56:19 -0600  Scott Moreau <oreaus@gmail.com>
 
-2018-03-28 17:54:15 +0200  Philipp Zabel <p.zabel@pengutronix.de>
+	* tools/gst-launch.c:
+	  gst-launch: accept option to set program name
+	  The option --prog-name="PROGRAM-NAME" can be passed to set the program name.
+	  The program name is used by gtk and gstreamer to set the class or app-id.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5263>
+
+2023-04-05 08:48:36 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/gstobject.h:
+	* gst/gstpad.h:
+	* tests/check/gst/gstobject.c:
+	  gstpad, gstobject: Add GMutexLocker helper
+	  Add GST_OBJECT_AUTO_LOCK() and GST_PAD_STREAM_AUTO_LOCK() to simplify
+	  g_autoptr(GMutexLocker) usage.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4300>
+
+2024-01-05 14:32:00 +0100  Stéphane Cerveau <scerveau@igalia.com>
+
+	* gst/gstutils.c:
+	* gst/gstutils.h:
+	  gstutils: add gst_util_ceil_log2
+	  Move ceil_log2 from nalutils.* to gstutils.*
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5888>
+
+2023-12-29 10:15:49 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/io.rs:
+	  ptp-helper: Allow unused `Stderr` export
+	  It's not used when building tests and would otherwise cause a warning.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5872>
+
+2023-12-18 16:33:07 -0500  Olivier Crête <olivier.crete@collabora.com>
 
 	* gst/gstbuffer.c:
 	* gst/gstmeta.c:
 	* gst/gstmeta.h:
-	* libs/gst/base/gstadapter.c:
-	* libs/gst/base/gstbasetransform.c:
-	  buffer: drop parent meta in deep copy/foreach_metadata
-	  The purpose of a deep buffer copy is to be able to release the source
-	  buffer and all its dependencies. Attaching the parent buffer meta to
-	  the newly created deep copy needlessly keeps holding a reference to the
-	  parent buffer.
-	  The issue this solves is the fact you need to allocate more
-	  buffers, as you have free buffers being held for no reason. In the good
-	  cases it will use more memory, in the bad case it will stall your
-	  pipeline (since codecs often need a minimum number of buffers to
-	  actually work).
-	  Fixes #283
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2928>
-
-2022-09-26 14:17:18 +0300  Sebastian Dröge <sebastian@centricular.com>
+	  meta: Add API to register metas in two steps
+	  And also remove the specific registration APIs for
+	  serializable meta.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5830>
 
-	* gst/gsturi.c:
-	  gsturi: When setting the same string again do nothing
-	  Otherwise code like gst_uri_set_host(uri, gst_uri_get_host(uri)) would
-	  first free the string, then create a copy of the freed string and then
-	  assigned that.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3076>
+2023-12-18 13:40:53 -0500  Olivier Crête <olivier.crete@collabora.com>
 
-2022-09-15 16:22:23 +0200  Edward Hervey <edward@centricular.com>
+	* gst/gstbufferpool.c:
+	* gst/gstmeta.c:
+	* gst/gstmeta.h:
+	  meta: Move the clear operation to its own vfunc
+	  Some transforms always assumed that the transformation was some kind
+	  of copy. So adding a "clear" operation didn't work out in practice.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5830>
 
-	* libs/gst/base/gstbasetransform.c:
-	  basetransform: Avoid useless codepath
-	  If QoS is disabled, skip the whole computation (avoids calculating values which
-	  won't be needed)
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3034>
+2023-12-01 12:10:36 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
 
-2022-09-21 19:19:45 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+	* libs/gst/base/gstbaseparse.c:
+	  doc: baseparse: Clarify consumed vs output size
+	  When we finish a frame, we pass a size which semantic can easily be confused.
+	  Improve the documentation to clarify that the parameter size is the amount of
+	  input data being consumed and, if set, the output_buffer size can differ.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5754>
 
-	* meson.build:
-	  meson: Use implicit builtin dirs in pkgconfig generation
-	  Starting with Meson 0.62, meson automatically populates the variables
-	  list in the pkgconfig file if you reference builtin directories in the
-	  pkgconfig file (whether via a custom pkgconfig variable or elsewhere).
-	  We need this, because ${prefix}/libexec is a hard-coded value which is
-	  incorrect on, for example, Debian.
-	  Bump requirement to 0.62, and remove version compares that retained
-	  support for older Meson versions.
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1245
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3061>
-
-2022-09-12 09:46:43 -0400  Xavier Claessens <xavier.claessens@collabora.com>
-
-	* data/bash-completion/helpers/meson.build:
-	* data/meson.build:
-	* libs/gst/helpers/meson.build:
-	* tests/validate/meson.build:
-	* tools/meson.build:
-	  meson: Set install_tag on some targets
-	  Trying to follow recommendation from Meson documentation:
-	  https://mesonbuild.com/Installing.html#installation-tags
-	  Move tools into 'bin' or 'bin-devel' categories to keep only libs and
-	  plugins in the default 'runtime' category. This simplifies distribution
-	  of GStreamer application skipping parts that are not needed, similarly
-	  to what Cerbero does by hardcoding huge list of files.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3017>
+2023-12-15 17:47:02 -0500  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/gstmeta.c:
+	  meta: gst_meta_serialize() is not introspectable
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5355>
 
-2022-08-31 18:08:08 +0200  Paweł Stawicki <stawel+gstreamer@gmail.com>
+2023-09-18 19:24:35 -0400  Xavier Claessens <xavier.claessens@collabora.com>
 
-	* plugins/elements/gstqueue2.c:
-	  queue2: Fix deadlock when deactivate is called in pull mode
-	  check is flush was called before waiting on condition
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2967>
+	* gst/gst.h:
+	* gst/gstbuffer.c:
+	* gst/gstbuffer.h:
+	* gst/gstbytearrayinterface.h:
+	* gst/gstmeta.c:
+	* gst/gstmeta.h:
+	* gst/meson.build:
+	* tests/check/gst/gstbuffer.c:
+	* tests/check/gst/gstmeta.c:
+	  meta: Add serialize/deserialize API
+	  This allows metas to be serialized to be transmitted or stored. This is
+	  intended to be used for example by gdppay or unixfdsink.
+	  Implemented on GstCustomMeta, GstVideoMeta, GstReferenceTimestampMeta,
+	  and GstAudioMeta.
+	  Sponsored-by: Netflix Inc.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5355>
+
+2023-09-20 15:34:40 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/gststructure.c:
+	* gst/gststructure.h:
+	* tests/check/gst/gststructure.c:
+	  structure: Add GST_SERIALIZE_FLAG_STRICT
+	  It makes serialization succeed only if all values have a type that can
+	  be deserialized.
+	  Sponsored-by: Netflix Inc.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5355>
+
+2023-09-24 14:48:36 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/gstbuffer.c:
+	  buffer: Remove trailing space
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5355>
+
+2023-12-01 08:21:03 -0500  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/gstplugin.c:
+	  devenv: Whitelist all plugins to be able to run tests
+	  Meson devenv already overrides GST_PLUGIN_PATH and
+	  GST_PLUGIN_SYSTEM_PATH so only built plugins can be found. That means
+	  unit tests are allowed to use every plugins.
+	  This makes easier to run some unit tests under devenv instead of through
+	  "meson test".
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5748>
+
+2023-12-05 14:01:50 +0200  Vivia Nikolaidou <vivia@ahiru.eu>
+
+	* plugins/elements/gstmultiqueue.c:
+	  multiqueue: Don't stop dropping when an internal queue is empty
+	  It is racy and may cause us to accidentally keep forwarding data past
+	  the EOS. The only reason to stop dropping would be when we encounter a
+	  stream-start, segment, or segment-done event, either in push_one
+	  (already queued) or in the sink pad's event function.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5766>
+
+2023-12-10 03:25:57 +1100  Jan Schmidt <jan@centricular.com>
+
+	* plugins/elements/gstmultiqueue.c:
+	  multiqueue: Ignore queue fullness for most events
+	  Use gst_data_queue_push_force() for most events so they
+	  are immediately enqueued. Only gap events and actual buffer
+	  data will now block when the queue is full.
+	  This fixes a problem with non-flushing seek handling
+	  where events following a segment-done event would block
+	  if they precede the SEGMENT event, since only SEGMENT
+	  events would clear the 'eos' state of the multiqueue
+	  queue.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5801>
+
+2023-12-12 23:55:04 +0100  Alexander Slobodeniuk <aslobodeniuk@fluendo.com>
+
+	* libs/gst/base/gstaggregator.c:
+	* tests/check/libs/aggregator.c:
+	  aggregator: fix use-after-free in queries processing
+	  Test included.
+	  The problem appears when aggregator drops the query while
+	  it's being proccessed by the klass->sink_query handler.
+	  This can happen on FLUSH_START event. If the query is still
+	  in the queue, it can be safely dropped, but if it's already
+	  in the klass->sink_query() handler, then sink pad has no
+	  choice and has to wait for the proccessing to complete.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5765>
+
+2023-11-28 15:47:38 -0300  Thibault Saunier <tsaunier@igalia.com>
+
+	* libs/gst/base/gstbasesrc.c:
+	  basesrc: Expose automatic-eos as a property
+	  It is useful for appsrc for example and no good reason to not expose it as a property
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5725>
+
+2023-11-29 10:53:15 -0700  Jordan Yelloz <jordan.yelloz@collabora.com>
+
+	* gst/gstcontext.c:
+	* gst/gstcontext.h:
+	  gstcontext: Added gst_clear_context()
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5756>
+
+2023-11-29 08:46:49 -0700  Jordan Yelloz <jordan.yelloz@collabora.com>
 
-2022-09-15 16:23:16 +0200  Edward Hervey <edward@centricular.com>
+	* gst/gstpromise.c:
+	* gst/gstpromise.h:
+	  gstpromise: Added gst_clear_promise()
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5756>
+
+2023-11-28 14:43:13 -0700  Jordan Yelloz <jordan.yelloz@collabora.com>
+
+	* gst/gstpromise.h:
+	  gstpromise: Added GST_IS_PROMISE() macro
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5728>
+
+2023-07-25 14:16:09 +0100  Stéphane Cerveau <scerveau@igalia.com>
+
+	* gst/gst.c:
+	* gst/meson.build:
+	* meson_options.txt:
+	  meson: fix gstreamer-full static mode on win32
+	  Win32 was expecting the symbol gst_init_static_plugins in gstreamer-full
+	  dynamic mode.
+	  Add mode in gstreamer gstreamer-full options to tell if its a
+	  gstreamer-full static or shared mode.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5098>
+
+2023-11-27 13:16:47 +0100  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
 
 	* libs/gst/base/gstbaseparse.c:
-	  baseparse: If available, return average bitrate upstream
-	  Helps improve queue2 buffering for single stream playback (ex: FLAC or mp3)
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3033>
+	  baseparse: Reset metadata for reverse playback fragment buffers
+	  Don't let the adapter leak uncontrollable values.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5718>
 
-2022-08-26 08:43:34 -0400  Thibault Saunier <tsaunier@igalia.com>
+2023-11-27 12:29:08 +0100  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
 
-	* gst/gstelement.c:
-	  Build documentation for rust plugins
-	  - Update the docker image we use, starting using the standard one adding
-	  `gtk4-doc` as required by rust plugins
-	  - Update the plugins_doc_caches as required, some more plugins are built
-	  with the new image
-	  - Install ninja from pip as the version from F31 is too old
-	  - Avoid buildings all GSreamer plugins when building the doc as it takes
-	  time and resources for no good reason
-	  - Stop linking to `GInstanceInitFunc` as it is not present in latest GLib
-	  documentation, leading to warnings in hotdoc.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2954>
-
-2022-08-26 08:39:16 -0400  Thibault Saunier <tsaunier@igalia.com>
+	* libs/gst/base/gstbaseparse.c:
+	  baseparse: Add missing gst_buffer_make_writable
+	  When the subclass attempts to finish without an explicit `out_buffer`,
+	  we take a buffer from our adapter. We need to make this buffer writable
+	  before copying the metadata.
+	  This led to data races such as in the following pipeline, which randomly
+	  messed up the buffer PTS:
+	  gst-launch-1.0 -e audiotestsrc timestamp-offset=5555 num-buffers=100 \
+	  ! opusenc ! tee name=t ! queue ! opusparse ! fakesink silent=0 \
+	  t. ! queue ! opusparse ! fakesink silent=0 -v | grep '0000, dur'
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5718>
+
+2023-09-01 17:29:50 -0400  Olivier Crête <olivier.crete@collabora.com>
 
-	* docs/gst-hotdoc-plugins-scanner.c:
-	  docs: plugin-scanner: Minor debug enhancement
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2954>
+	* gst/gstbufferpool.c:
+	* gst/gstmeta.c:
+	* gst/gstmeta.h:
+	  meta: Add a new "clear" transform to avoid re-allocations
+	  In the buffer pool, try to clear metas before freeing them so we
+	  avoid constant reallocations on every frame.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4962>
 
-2021-01-28 08:40:56 +0200  Jordan Petridis <jordan@centricular.com>
+2023-08-03 17:05:17 -0600  Jordan Yelloz <jordan.yelloz@collabora.com>
 
-	* gst/gst_private.h:
-	* gst/gstelement.c:
-	* gst/gstinfo.c:
-	  gstinfo: remove the vasprintf fallback
-	  We are always building our printf implementation, even when
-	  GST_DEBUG is disabled, since we are exposing api (gst_print*)
-	  that's dependant on our printf behavior.
-	  We don't need to keep __gst_info_fallback_vasprintf around anymore.
-	  Close #640
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/739>
+	* libs/gst/check/gstcheck.c:
+	  bad: Added W3C Media Source Extensions library
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2992>
+
+2023-11-17 14:32:37 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/gstreamer.supp:
+	  valgrind: Supress racy cancellable source leak
+	  Creating a socket source, creates a cancellable source internally. This
+	  mechanism is racy and in order to workaround the race, the final unref
+	  can be delayed. Unfortunatly, it seams that this is randomly leaked.
+	  This affects users of glib 2.65 and up. Add a suppression on our side
+	  in order to avoid this leak showing up randomly in our CI.
+	  See https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1400 for more
+	  about the glib implementation detail. And follow this link for an
+	  example of failing CI pipeline:
+	  https://gitlab.freedesktop.org/gstreamer/gstreamer/-/jobs/51694889
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5688>
+
+2023-11-13 16:27:48 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/args.rs:
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Add `ttl` configuration to gst_ptp_init_full()
+	  This allows configuring the TTL that is used for multicast packets sent
+	  out on the sockets, and is defaulting to 1 as before. The default might
+	  change at some point.
+	  In some networks multiple hops are needed to reach the PTP clock and
+	  this allows to configure GStreamer in a way that works in such networks.
+	  At a later time, per-domain or per-interface TTL configurations might be
+	  added when needed.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5649>
+
+2023-11-13 16:14:07 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	* libs/gst/net/gstptpclock.h:
+	  ptp: Add new gst_ptp_init_full()
+	  This takes a free-form GstStructure as parameter that allows to easily
+	  extend it with new configuration at a later time without having to add
+	  new API.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5649>
+
+2023-11-15 10:03:52 +0000  Daniel Moberg <daniemob@axis.com>
+
+	* gst/gstpad.c:
+	  gstpad: Recheck pads when linking after temporary unlock
+	  This commit makes sure that pads are valid for linking
+	  after the pads has been temporarily unlocked in the linking process.
+	  Not doing this opens up for a race condition where
+	  pads potentially can be linked twice.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5670>
+
+2023-10-31 16:22:20 +0000  Philippe Normand <philn@igalia.com>
+
+	* gst/gststreamcollection.c:
+	  streamcollection: Fixup doc blurbs
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5605>
+
+2023-11-05 16:13:10 +0100  Fabian Orccon <cfoch.fabian@gmail.com>
+
+	* tools/gst-inspect.c:
+	  gst-inspect: Remove current caps print
+	  At GST_STATE_NULL, all pads are deactivated and have no caps.
+	  It can be observed with `gst-inspect-1.0 -a` that no element
+	  is reaching this removed code.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5604>
+
+2023-09-18 14:38:23 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/gstallocator.c:
+	* gst/gstallocator.h:
+	  GstAllocator: Add GST_ALLOCATOR_FLAG_NO_COPY flag
+	  Detail a bit the intention behind GST_ALLOCATOR_FLAG_CUSTOM_ALLOC, even
+	  if implementation does not currently fully follow that usage. Introduce
+	  a new flag specifically for copying memories using the default system
+	  allocator.
+	  Sponsored-by: Netflix Inc.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5328>
 
-2021-03-24 14:20:18 -0500  Zebediah Figura <z.figura12@gmail.com>
+2023-11-02 00:03:28 +0900  Seungha Yang <seungha@centricular.com>
 
 	* meson.build:
-	  meson: Build with -Wl,-z,nodelete to prevent unloading of dynamic libraries and plugins
-	  GLib made the unfortunate decision to prevent libgobject from ever being
-	  unloaded, which means that now any library which registers a static type
-	  can't ever be unloaded either (and any library that depends on those,
-	  ad nauseam).
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/778>
+	  meson: Fix MSVC build with GST_DISABLE_GST_DEBUG
+	  MSVC does not understand Wno-unused
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5585>
 
-2021-04-19 10:49:42 -0400  Doug Nazar <nazard@nazar.ca>
+2023-11-01 16:24:21 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gstregistry.c:
-	  registry: skip integration testsuite directory during plugin scan
-	  When using an uninstalled development environment and running the
-	  validation tests, the number of log files can grow substantially,
-	  slowing down startup.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/799>
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/helpers/ptp/net.rs:
+	  ptp: Use SO_BINDTOIFINDEX / SO_BINDTODEVICE on Linux
+	  This makes sure we really really really only get packets from the
+	  desired interface as passing a device to IP_ADD_MEMBERSHIP apparently
+	  does not have this effect alone.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5584>
 
-2022-08-30 10:48:18 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+2023-10-28 08:10:48 +0200  Fabian Orccon <cfoch.fabian@gmail.com>
 
-	* gst/gstbufferpool.c:
-	  doc: Clarify that gst_buffer_pool_acquire_buffer() blocks by default
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2955>
+	* tools/gst-inspect.c:
+	  gst-inspect: Do not check for element clock
+	  Clock is only set at GST_PLAYING state, not the case for gst-inspect
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5570>
+
+2023-11-01 14:21:05 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Check once a second for timeouts
+	  While the minimum timeout duration is 5s, checking only every 5s means
+	  that we would notice this 4.9s too late in the worst case.
+	  Checking once a second reduces this considerably while keeping the
+	  number of wakeups still low.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5520>
+
+2023-10-30 16:24:23 +0200  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Only warn if the clock id and interface of a timed out matches the current one
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5520>
+
+2023-10-25 13:33:39 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Only time out SYNCs if we're actually waiting for a FOLLOW_UP
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5520>
+
+2023-10-20 14:25:27 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Downgrade clocks that don't send FOLLOW_UPs / DELAY_RESPs
+	  This allows to select a different clock if there is one that is
+	  for the same grandmaster clock and has fewer timeouts.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5520>
+
+2023-10-20 14:20:45 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Don't switch domain's master clock if it is equivalent to the previous one
+	  Otherwise it can happen that we regularly switch back and forth between
+	  clocks under certain circumstances for no good reason.
+	  Also remove redundant comparison when comparing the steps removed between two
+	  clocks.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5520>
+
+2023-10-16 20:53:49 +0000  robert <robert.ayrapetyan@gmail.com>
+
+	* docs/gst/running.md:
+	  ximagesrc: fix compile-time warning and XInitThreads()
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5493>
+
+2023-10-27 09:59:03 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/gstreamer.supp:
+	  valgrind: Use frame-level widlcard for getaddrinfo leak
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5565>
+
+2023-10-26 15:03:22 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-2022-09-01 15:11:31 -0400  Thibault Saunier <tsaunier@igalia.com>
+	* tests/misc/network-clock-utils.scm:
+	* tests/misc/network-clock.scm:
+	  gstreamer: misc: relicense network-clock scheme files to LGPL v2.1+
+	  Permission to relicense granted by author by e-mail:
+	  Message-Id: <155C6D51-7F74-4C40-814A-2ADDED7707FD@pobox.com>
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5559>
 
+2023-10-26 14:35:33 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* tests/check/gstreamer.supp:
+	  valgrind: Add getaddrinfo leak suppression
+	  With Fedora 34 in our CI, we start seeing a sometime leak in getaddrinfo. At
+	  first sight it looks like some TLS context being leaked. Could be a thread
+	  teardown leak, just suppress it for now.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5562>
+
+2023-10-25 13:58:55 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/gstdebugutils.c:
+	  debugutils: Ensure we always expose a bin_to_dot_data implementation
+	  Fixes a linking issue when building with `-Dgst_debug=false`.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5550>
+
+2023-10-25 00:40:22 +0900  Seungha Yang <seungha@centricular.com>
+
+	* gst/gstpluginloader-win32.c:
+	  pluginloader-win32: Increase plugin loading timeout
+	  Some hardware plugin loading might take more than 10sec under
+	  full CPU load condition
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5545>
+
+2023-10-19 19:44:21 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: Allow passing unparented pads to gst_aggregator_pad_is_inactive()
+	  It's very difficult to ensure that a pad is still child of the
+	  aggregator during aggregation, so simply consider unparented pads as
+	  inactive instead of asserting.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5510>
+
+2023-10-19 19:43:26 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: Also release clipped buffer when releasing an aggregator pad
+	  Instead of waiting until the pad is actually finalized.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5510>
+
+2023-10-19 19:43:26 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: Take pad lock while releasing buffers when removing pads
+	  Accessing the buffers in all other places requires the pad lock and not
+	  taking it here can cause access to already freed buffers if there's
+	  concurrent access from another thread.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5510>
+
+2022-04-06 12:56:30 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/gstbus.c:
 	* meson.build:
-	* plugins/elements/meson.build:
-	* plugins/tracers/meson.build:
-	  meson: Call pkgconfig.generate in the loop where we declare plugins dependencies
-	  Removing some copy pasted code
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2970>
+	  meson: Bump GLib requirement to >= 2.64
+	  This includes fixes to make GstBus watches non-racy.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2126>
+
+2023-10-19 14:10:16 +0200  Loïc Le Page <llepage@igalia.com>
+
+	* docs/gst/running.md:
+	* docs/index.md:
+	  gl: add support for surfaceless display in GstGL
+	  Use of the EGL_MESA_platform_surfaceless EGL extension to create an EGL
+	  display that is not depending on any kind of windowing system.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5511>
+
+2023-10-05 23:18:53 +0900  Seungha Yang <seungha@centricular.com>
+
+	* tests/check/elements/multiqueue.c:
+	  tests: multiqueue: Add overrun test case
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5430>
+
+2023-10-05 22:40:43 +0900  Seungha Yang <seungha@centricular.com>
+
+	* plugins/elements/gstmultiqueue.c:
+	  multiqueue: Do not update time level on segment
+	  Update time level decision logic to be identical to the queue/queue2
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5430>
+
+2023-10-03 17:38:18 +0900  Seungha Yang <seungha@centricular.com>
+
+	* tests/check/elements/queue.c:
+	* tests/check/elements/queue2.c:
+	  tests: queue, queue2: Add more timelevel test
+	  ... and update existing testcases for new timelevel measuring logic
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5430>
+
+2023-10-03 02:05:23 +0900  Seungha Yang <seungha@centricular.com>
+
+	* plugins/elements/gstqueue.c:
+	* plugins/elements/gstqueue.h:
+	* plugins/elements/gstqueue2.c:
+	* plugins/elements/gstqueue2.h:
+	  queue, queue2: Fix current-level-time report
+	  Do not update timelevel on segment. Segment itself does not tell
+	  anything about the amount of buffered time duration in the element
+	  but buffer timestamp/duration is required to measure actual bufferred time.
+	  Moreover, at the time when new segment is applied to sink/srcpad,
+	  segment.position would point to random value.
+	  Therefore calculating running time using the random value does not
+	  make sense and it will result in wrong timelevel report.
+	  This patch updates queue/queue2's timelevel measuring logic so that
+	  it can be updated only on buffer/buffer-list/gap-event flow.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5430>
+
+2023-10-06 13:39:34 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/io.rs:
+	  ptp: Fix a couple of stylistic clippy warnings
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5441>
+
+2023-09-04 14:02:25 +0200  Alexander Slobodeniuk <aslobodeniuk@fluendo.com>
+
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: fix start-time-selection=first on negative rate
+	  When the property "start-time-selection" is set to "first", it
+	  calculates the start time of the output from the buffer pts
+	  (converting it to running time of the segment), but if the
+	  rate is negative, the real start is not the pts, but the
+	  pts + duration, because it plays from the end of the buffer
+	  to it's start.
+	  As a result of this bug, in the negative rate, when the
+	  start-time-selection=first, the first frame is dropped
+	  by the videoaggregator (reproduced on d3d11compositor).
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5276>
+
+2023-09-27 16:59:34 +0200  François Laignel <francois@centricular.com>
+
+	* tools/gst-inspect.c:
+	  tools: gst-inspect: add specific messages for CONSTRUCT_ONLY params
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5407>
+
+2023-09-27 08:46:35 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* libs/gst/base/gstaggregator.c:
+	  GstCustomMeta: Use simplified API where possible
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5385>
+
+2023-09-23 13:12:57 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+
+	* gst/gstmeta.c:
+	* gst/gstmeta.h:
+	  GstCustomMeta: simplify API
+	  Move the GstStructure field into public struct for direct access, that's
+	  easier than having to call a function to get it. It is not an API/ABI
+	  breakage to extend the public structure of a GstMeta because they are
+	  always allocated by inside GStreamer. The structure is exposed already
+	  by gst_custom_meta_get_structure() which does not return a copy/ref, so
+	  it is locked into holding a GstStructure forever anyway.
+	  Also add gst_meta_register_custom_simple() because most of the time only
+	  a name is required, tags and transform functions are more niche
+	  use-case.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5385>
+
+2023-09-20 09:49:27 +0200  Ruben Gonzalez <rgonzalez@fluendo.com>
+
+	* gst/gstutils.h:
+	  gstutils: Delete extra semicolon
+	  Warning reported by GCC with -Wpedantic: ISO C does not allow extra
+	  ‘;’ outside of a function.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5359>
+
+2023-08-01 17:08:39 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* libs/gst/base/gstbasesrc.c:
+	  basesrc: Delay unlocking so we can hold the STREAM_LOCK
+	  unlock_stop() is expected to be run while the streaming thread is idle. To
+	  guaranty this is the case, we should take the streamlock, but its not
+	  possible to take this lock during state transitions from PAUSED to
+	  PLAYING as the wait function that we want to terminate is holding it.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4961>
+
+2023-08-01 16:52:28 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
+
+	* libs/gst/base/gstbasesrc.c:
+	  basesrc: Retry create() if we are back from pause
+	  After a create() call, which may have returned FLUSHING or a filled buffer,
+	  if it possible that we detect that we are now in pause. As live sourced
+	  don't produce data in pause, drop the buffer is any and later retry creating
+	  a buffer. This will ensure that we resume from pause while avoiding displaying
+	  ancient frame.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4961>
+
+2023-07-03 11:48:57 -0400  soak <oakasanj@yahoo.com>
+
+	* libs/gst/base/gstbasesrc.c:
+	  basesrc: Restore pause/resume in derived classes
+	  When the pipeline goes from Playing to Paused, this change will invoke
+	  unlock in the derived class. When the pipeline goes from Paused to
+	  Playing, this change will invoke unlock_stop in the derived class.
+	  This feature was removed in commit 523de1a9 and is now being restored.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4961>
+
+2023-07-12 02:43:18 +0900  Seungha Yang <seungha@centricular.com>
+
+	* plugins/elements/gstqueue.c:
+	* plugins/elements/gstqueue2.c:
+	* tests/check/elements/queue.c:
+	* tests/check/elements/queue2.c:
+	  queue, queue2: Flush internal queue on flow error
+	  This is to fix an infinitely blocked upstream streaming thread if
+	  * upstream has fixed-size buffer pool, some H/W decoders for example
+	  * downstream returned flow error without releasing buffer
+	  When the fixed-size buffer pool hits its configured max-buffers and
+	  also downstream of queue returned flow error without releasing corresponding
+	  buffer, upstream has no chance to run the next processing loop
+	  because it will be blocked by acquire_buffer(), and therefore
+	  downstream flow will not be propagated to upstream.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5023>
+
+2023-08-31 09:04:05 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/io.rs:
+	* libs/gst/helpers/ptp/main.rs:
+	  ptp: Fix compilation with rustc 1.48
+	  That's currently the minimum version we declare in meson.build but the
+	  latest changes introduced some usage of 1.62 features.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5265>
+
+2023-08-23 19:21:37 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/io.rs:
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/helpers/ptp/net.rs:
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Listen with different sockets on individual interfaces
+	  This allows us to portably know on which interface a multicast packet
+	  arrived, and to send back any packets for that clock on the correct
+	  interface.
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2728
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5232>
+
+2023-02-10 13:04:26 -0500  Olivier Crête <olivier.crete@collabora.com>
 
-2022-09-01 11:51:48 -0400  Thibault Saunier <tsaunier@igalia.com>
+	* tools/gst-stats.c:
+	  gst-stats: Add argument for a custom regexp
+	  This is to use gst-stats against GStreamer logs that went through
+	  some other logging system.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3935>
+
+2023-08-15 16:01:28 +0200  Piotr Brzeziński <piotr@centricular.com>
+
+	* tools/gst-launch.c:
+	  tools: Disable fault signal handlers in gst-launch/gst-validate on macOS
+	  By default, macOS attempts to run lldb against a misbehaving process to handle the crash. This does not play well
+	  with the SISEGV/SIGQUIT handler we add in gst-launch/gst-validate. The 'spinning' mechanism causes the lldb
+	  and debugserver processes ran by macOS to misbehave, taking 100% CPU and rendering both themselves and the GStreamer
+	  instance frozen and very hard to effectively kill. macOS's Activity Monitor is also unusable while this is happening.
+	  This patch takes the quickest possible solution of just disabling those signal handlers entirely on macOS.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5190>
+
+2023-07-27 13:32:48 +0200  Piotr Brzeziński <piotr@centricular.com>
+
+	* libs/gst/base/gstqueuearray.c:
+	* libs/gst/base/gstqueuearray.h:
+	* tests/check/libs/queuearray.c:
+	  queuearray: Add sorting and sorted pushing
+	  Adds gst_queue_array_sort for sorting and gst_queue_array_push_sorted{,struct} for pushing in a sorted order.
+	  All three functions accept a comparison GCompareDataFunc along with optional user_data to pass to it.
+	  In gst_queue_array_sort a small workaround was needed to correctly sort non-struct arrays. Like what _find() already
+	  does, we need to dereference our pointers first, to make sure we can use the same comparison functions everywhere.
+	  This is done via a small wrapper around the provided comparison function.
+	  The array can also wrap around (tail ends up 'before' the head), in which case we have to reorder the array (similar to
+	  what do_expand() does) to then be able to use an existing sorting function, like g_qsort_with_data().
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5112>
+
+2023-07-27 16:42:51 +1000  Matthew Waters <matthew@centricular.com>
+
+	* gst/parse/grammar.y.in:
+	  parse: avoid -Werror=unused-but-set-variable
+	  bison seems to generate a yyparse() with one unsed but set variable in it.
+	  Avoid that.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5110>
+
+2023-07-17 15:18:39 +0100  Philippe Normand <philn@igalia.com>
+
+	* gst/gstquery.c:
+	  query: Add a quark for SELECTABLE query type
+	  So that `gst_query_type_get_name()` won't return "unknown" for this type.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5048>
+
+2023-07-05 18:46:25 -0600  Olivier Crête <olivier.crete@collabora.com>
+
+	* scripts/gen-changelog.py:
+	* scripts/git-version.sh:
+	  gst-omx: Retire the whole package
+	  The OpenMAX standard is long dead and even the Raspberry Pi OS
+	  no longer supports it.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4976>
+
+2023-07-12 09:27:22 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* tests/check/meson.build:
+	  meson: Always use forward slashes in defines with paths
+	  Fixes the following build failure on MSYS2:
+	  ```
+	  ../subprojects/gstreamer/tests/check/elements/filesrc.c: In function 'test_seeking':
+	  ../subprojects/gstreamer/tests/check/elements/filesrc.c:107:53: error: incomplete universal character name \U
+	  107 |   g_object_set (G_OBJECT (src), "location", TESTFILE, NULL);
+	  |                                                     ^
+	  ../subprojects/gstreamer/tests/check/elements/filesrc.c:107:53: warning: unknown escape sequence: '\A'
+	  ../subprojects/gstreamer/tests/check/elements/filesrc.c:107:53: warning: unknown escape sequence: '\g'
+	  ../subprojects/gstreamer/tests/check/elements/filesrc.c:107:53: warning: unknown escape sequence: '\s'
+	  ../subprojects/gstreamer/tests/check/elements/filesrc.c:107:53: warning: unknown escape sequence: '\g'
+	  ../subprojects/gstreamer/tests/check/elements/filesrc.c:107:53: warning: unknown escape sequence: '\c'
+	  ```
+	  Due to: `-DTESTFILE=\"C:\\Users\\Administrator\[...]`
+	  https://gitlab.freedesktop.org/nirbheek/gstreamer/-/jobs/45317733
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5018>
+
+2023-07-11 23:24:41 +0200  Alicia Boya García <aboya@igalia.com>
 
 	* docs/meson.build:
-	* gst/meson.build:
-	* libs/gst/base/meson.build:
+	* libs/gst/check/gstharness.c:
+	* libs/gst/check/gstharnesslink.c:
+	* libs/gst/check/gstharnesslink.h:
 	* libs/gst/check/meson.build:
-	* libs/gst/controller/meson.build:
-	* libs/gst/net/meson.build:
-	* meson.build:
-	  meson: Namespace the plugins_doc_dep/libraries variables
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2970>
+	  harness: Fix race condition when torn down during the handling of a non-serialized query or event
+	  It's possible and normal to tear down a harness while the pipeline is
+	  running. At the same time, it's desired for the
+	  `gst_harness_pad_link_tear_down()` function to be synchronous.
+	  This has created the conflict where the main thread may request a
+	  harness to be torn down while it's in use or about to be used by a pad
+	  in the streaming thread.
+	  The previous implementation of `gst_harness_pad_link_tear_down()` tried
+	  to handle this by taking the stream lock of the harnessed pad and
+	  resetting all the pad functions while holding it. That approach was
+	  however insufficient to handle the case where a non-serialized event
+	  or query is being handled or about to be handled in a different thread.
+	  This edge case was one race condition behind the flakes in the flvmux
+	  check tests -- the rest being covered by https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2803.
+	  This patch fixes the problem by adding an intermediate ref-counted
+	  object, GstHarnessLink, which replaces the usage of the HARNESS_KEY
+	  association. GstHarnessLink allows the pad functions such as event,
+	  query and chain to borrow a reference to GstHarness and more
+	  importantly, to lock the GstHarnessLink during their usage to block
+	  (delay) its destruction until no users are left, and guarantee that any
+	  future user will not receive an invalid GstHarness handle past its
+	  destruction.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5017>
+
+2023-07-06 18:08:57 +0200  Théo Maillart <tmaillart@freebox.fr>
 
-2022-08-31 18:44:14 -0400  Thibault Saunier <tsaunier@igalia.com>
+	* plugins/elements/gstinputselector.c:
+	  inputselector: fix playing variable is never set
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4983>
 
-	* meson.build:
-	  meson: Rename plugins list and make them "dependency" objects
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2970>
+2023-07-05 16:50:07 +0200  Andoni Morales Alastruey <ylatuya@gmail.com>
+
+	* plugins/tracers/gstleaks.c:
+	  leaks: add unix signals documentation
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4973>
 
-2022-08-31 14:23:59 +0200  Martin Dørum <martid0311@gmail.com>
+2023-07-01 00:33:56 +1000  Jan Schmidt <jan@centricular.com>
 
-	* gst/gstpluginloader.c:
-	  gstpluginloader: Don't hang on short reads/writes
-	  If read_one or write_one was called but the stream closed before it could
-	  read/write a whole packet, read_one/write_one would hang indefinitely,
-	  consuming 100% CPU. This commit fixes that by treating a short read/write
-	  as an error.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2964>
+	* libs/gst/base/gstbasesrc.c:
+	  basesrc: Don't hold the object lock while pushing an event
+	  Release the object lock before pushing a segment event.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4951>
+
+2023-06-26 11:53:47 +0200  Alicia Boya García <aboya@igalia.com>
+
+	* tests/validate/meson.build:
+	  validate tests: include debugutilsbad to be able to use testsrcbin
+	  Fixes test: validate.uridecodebin.expose_raw_pad_caps
+	  testsrcbin (currently part of debugutilsbad) is an useful element for
+	  validate tests.
+	  validate.uridecodebin.expose_raw_pad_caps makes use of it.
+	  Unfortunately, because validate tests with GStreamer only run with
+	  whitelisted plugins and `debugutilsbad` wasn't in the whitelist, the
+	  test was failing and being auto-skipped.
+	  This patch adds debugutilsbad to the whitelists used by validate tests
+	  in subprojects with a validate/meson.build.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4931>
+
+2023-06-26 12:56:26 +0200  Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+
+	* gst/gstcaps.c:
+	  caps: Fix documentation
+	  Fix gst_caps_filter_and_map_in_place() documentation, aiming to
+	  gst_caps_maps_in_place() to express their difference.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4933>
 
-2022-08-31 09:15:08 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+2023-06-22 15:39:20 +0200  Alicia Boya García <aboya@igalia.com>
+
+	* gst/gsttask.c:
+	  task: Log task states as string
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4913>
+
+2023-06-21 13:44:40 +0200  Edward Hervey <edward@centricular.com>
+
+	* gst/gststreamcollection.c:
+	  streamcollection: Use upstream-id as name
+	  It is more coherent, in the same vein as  08dc5d29
+	  Fixes #2640
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4911>
+
+2023-06-21 01:20:18 +0900  Seungha Yang <seungha@centricular.com>
 
 	* gst/gst.c:
-	  gst_init: Initialize static plugins just before dynamic plugins
-	  All plugins needs to be initialized after `gst_initialized = TRUE;`
-	  otherwise they could complain that gst_init() has not been called.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2962>
+	* libs/gst/net/gstptpclock.c:
+	  gst: Don't use DllMain in case of static build
+	  That might cause duplicated symbol linking error if app has its own
+	  DllMain
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4905>
 
-2022-05-31 15:18:03 +0200  Stéphane Cerveau <scerveau@collabora.com>
+2023-06-13 21:53:29 +0900  Seungha Yang <seungha@centricular.com>
 
-	* docs/meson.build:
-	  docs: disable in static build
-	  Following gst-plugins-base, disable docs if static_build
-	  in:
-	  - gstreamer
-	  - gst-plugins-good
-	  - gst-plugins-ugly
-	  - gst-libav
-	  - gstreamer-vaapi
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2529>
-
-2022-08-24 12:42:12 -0400  Olivier Crête <olivier.crete@collabora.com>
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: Resume srcpad task on stream-start only when running
+	  Race condition without this patch:
+	  - srcpad task is being stopped in gst_aggregator_stop_srcpad_task()
+	  - at that moment, in pre-queue event handler, gst_pad_get_task_state()
+	  returned GST_TASK_PAUSED
+	  - then in srcpad task got stopped in gst_aggregator_stop_srcpad_task()
+	  - finally srcpad task got resumed in pre-queue event handler
+	  To address it, checks "running" flag in pre-queue event handler.
+	  Both pre-queue stream-start event handler and "running" flag
+	  are protected by SRC_LOCK already.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4847>
+
+2023-06-09 17:51:28 +0800  Elliot Chen <elliot.chen@nxp.com>
 
-	* gst/gstvalue.c:
-	  value: Use g_critical() when trying to serialize things that can't be
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2823>
+	* libs/gst/base/gsttypefindhelper.c:
+	  typefindhelper: avoid printing error log
+	  some plugins such as wavparse may need find if type of media
+	  contained in the given data and will print error log if there
+	  is no matching factory.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4814>
+
+2023-06-08 09:35:44 +0200  Jochen Henneberg <jh@henneberg-systemdesign.com>
+
+	* libs/gst/net/gstnetclientclock.c:
+	  netclientclock: Handle time server reset correctly
+	  If the time server is restarted with a time in the past the net client
+	  clock will not report the new time anymore as this would mean that the
+	  clock moves back in time which it does not do.
+	  Now the clock will be kept alive but marked as corrupted and will not
+	  be re-used from the cache.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4802>
+
+2023-02-16 13:44:50 +0100  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* gst/gsttracerutils.c:
+	  tracerutils: allow casting parameters types
+	  It was impossible to have an u32 parameter such as
+	  'max-buffer-size=(uint)5' because the parentheses were not properly
+	  parsed.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3981>
+
+2023-03-13 19:42:23 +0100  Ruben Gonzalez <rgonzalez@fluendo.com>
 
-2022-08-01 14:00:20 -0400  Olivier Crête <olivier.crete@collabora.com>
+	* docs/gst/running.md:
+	* docs/index.md:
+	  doc: Add %p and %r patters for GST_DEBUG_FILE
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4166>
+
+2023-06-05 12:21:22 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
 
 	* gst/gstvalue.c:
 	* tests/check/gst/gstvalue.c:
-	  gstvalue: Don't loop forever when serializing invalid flag
-	  The serialization code would loop forever if an invalid flag was sent into it.
-	  With unit test for this corner case.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2823>
-
-2022-08-23 19:40:54 +0300  Sebastian Dröge <sebastian@centricular.com>
+	  flagset: Fail parsing on overflowing hex strings
+	  This adds code to detect when the hex form of the string we are to
+	  parse exceeds the number of bytes that would form a 32bit flag. This will
+	  avoid treating as flagset anything above then the expected 32 bits and also
+	  stop treading DRM format with modifiers as flagset (like
+	  drm-format=AB24:0x0100000000000002).
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4775>
 
-	* gst/gstbin.c:
-	  bin: Don't propagate state change errors of elements in locked state
-	  Theoretically having elements in locked state should not have any effect
-	  at all when the surrounding bin is doing state changes. However
-	  previously a state change error of a locked element would cause the
-	  bin's state change to also fail, which is clearly not intended.
-	  State change failures of locked elements are to be handled by whoever
-	  set the element to locked state. By always returning them here it is
-	  impossible for the owner of the element to handle state change failures
-	  gracefully without potentially affecting the whole pipeline's state
-	  changes.
-	  Non-failure returns are still returned as-is as the distinction between
-	  ASYNC/NO_PREROLL/SUCCESS has big consequences on the state changes of
-	  the bin and overall pipeline. Theoretically SUCCESS should also be
-	  returned in all cases but I can't estimate the effects this would have
-	  on the overall pipeline.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2932>
-
-2022-08-17 16:27:36 +0300  Sebastian Dröge <sebastian@centricular.com>
+2023-06-06 03:03:07 +0900  Seungha Yang <seungha@centricular.com>
 
 	* libs/gst/base/gstaggregator.c:
-	  aggregator: Improve debug output to better understand why pads are not ready or can't accept more data
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2907>
+	  aggregator: Restart srcpad task on stream-start
+	  Re-start srcpad task on stream-start in addition to flush event
+	  so that subclass can process data when new pad is added
+	  after EOS or an input stream is started again with stream-start event
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4783>
 
-2022-08-15 20:07:09 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+2023-06-08 20:52:21 +0900  Seungha Yang <seungha@centricular.com>
 
-	* gst/gstmeta.c:
-	* gst/gstmeta.h:
-	* tests/check/gst/gstmeta.c:
-	  meta: Set the parent refcount of the GstStructure correctly
-	  The parent refcount is of the *transformed* buffer, not the input
-	  buffer.
-	  Also update the docs to clarify that @transbuf is the transformed
-	  buffer, and not the buffer on which a transformation is being
-	  performed.
-	  Due to this bug, modifying the structure of a meta that has been
-	  copied to another buffer fails with:
-	  gst_structure_set: assertion 'IS_MUTABLE (structure) || field == NULL' failed
-	  Add a test for the same.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2890>
-
-2022-07-09 17:04:07 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* plugins/elements/gstelements_private.c:
+	* tests/check/elements/filesink.c:
+	  filesink: Fix buffered mode writing
+	  Fixing miscalculated buffer index when a buffer holds multiple
+	  memories and it's not aligned to the vector size 16
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4809>
+
+2023-06-08 13:40:47 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/helpers/ptp/net.rs:
+	  ptp: Set port-reuse socket options before binding the socket
+	  Otherwise it only works if GStreamer is binding the first socket on this
+	  port.
+	  Unfortunately this requires duplicating a bit more of Rust std because
+	  `UdpSocket` can only be created already bound without allowing to set
+	  any options between socket creation and binding.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4807>
+
+2023-06-08 13:51:57 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/args.rs:
+	  ptp: Correctly parse clock ID from the commandline parameters in the helper
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2652
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4806>
+
+2023-06-07 08:51:09 +0200  Philippe Normand <philn@igalia.com>
+
+	* gst/gstutils.c:
+	  utils: Fix doc warnings in gst_utils_simplify_fraction
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4793>
+
+2023-06-07 23:10:47 +0900  Seungha Yang <seungha@centricular.com>
+
+	* gst/gstsystemclock.c:
+	  systemclock: Use Windows interlocked APIs
+	  MSVC most likely does not support C11 atomic operations
+	  with given compile options
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4794>
+
+2023-06-07 20:24:43 +0900  Seungha Yang <seungha@centricular.com>
+
+	* gst/gst.c:
+	* gst/gstutils.c:
+	  gst: Call priv_gst_clock_init() on DllMain
+	  Can avoid atomic read per gst_util_get_timestamp() call
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4794>
+
+2023-06-06 20:44:02 +0900  Seungha Yang <seungha@centricular.com>
+
+	* tests/check/libs/basesink.c:
+	  tests: basesink: Add STREAM-START after EOS test
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4782>
+
+2023-06-06 04:42:05 +0900  Seungha Yang <seungha@centricular.com>
+
+	* libs/gst/base/gstbasesink.c:
+	  basesink: Clear EOS flag on STREAM-START event
+	  EOS -> STREAM-START -> new data flow is valid scenario
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4782>
+
+2023-06-06 10:54:36 +0200  Stéphane Cerveau <scerveau@igalia.com>
+
+	* gst/gst.c:
+	  gstreamer-full: keep g_module_symbol to init plugins
+	  In Android use case, the flag GST_FULL_COMPILATION
+	  is not defined whereas the plugins need to be
+	  initialized using 'gst_init_static_plugins'
+	  method.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4777>
+
+2023-06-05 20:17:40 +0900  Seungha Yang <seungha@centricular.com>
+
+	* plugins/elements/gstclocksync.c:
+	  clocksync: Fix deadlock because of taken stream lock on flush-start
+	  Deadlock happens when streaming thread is already blocked by downstream
+	  and clocksync is trying to take stream lock on flush-start.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4772>
+
+2023-06-01 14:49:06 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+
+	* gst/gstinfo.c:
+	  docs: Use backticks to escape * in markdown
+	  Otherwise it's interpreted as emphasis.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4753>
+
+2023-03-08 01:09:42 +0100  Michael Grzeschik <m.grzeschik@pengutronix.de>
+
+	* gst/gstutils.c:
+	* gst/gstutils.h:
+	  gstreamer: gst-utils: add gst_util_simplify_fraction
+	  We add the gst_util_simplify_fraction function to be able to convert
+	  fractions such as 333333/10000000 to 1/30.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1304>
+
+2023-03-23 13:03:18 +0100  Stéphane Cerveau <scerveau@igalia.com>
+
+	* gst/meson.build:
+	  gstreamer-full: add GST_STATIC_COMPILATION for Windows
+	  In the case of a gstreamer-full target type to static,
+	  the GST_STATIC_COMPILATION is necessary on Windows to avoid
+	  a different mangling from the external project using the
+	  gstreamer-full libraries (ie dllimport).
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4128>
+
+2023-03-16 09:39:27 +0100  Stéphane Cerveau <scerveau@igalia.com>
+
+	* libs/gst/helpers/meson.build:
+	  gstreamer-full: helpers built as tools
+	  gst-plugin-scanner and gst-completion-helper
+	  are now built part of the helpers as tools.
+	  Add libraries to the summary to know
+	  what library will be built and can be exposed
+	  by gstreamer-full
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4128>
+
+2023-03-07 14:05:54 +0100  Stéphane Cerveau <scerveau@igalia.com>
 
 	* gst/gst.c:
-	  gst: Protect initialization state with a recursive mutex.
-	  Otherwise a gst_init() call from a plugin would deadlock if the plugin
-	  is loaded as part of registry updating.
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/940
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2740>
+	* gst/meson.build:
+	* meson.build:
+	* meson_options.txt:
+	* tests/meson.build:
+	* tools/meson.build:
+	  gstreamer-full: add full static support
+	  Allow a project to use gstreamer-full as a static library
+	  and link to create a binary without dependencies.
+	  Introduce the option 'gst-full-target-type' to
+	  select the build type, dynamic(default) or static.
+	  In gstreamer-full/static build configuration gstreamer (gst.c)
+	  needs the symbol gst_init_static_plugins which is defined
+	  in gstreamer-full.
+	  All the tests and examples are linking with gstreamer but the
+	  symbol gst_init_static_plugins is only defined in the gstreamer-full
+	  library. gstreamer-full can not be built first as it needs to know what plugins
+	  will be built.
+	  One option would be to build all the examples and tests after
+	  gstreamer-full as the tools.
+	  Disable tools build in subprojects too as it will be built at the end of
+	  build process.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4128>
+
+2023-05-31 13:15:13 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/io.rs:
+	  ptp: On Windows handle socket polls that result in no error but also no FD_READ event
+	  According to the documentation this should never happen but apparently
+	  does under certain circumstances. As the sockets are set non-blocking,
+	  trying to read from them regardless should not cause any problems.
+	  In all cases that were observed so far, the socket in question actually
+	  has a packet queued up for reading.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4748>
+
+2023-05-19 09:49:17 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/helpers/ptp/parse.rs:
+	  ptp: Parse PTP messages in the helper process and filter earlier
+	  This drops invalid, unknown or uninteresting PTP messages in the helper
+	  process already instead of forwarding them to the main process.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4665>
+
+2023-05-21 12:45:50 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Ignore DELAY_RESP messages not for us earlier in the main process
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4665>
+
+2023-05-21 12:45:14 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/main.rs:
+	  ptp: Set UDP sockets as non-blocking
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4665>
+
+2023-05-18 13:59:10 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-2022-07-09 17:02:26 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* libs/gst/helpers/ptp/clock.rs:
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Capture actual send/receive times in the helper process
+	  While this doesn't yet use any OS provided times from the actual network
+	  stack, this still gets rid of any IPC jitter between the helper process
+	  and the main process as part of the PTP time calculations and should
+	  improve accuracy.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4665>
+
+2023-05-17 14:44:24 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gst.c:
+	* gst/gst_private.h:
+	* gst/gstsystemclock.c:
+	* gst/gstutils.c:
+	  gst: clock: Clean up code to get the monotonic / realtime clock a bit
+	  On Windows and macOS always use the proper monotonic clock, including
+	  for gst_util_get_timestamp(), and initialize its state only once.
+	  Also on macOS use clock_gettime() for the realtime clock, if available
+	  instead of always falling back to GLib.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4658>
+
+2023-05-17 10:01:30 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Work around bug in ptpd in default configuration
+	  ptpd is defaulting to the hybrid mode, and was sending invalid multicast
+	  PTP messages in that configuration until ce96c742a88792a8d92deebaf03927e1b367f4a9.
+	  While this commit was made in 2015 there was no release in the meantime.
+	  Work around this by detecting this case and defaulting to the default
+	  values for the given intervals as given by the PTP standard.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4654>
+
+2023-05-19 09:47:06 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/rand.rs:
+	  ptp: Fix compilation with Rust 1.48
+	  Use `ErrorKind::NotFound` instead of `ErrorKind::Unsupported` if the
+	  `getrandom` syscall is not available. `Unsupported` was added in 1.53.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4647>
+
+2023-05-16 14:53:24 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/args.rs:
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/io.rs:
+	* libs/gst/helpers/ptp/log.rs:
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/helpers/ptp/net.rs:
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Add logging between the helper process and the main process via stderr
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4647>
+
+2023-05-15 17:52:20 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Add a working default branch to the message type switch
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4647>
+
+2023-05-15 17:44:31 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/net/gstptp_private.h:
+	* libs/gst/net/gstptpclock.c:
+	  ptp: Get rid of struct padding in the messages with the helper process
+	  Also remove the now unnecessary private header file.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4647>
+
+2023-05-17 22:58:46 +0200  Ruben Gonzalez <rgonzalez@fluendo.com>
+
+	* README.md:
+	  README.md: fix current version
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4662>
+
+2023-05-12 18:35:48 +0200  Mathieu Duponchelle <mathieu@centricular.com>
+
+	* gst/parse/grammar.y.in:
+	  parse/grammar: fix missing unref of looked up child
+	  the target parameter of gst_child_proxy_lookup() is (transfer full)
+	  Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2560
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4622>
+
+2023-04-20 10:32:43 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/io.rs:
+	* libs/gst/helpers/ptp/meson.build:
+	* libs/gst/helpers/ptp/net.rs:
+	* libs/gst/helpers/ptp/privileges.rs:
+	* libs/gst/helpers/ptp/rand.rs:
+	  ptp-helper: Add some tests for functionality and memory safety of unsafe code
+	  These tests are mostly for ensuring that the calls to system APIs are
+	  done correctly and that there are no memory bugs (that would be caught
+	  by valgrind) in the unsafe code.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4458>
+
+2023-04-03 13:51:38 +0100  Lukas Geiger <lukas.geiger94@gmail.com>
+
+	* gst/gstmacos.m:
+	  macos: Set activation policy in `gst_macos_main`
+	  Setting the policy to NSApplicationActivationPolicyAccessory by default makes
+	  sure that we can activate windows programmatically or by clicking on them.
+	  Without that, windows would disappear if you clicked outside them and there
+	  would be no way to bring them to front again. This change also allows osxvideosink
+	  to receive navigation events correctly.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4573>
+
+2023-05-07 01:06:26 +0200  Maxim P. DEMENTYEV <mdementyev@fluendo.com>
+
+	* gst/gstplugin.c:
+	  plugin ext dep INFO: Adding var name and value part number
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4570>
+
+2023-05-05 23:21:22 +0900  Seungha Yang <seungha@centricular.com>
+
+	* gst/gstpluginloader-win32.c:
+	* gst/meson.build:
+	  pluginloader-win32: Use UWP compatible Windows API
+	  CreateFile2 API should be used in case of UWP
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4556>
+
+2023-05-04 00:19:32 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstpluginloader.c:
+	  gstreamer: pluginloader: Remove unnecessary Windows special cases
+	  The Windows plugin loader is in a separate file.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4541>
+
+2023-05-04 00:17:47 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gstpluginloader-win32.c:
+	* gst/gstpluginloader.c:
+	* libs/gst/net/gstptpclock.c:
+	  gstreamer: #undef a few local #defines after usage
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4541>
+
+2023-05-04 00:15:33 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	  gstreamer: ptpclock: Remove unnecessary empty line
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4541>
+
+2023-05-04 00:14:29 +0300  Sebastian Dröge <sebastian@centricular.com>
 
 	* gst/gstregistry.c:
-	  registry: Remove dead code
-	  Initialization/updating of the registry can't possible fail and all code
-	  paths always returned TRUE.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2740>
+	* libs/gst/net/gstptpclock.c:
+	  gstreamer: Fix minor memory leak in error path for internal path depth helper function
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4541>
+
+2023-05-03 19:15:53 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* libs/gst/net/gstptpclock.c:
+	* libs/gst/net/meson.build:
+	* meson.build:
+	  ptp: Allow relocation of GStreamer installation for finding PTP helper process
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4538>
+
+2023-05-03 18:47:33 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gst_private.h:
+	* gst/gstpluginloader-win32.c:
+	* gst/gstpluginloader.c:
+	* gst/gstregistry.c:
+	  gst: pluginloader: De-duplicate count_directories() private function
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4538>
+
+2023-04-29 12:16:09 +0100  Tim-Philipp Müller <tim@centricular.com>
+
+	* gst/gstpluginfeature.c:
+	* tests/check/gst/gstplugin.c:
+	  pluginfeature: fix unexpected version check behaviour for git versions
+	  check_version(1.23.1) would return TRUE for a git development version
+	  like 1.23.0.1, which is quite confusing and somewhat unexpected.
+	  We fixed this up in the version check macros already in !2501, so this
+	  updates the run-time check accordingly as well.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4513>
+
+2023-04-22 04:27:54 +0900  Seungha Yang <seungha@centricular.com>
+
+	* gst/gstsample.c:
+	* gst/gstsample.h:
+	  sample: Add gst_clear_sample() method
+	  Similar to other GstMiniObject clear helper methods like
+	  gst_clear_buffer().
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4473>
+
+2023-04-22 04:11:40 +0900  Seungha Yang <seungha@centricular.com>
+
+	* gst/gstsample.c:
+	* gst/gstsample.h:
+	  sample: Fix typo around gst_sample_copy() method
+	  It's sample, not buffer
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4473>
+
+2023-04-26 15:55:05 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+
+	* gst/gstpad.c:
+	  core: pad: fully log event being pushed
+	  It's useful when debugging to check the details of the event being sent,
+	  like the segment for example.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4493>
+
+2023-03-19 15:35:29 -0300  Thibault Saunier <tsaunier@igalia.com>
+
+	* docs/gst-plugins-doc-cache-generator.py:
+	* docs/meson.build:
+	  doc: Avoid shelling out to hotdoc to generate plugins config files
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4479>
+
+2023-04-04 22:03:18 +0300  Jordan Petridis <jordan@centricular.com>
+
+	* tests/check/gst/gstinfo.c:
+	  build: appease clang warning
+	  Clang complains about these variables being (possibly) unitialized, even
+	  when they are assigned to NULL or proper value inside the macro.
+	  Might as well initialize them to avoid the warning.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4281>
+
+2022-08-31 14:15:16 -0400  Thibault Saunier <tsaunier@igalia.com>
+
+	* gst/meson.build:
+	* libs/gst/base/meson.build:
+	* libs/gst/check/meson.build:
+	* libs/gst/controller/meson.build:
+	* libs/gst/net/meson.build:
+	  gir: Checkout all .gir files and check that they are updated on the CI
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3010>
 
-2022-07-09 16:50:54 +0300  Sebastian Dröge <sebastian@centricular.com>
+2023-04-19 14:12:31 +0200  Ruben Gonzalez <rgonzalez@fluendo.com>
 
 	* gst/gst.c:
-	  gst: Don't fail gst_init() if updating the registry fails
-	  Everything is already marked as initialized at that point and by failing
-	  no tracers would be loaded or plugin feature rank overrides would be
-	  applied.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2740>
+	* po/it.po:
+	* tools/gst-inspect-1.0.1:
+	* tools/gst-launch-1.0.1:
+	* tools/gst-typefind-1.0.1:
+	  gst: Delete inoperative ARG_PLUGIN_SPEW
+	  Logic related with the option was deleted 20 years ago in commit:
+	  086de421dc
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4452>
 
-2022-08-03 12:32:24 +0100  Tim-Philipp Müller <tim@centricular.com>
+2023-04-11 21:23:00 +0200  badcel <33569-badcel@users.noreply.gitlab.gnome.org>
 
-	* plugins/tracers/gstleaks.c:
-	  tracers: leaks: delay type name lookup
-	  Micro optimisation: Store the quark of the type name when tracking
-	  objects and only do the quark to string conversion (hashtable lookup)
-	  later when we actually need the string.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2832>
+	* libs/gst/base/gstadapter.c:
+	  base: adapter: Explicitly mark size parameter as input
+	  The generated gir file marks the size parameter as "out" by default.
+	  This is wrong in the context of a caller allocated buffer with a given size.
+	  Explicitly marking the size parameter as (in) fixes the issue.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4399>
 
-2022-08-03 12:10:02 +0100  Corentin Damman <c.damman@intopix.com>
+2023-04-13 15:38:54 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* plugins/tracers/gstleaks.c:
-	  tracers: leaks: fix potentially invalid memory access when trying to detect object type
-	  The is_gst_mini_object_check would sometimes detect a proper GObject
-	  as a mini object, and then bad things happen.
-	  We know whether a pointer is a proper GObject or a MiniObject here
-	  though, so just pass that information to the right code paths and
-	  avoid the heuristics altogether.
-	  Eliminates all remaining uses of object_is_gst_mini_object().
-	  Fixes #1334
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2832>
-
-2022-08-03 12:10:02 +0100  Tim-Philipp Müller <tim@centricular.com>
+	* libs/gst/helpers/ptp/meson.build:
+	* meson_options.txt:
+	  ptp-helper: Add a feature option for the PTP support
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4410>
 
-	* plugins/tracers/gstleaks.c:
-	  tracers: leaks: fix potentially invalid memory access when trying to detect object type
-	  The is_gst_mini_object_check would sometimes detect a proper GObject
-	  as a mini object, and then bad things happen.
-	  We know whether a pointer is a proper GObject or a MiniObject here
-	  though, so just pass that information to the right code paths and
-	  avoid the heuristics altogether.
-	  There are probably more cases where the check should be eliminated.
-	  Fixes #1334, maybe
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2832>
-
-2022-07-28 19:44:20 +0000  Rafael Sobral <rafaelsobral@pm.me>
+2023-04-13 15:22:23 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* libs/gst/base/gstaggregator.c:
-	  aggregator: fix reversed active/flushing arguments in debug log output
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2813>
+	* libs/gst/helpers/ptp/meson.build:
+	  ptp-helper: Convert various meson message() to warning()
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4410>
 
-2022-05-26 15:26:40 +0100  Philippe Normand <philn@igalia.com>
+2023-04-13 15:21:20 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gstversion.h.in:
-	  GST_CHECK_VERSION: Fix unexpected "git = next version" assumption
-	  1.21.0.1 should not satisfy a check for 1.22.0.
-	  If someone needs more control they should do a feature check for
-	  the symbol in the headers or lib.
-	  Based on a similar patch by Tim-Philipp Müller for libnice.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2501>
+	* libs/gst/helpers/ptp/meson.build:
+	  ptp-helper: Don't check for a Rust compiler on unsupported platforms
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4410>
 
-2022-07-19 04:05:55 +0900  Seungha Yang <seungha@centricular.com>
+2023-04-13 14:46:43 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gststructure.c:
-	* gst/gststructure.h:
-	* tests/check/gst/gststructure.c:
-	  gststructure: Add gst_structure_get_flags method
-	  We don't prevent setting G_TYPE_FLAGS on GstStructure
-	  but no helper method for getting the value.
-	  Add a method similar to gst_structure_get_enum()
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2770>
+	* libs/gst/helpers/ptp/meson.build:
+	  ptp-helper: Check for the required Rust toolchain version via meson
+	  If an older version is found that gives a more useful output than a
+	  compiler error at a later time.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4410>
 
-2022-07-18 15:46:21 +0300  Sebastian Dröge <sebastian@centricular.com>
+2023-04-12 22:39:58 +0900  Seungha Yang <seungha@centricular.com>
 
-	* libs/gst/base/gstaggregator.c:
-	  aggregator: Reset EOS flag after receiving a stream-start event
-	  And also don't assert that there are no buffers queued up when handling
-	  an EOS event. The pad's streaming thread might've already received a new
-	  stream-start event and queued up a buffer in the meantime.
-	  This still leaves a race condition where the srcpad task sees all pads
-	  in EOS state and finishes the stream, while shortly afterwards a pad
-	  might receive a stream-start event again, but this doesn't seem to be
-	  solveable with the current aggregator design.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2769>
-
-2022-07-12 10:49:27 +0000  Corentin Damman <c.damman@intopix.com>
+	* gst/gstpluginloader-win32.c:
+	  pluginloader-win32: Fix for pipe connection error
+	  Don't error out on WAIT_IO_COMPLETION. It means queued APC job
+	  was executed but the job may not be our callback.
+	  For example, user or system might be able to schedule APC on
+	  gst_init() thread or so.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4405>
 
-	* plugins/tracers/gstleaks.c:
-	  tracers: leaks: fix object-refings.class flags
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2749>
+2023-04-12 10:58:31 +0300  Sebastian Dröge <sebastian@centricular.com>
+
+	* gst/gst.c:
+	  gst: tracer: Initialize tracing infrastructure even if the debug system is not compiled in
+	  There is a separate #define for the tracing infrastructure.
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/2467
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4402>
 
-2022-07-09 18:05:58 +0300  Sebastian Dröge <sebastian@centricular.com>
+2023-04-10 13:49:41 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstdevicemonitor.c:
-	  devicemonitor: Use a sync bus handler for the provider to avoid accumulating all messages until the provider is stopped
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/issues/981
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2741>
+	* po/sr.po:
+	  gstreamer: update translations
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4388>
 
-2022-07-08 16:37:51 +0200  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
+2023-04-11 07:23:48 +0200  Edward Hervey <edward@centricular.com>
 
-	* gst/gstinfo.c:
-	  gstinfo: Parse "NONE" as a valid level name
-	  This allows using `NONE` in `GST_DEBUG`,
-	  `gst_debug_set_threshold_from_string`, etc. It was accessible before,
-	  but only via the integer `0`.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2734>
+	* libs/gst/base/gsttypefindhelper.c:
+	  typefindhelper: Avoid dead assignment
+	  Move variables within the loop (where they are actually used)
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4387>
 
-2022-06-29 08:57:42 +0300  Sebastian Dröge <sebastian@centricular.com>
+2023-03-31 23:15:30 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gstpad.c:
-	* gst/gsttracerutils.c:
-	* gst/gsttracerutils.h:
-	  tracing: add hooks for gst_pad_chain() / gst_pad_chain_list()
-	  This allows tracing buffers when they arrive in a pad instead of just
-	  when they are pushed out of a pad.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2682>
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/ptp_helper_post_install.sh:
+	* libs/gst/helpers/ptp/thread.rs:
+	  ptp-helper: Set a process priority / nice value of -5 on UNIX platforms
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3889>
 
-2022-06-29 10:55:13 +0100  Tim-Philipp Müller <tim@centricular.com>
+2023-03-30 21:58:12 +0300  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gst.c:
-	* meson.build:
-	  coding style: allow declarations after statement
-	  See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1243/
-	  and https://gitlab.freedesktop.org/gstreamer/gstreamer-project/-/issues/78
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2683>
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/helpers/ptp/thread.rs:
+	  ptp-helper: Set thread priority to time-critical on Windows
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3889>
 
-2022-06-22 09:43:02 +0200  Jonas Danielsson <jonas.danielsson@spiideo.com>
+2023-02-04 00:55:39 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gst.c:
-	  gst: add missing define guard
-	  If compiled with -Dgstreamer:gst_debug=false and we have
-	  GST_REMOVE_DISABLED defined we will get the following compiler error:
-	  ```
-	  [...]/libgstreamer-1.0.so.0.2100.0.p/gst.c.o: in function `gst_deinit':
-	  [...]/gst/gst.c:1258: undefined reference to `_priv_gst_debug_cleanup'
-	  [...] hidden symbol `_priv_gst_debug_cleanup' isn't defined
-	  ```
-	  Add the missing define guard to avoid this.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2648>
+	* libs/gst/helpers/gst-ptp-helper.c:
+	* libs/gst/helpers/meson.build:
+	* libs/gst/helpers/ptp/args.rs:
+	* libs/gst/helpers/ptp/conf_lib.rs.in:
+	* libs/gst/helpers/ptp/error.rs:
+	* libs/gst/helpers/ptp/ffi.rs:
+	* libs/gst/helpers/ptp/io.rs:
+	* libs/gst/helpers/ptp/main.rs:
+	* libs/gst/helpers/ptp/meson.build:
+	* libs/gst/helpers/ptp/net.rs:
+	* libs/gst/helpers/ptp/privileges.rs:
+	* libs/gst/helpers/ptp/ptp_helper_post_install.sh:
+	* libs/gst/helpers/ptp/rand.rs:
+	  ptp-helper: Rewrite in Rust for portability and security
+	  This works on Linux, Android, Windows, macOS, FreeBSD, NetBSD, OpenBSD,
+	  DragonFlyBSD, Solaris and Illumos.
+	  Newly supported compared to the C version is Windows.
+	  Compared to the C version various error paths are handled more correctly
+	  and a couple of memory leaks are fixed. Otherwise it should work identically.
+	  The minimum required Rust version for compiling this is 1.48, i.e. the
+	  version currently in Debian stable. On Windows, Rust 1.54 is needed at
+	  least.
+	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1259
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3889>
+
+2023-04-03 11:24:42 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
 
-2022-06-21 11:51:35 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* libs/gst/base/gstbasesrc.c:
+	* libs/gst/base/gstbasesrc.h:
+	  basesrc: add gst_base_src_push_segment()
+	  gst_base_src_new_segment() does not send the segment right away, which
+	  may break events ordering if subclass sends other events after
+	  calling it.
+	  Introducing a variant pushing the segment right away to preserve
+	  ordering in such cases.
+	  Will be used by appsrc which has its own internal queue where we need to
+	  preserve events order.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4297>
+
+2021-05-06 14:07:35 +0200  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
 
-	* tests/check/gst/gstbin.c:
-	  bin: Fix race conditions in tests
-	  The latency messages are non-deterministic and can arrive before/after
-	  async-done or during state-changes as they are posted by e.g. sinks from
-	  their streaming thread but bins are finishing asynchronous state changes
-	  from a secondary helper thread.
-	  To solve this, expect latency messages at any time and assert that we
-	  receive one at some point during the test.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2643>
+	* plugins/elements/gstmultiqueue.c:
+	  multiqueue: Simplify gst_multi_queue_iterate_internal_links
+	  We don't need to obtain the mutex to ensure that `sq` is non-NULL. `sq`
+	  is assigned immediately after the pads are created and not destroyed
+	  until the pads are finalized.
+	  Use the pad direction to determine which internal peer we need.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/888>
 
-2022-06-20 16:45:19 +0300  Sebastian Dröge <sebastian@centricular.com>
+2023-02-28 11:48:27 -0600  Michael Gruner <michael.gruner@ridgerun.com>
 
 	* gst/gstelement.c:
-	* tests/check/gst/gstelement.c:
-	  element: Fix requesting of pads with string templates
-	  Previously it was only possible to request them with the exact template
-	  name, e.g. 'src_%s', but not with "instantiated" names that would match
-	  this template, e.g.'src_foo_bar'.
-	  This is now possible and a test was added for this, in addition to
-	  fixing a previously invalid test.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2635>
-
-2022-05-17 10:18:28 -0700  Xavier Claessens <xavier.claessens@collabora.com>
+	  gstelement: protect async state changes against spurious wake ups
+	  When a pipeline is pre-rolling, it waits for all sink elements to report
+	  they have received a buffer before completing the transition to paused.
+	  This async wait is done using a state condition variable. The way this
+	  waits are currently implemented do not protect against spurious conditional
+	  wake ups, which may happen due to external factors in the kernel.
+	  This change implements the wait within a loop that iterates over the protected
+	  variable to reinitiates the wait if the wakeup was spurious. More details in
+	  the [GCond docs](https://docs.gtk.org/glib/struct.Cond.html).
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4086>
+
+2023-03-28 19:58:30 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstbuffer.h:
-	* gst/gstmemory.h:
-	  Add GstMemoryMapInfo to be used with g_auto()
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2412>
+	* tools/gst-inspect.c:
+	  tools: gst-inspect: print action signals as emit_by_name() invocations
+	  It's quite confusing to print a function callback signature for
+	  action signals when people need to do a g_signal_by_name() invocation
+	  in order to use this feature. Requires too much background knowledge
+	  about how GObject works under the hood to make sense of that.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4299>
 
-2022-05-13 11:51:09 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+2023-03-29 16:46:43 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstbuffer.c:
-	* gst/gstbuffer.h:
-	* tests/check/gst/gstbuffer.c:
-	  Add GstBufferMapInfo to be used with g_auto()
-	  We need a separate typedef for this feature because GstMapInfo itself
-	  can be initialized by gst_memory_map() in which case info.memory should
-	  not be unreffed.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2412>
+	* tools/gst-inspect.c:
+	  tools: gst-inspect: prettify type names for strings
+	  'gchararray' and 'GStrv' are not types used anywhere else
+	  and are just confusing. Map that to 'const gchar *' and 'gchar *'
+	  etc. depending on context.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4299>
 
-2022-06-20 15:29:21 +0100  Philippe Normand <philn@igalia.com>
+2023-03-28 19:56:14 +0100  Tim-Philipp Müller <tim@centricular.com>
 
 	* tools/gst-inspect.c:
-	  gst-inspect: Fix inspection of third-party plugins
-	  Since commit de57657de1d1916503b4ad451ac13a3e191465f8 inspecting a third-party
-	  plugin would trigger a segfault (Address boundary error) due to the missing
-	  sentinel in the list of GStreamer modules.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2636>
+	  tools: gst-inspect: add vertical spacing between properties and signals
+	  Makes it easier to read and less squashed.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4299>
 
-2022-06-14 16:30:08 +0100  Tim-Philipp Müller <tim@centricular.com>
+2023-03-31 04:40:58 +0900  Seungha Yang <seungha@centricular.com>
 
-	* docs/meson.build:
-	* docs/plugins/coretracers/index.md:
-	* docs/plugins/coretracers/sitemap.txt:
-	  docs: ensure coretracers plugin index page is index.html
-	  And not blank.html
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2592>
+	* tools/gst-inspect.c:
+	* tools/gst-launch.c:
+	* tools/gst-stats.c:
+	* tools/gst-typefind.c:
+	  tools: Count argc after parsing GOption on Windows
+	  Existing codes rely on modified argc value by g_option_context_parse()
+	  but g_option_context_parse_strv() is used in case of Windows.
+	  Count arguments after the option parsing manually.
+	  Fixing command "gst-inspect-1.0.exe -b"
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4313>
 
-2022-06-12 23:28:21 +0100  Tim-Philipp Müller <tim@centricular.com>
+2023-03-28 16:13:51 +0200  Juan Navarro <juan.navarro@gmx.es>
 
-	* tools/gst-inspect.c:
-	  gst-inspect: print link to documentation for gstreamer elements
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2592>
+	* gst/gstutils.c:
+	  gstutils: Add category and object to most logging messages
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4291>
 
-2022-05-19 04:59:58 +0000  Adam Doupe <adamdoupe@gmail.com>
+2023-03-24 18:34:36 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-	* libs/gst/base/gstqueuearray.c:
-	  queuearray: Fix potential heap overflow when expanding GstQueueArray
-	  Check that elt_size*newsize doesn't overflow when expanding a
-	  GstQueueArray, which has the potential for a heap overwrite.
-	  Co-authored-by: Sebastian Dröge <sebastian@centricular.com>
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1232
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2606>
+	* gst/gstdatetime.c:
+	  datetime: Return G_MAXFLOAT instead of G_MAXDOUBLE for no timezone offset
+	  Returning G_MAXDOUBLE from a function returning a float is not going to
+	  work well and MSVC also correctly warns about this.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4264>
 
-2022-06-15 12:56:13 +0200  Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+2023-03-26 16:40:28 +0100  Tim-Philipp Müller <tim@centricular.com>
 
-	* libs/gst/check/gstharness.c:
-	  docs: harness: Fix example
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2602>
+	* gst/gsttaglist.c:
+	  taglist, plugins: fix compiler warnings with GLib >= 2.76
+	  Fix compiler warnings about not using the return value when
+	  freeing the GString segment with g_string_free(.., FALSE):
+	  ignoring return value of ‘g_string_free_and_steal’ declared with attribute ‘warn_unused_result’
+	  which we get with newer GLib versions. These were all harmless.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4273>
 
-2022-06-14 17:29:31 +0100  Tim-Philipp Müller <tim@centricular.com>
+2023-03-22 14:40:32 +0100  Aleksandr Slobodeniuk <aslobodeniuk@fluendo.com>
 
-	* plugins/elements/gstmultiqueue.c:
-	  multiqueue: fix potential crash on shutdown
-	  The mq we get out of the weak ref might be NULL if we're
-	  shutting down, which could cause assertion failures or
-	  crashes.
-	  It might also cause miscompilations where the compiler just
-	  optimises away the NULL check because it jumps to a code path
-	  that then dereferences the pointer which clearly isn't going
-	  to work. Seems like something like this happens with gcc 11.
-	  Fixes #1262
-	  Co-authored-by: Doug Nazar <nazard@nazar.ca>
-	  Co-authored-by: Sebastian Dröge <sebastian@centricular.com>
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2599>
-
-2022-06-14 03:29:41 -0600  James Hilliard <james.hilliard1@gmail.com>
+	* gst/gstbin.c:
+	  bin: fix documentation about event forwarding
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4249>
 
-	* plugins/elements/gstmultiqueue.c:
-	  multiqueue: fix warning: ‘is_query’ may be used uninitialized in this function
-	  Fixes:
-	  ../plugins/elements/gstmultiqueue.c: In function ‘gst_multi_queue_loop’:
-	  ../plugins/elements/gstmultiqueue.c:2394:19: warning: ‘is_query’ may be used uninitialized in this function [-Wmaybe-uninitialized]
-	  2394 |     if (object && !is_query)
-	  |                   ^~~~~~~~~
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2593>
+2023-03-15 18:51:03 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-06-10 11:40:18 +0100  Tim-Philipp Müller <tim@centricular.com>
+	* docs/gst-hotdoc-plugins-scanner.c:
+	* gst/gstandroid.c:
+	* gst/gstclock.c:
+	* gst/gstcontrolbinding.c:
+	* gst/gstplugin.c:
+	* gst/gsttask.c:
+	* gst/gstutils.c:
+	* gst/printf/asnprintf.c:
+	* gst/printf/vasnprintf.c:
+	* libs/gst/base/gstcollectpads.c:
+	* libs/gst/check/libcheck/check_run.c:
+	* libs/gst/check/libcheck/libcompat/getline.c:
+	* libs/gst/controller/gstinterpolationcontrolsource.c:
+	* libs/gst/controller/gstlfocontrolsource.c:
+	* plugins/elements/gstinputselector.c:
+	* plugins/elements/gstqueue2.c:
+	* plugins/elements/gsttypefindelement.c:
+	* tests/check/elements/tee.c:
+	* tests/check/gst/gstdevice.c:
+	* tests/check/gst/gstutils.c:
+	* tests/check/gst/gstvalue.c:
+	* tools/gst-inspect.c:
+	  gstreamer: re-indent with GNU indent 2.2.12
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4182>
 
-	* docs/random/moving-plugins:
-	  docs: update technical howto in moving-plugins
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2583>
+2023-03-16 12:38:23 +0200  Vivia Nikolaidou <vivia@ahiru.eu>
 
-2022-06-08 11:33:22 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+	* plugins/elements/gstinputselector.c:
+	  inputselector: Wake up streaming thread before PLAYING_TO_PAUSED transition
+	  Also take object lock before iterating the pads.
+	  https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1772
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4190>
 
-	* gst/gst_private.h:
-	* gst/gstclock.c:
-	  clock: Use g_atomic_rc_box for refcounting entry clocks
-	  g_atomic_rc_box was added in GLib 2.58, and we require 2.62 now, so we
-	  can fix the FIXME and use this.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2568>
+2023-03-16 10:56:13 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-2022-04-06 12:56:30 +0100  Tim-Philipp Müller <tim@centricular.com>
+	* tests/check/pipelines/parse-launch.c:
+	  parse: Add unit test for array parsing in capsfilters
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4181>
 
-	* gst/gstdevicemonitor.c:
-	* meson.build:
-	* tests/check/gst/gsturi.c:
-	  Bump GLib requirement to >= 2.62
-	  Can't require 2.64 yet because of
-	  https://gitlab.freedesktop.org/gstreamer/cerbero/-/issues/323
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2568>
+2023-03-15 19:13:33 +0100  Mathieu Duponchelle <mathieu@centricular.com>
 
-2022-06-01 09:25:29 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+	* gst/parse/grammar.y.in:
+	  parse: fix parsing arrays in caps for "implicit" capsfilters
+	  When using such a launch line:
+	  fakesrc ! "audio/x-opus, channel-mapping=(int)<0, 1>" ! fakesink
+	  the caps string, with spaces escaped but no quotes gets passed to
+	  gst_caps_from_string(), which then fails to parse the array because it
+	  contains spaces.
+	  When using an explicit capsfilter instead:
+	  fakesrc ! capsfilter caps="audio/x-opus, channel-mapping=(int)<0, 1>" ! fakesink
+	  the caps string, with spaces escaped and quotes gets passed through
+	  gst_value_deserialize, which first calls gst_str_unwrap() on it and only
+	  then gst_caps_from_string() on the result.
+	  This fixes the inconsistency by using a custom version of str_unwrap()
+	  in the parser, which doesn't expect a quoted string.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4181>
+
+2023-03-15 09:11:51 -0400  Xavier Claessens <xavier.claessens@collabora.com>
 
-	* libs/gst/base/gstbasetransform.c:
-	  basetransform: handle gst_base_transform_query_caps() returning NULL
-	  If gst_base_transform_transform_caps() returns NULL, gst_base_transform_query_caps()
-	  will return NULL as well.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2532>
+	* gst/gstbuffer.c:
+	* tests/check/gst/gstbufferpool.c:
+	  gstbuffer: Add parent meta when a copy shares memory with parent
+	  When copying a buffer, for example with gst_buffer_make_writable(), the
+	  new buffer might reference the same GstMemory as the src buffer,
+	  making those memories not writable. If the src buffer gets disposed
+	  first it should return to its buffer pool, but since some of its
+	  memories are not writable it gets discarded and new buffer/memory gets
+	  allocated.
+	  Solves this by making the new buffer keep a reference to the src buffer,
+	  that ensures that by the time the src buffer gets disposed no other
+	  buffer are referencing its memories and it can thus return safely to its
+	  pool.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4176>
+
+2023-03-09 22:18:12 -0800  Xavier Claessens <xavier.claessens@collabora.com>
 
-2022-05-18 17:03:27 +0200  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
+	* gst/gstbuffer.c:
+	* tests/check/gst/gstbufferpool.c:
+	  gstbuffer: Unref memories before metas
+	  gst_buffer_add_parent_buffer_meta() is used when a GstBuffer uses
+	  GstMemory from another buffer that was allocated from a pool. In that
+	  case we want to make sure the buffer returns to the pool when the memory
+	  is writable again, otherwise a copy of the memory is created. That means
+	  the child buffer must drop its ref to the memory first, then drop the
+	  ref to parent buffer so it can return to the pool when it is the only
+	  owner of the memory.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4176>
+
+2023-02-15 13:10:25 -0500  Nicolas Dufresne <nicolas.dufresne@collabora.com>
 
-	* gst/gst_private.h:
-	* gst/gstclock.c:
-	  clock: Avoid creating a weakref with every entry
-	  Creating and destroying weakrefs takes a write lock on a global
-	  `GRWLock`. This makes for a very contended lock when the pipeline has
-	  many synchronizing elements.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2530>
+	* libs/gst/base/gstbasesink.c:
+	* libs/gst/base/gstbasesink.h:
+	  basesink: Add GST_BASE_SINK_FLOW_DROPPED return value
+	  This new flow return value can be used in ::render virtual method
+	  to signal that a frame is not being rendered.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3801>
 
-2022-05-31 14:27:51 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+2023-03-10 20:45:35 +0100  Alicia Boya García <ntrrgc@gmail.com>
 
-	* libs/gst/base/gstbasetransform.c:
-	  basetransform: fix critical if transform_caps() returned NULL
-	  klass->transform_caps() may return NULL, which was raising this
-	  critical:
-	  GStreamer-CRITICAL **: 12:23:56.243: gst_caps_is_subset: assertion 'subset != NULL' failed
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2528>
+	* plugins/tracers/gstlog.c:
+	  tracers: Document the 'log' tracer
+	  This patch adds documentation to the 'log' tracer and amends the design
+	  document of Tracers to replace a misleading example of the 'log' tracer
+	  with a different example that uses tracer arguments with tracers that do
+	  actually handle said arguments.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4153>
 
-2022-05-29 20:38:38 +1000  tom schuring <tomschuring@gmail.com>
+2023-03-09 22:18:12 -0800  Xavier Claessens <xavier.claessens@collabora.com>
 
-	* gst/gstplugin.c:
-	  plugin: add Apache 2 license to known licenses
-	  the licence in gstreamer/subprojects/gstreamer/gst/gstplugin.c
-	  currently is defined to be one of:
-	  LGPL GPL QPL GPL/QPL MPL BSD MIT/X11 0BSD Proprietary
-	  The open source project for the kinesis plugin is using an
-	  Apache 2.0 license. Because "Apache 2.0" is not one of the
-	  supported licenses it automatically falls back to Proprietary.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2514>
+	* gst/gstallocator.c:
+	  gstallocator: Use the right allocator instance to free memory
+	  In the case GST_ALLOCATOR_FLAG_CUSTOM_ALLOC is set, `copy` is allocated
+	  by the default allocator and not mem->allocator.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4144>
 
-2022-01-21 20:31:27 -0300  Thibault Saunier <tsaunier@igalia.com>
+2023-03-09 08:46:17 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
 
-	* gst/gst_private.h:
-	* gst/gststructure.c:
 	* gst/gstvalue.c:
-	* tests/check/gst/gststructure.c:
-	  structure: Fix serializing with new format inside arrays/lists
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1554>
+	* tests/check/gst/gstvalue.c:
+	  gstvalue: Implement union for GstFractionRange
+	  This fixes simplification of caps with GstFractionRange structures,
+	  for example, this caps:
+	  video/x-raw, framerate=(fraction)5/1; video/x-raw, framerate=(fraction)[ 5/1, 30/1 ]
+	  can now be simplified to:
+	  video/x-raw, framerate=(fraction)[ 5/1, 30/1 ]
+	  instead of:
+	  video/x-raw, framerate=(fraction){ 5/1, [ 5/1, 30/1 ] }
+	  And this:
+	  video/x-raw, framerate=(fraction)[ 2/1, 5/1 ]; video/x-raw, framerate=(fraction)[ 5/1, 30/1 ]
+	  can be simplified to:
+	  video/x-raw, framerate=(fraction)[ 2/1, 30/1 ]
+	  instead of
+	  video/x-raw, framerate=(fraction){ [ 2/1, 5/1 ], [ 5/1, 30/1 ] }
+	  This fixes overly-complicated GL caps set by avfvideosrc on macOS and
+	  iOS when capturing from a webcam.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4132>
+
+2022-11-29 18:32:09 +0800  Chao Guo <chao.guo@nxp.com>
 
-2022-05-18 10:04:08 +0800  WANG Xuerui <xen0n@gentoo.org>
+	* gst/gstbin.c:
+	  bin: Fix bin won't post async done message to parent while nothing pending in state changing
+	  When we run Cheese 41.1 on our imx platform, Cheese preview freeze
+	  at first frame.
+	  During pipeline state changing from NULL to PLAYING, if there are
+	  both elements that state change asynchronously and state change
+	  with no preroll in the bin, the element inside may send ASYNC_DONE
+	  message to it, while the bin's pending state is VOID_PENDING.
+	  In this case, the bin will not post ASYNC_DONE message to parent
+	  bin, which makes parent bin thinks that there are still elements
+	  in it that haven't completed state changing, causing the pipeline
+	  freeze in an intermediate state.
+	  This commit modifies the bin_handle_async_done() function. When the
+	  bin, whose pending state is VOIDING_PENDING, receives the ASYNC_DONE
+	  message, it will also post this message to its parent bin.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3490>
+
+2022-11-26 13:36:32 +0100  Alicia Boya García <ntrrgc@gmail.com>
 
-	* gst/gstconfig.h.in:
-	  gstreamer/gst/gstconfig.h.in: Add support for LoongArch
-	  While current and future LoongArch machines that are supposed to run
-	  GStreamer all support unaligned accesses, there might be future
-	  lower-end cores (e.g. the embedded product line) without such support,
-	  and we may not want to penalize these use cases.
-	  So, mark LoongArch as not supporting unaligned accesses for now, and
-	  hope the compilers do a good job optimizing them. We can always flip
-	  switch later.
-	  Suggested-by: CHEN Tao <redeast_cn@outlook.com>
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2443>
+	* libs/gst/base/gstbasesink.c:
+	* tests/check/elements/fakesink.c:
+	  basesink: Support position queries after non-resetting flushes
+	  A flush is resetting or not depending on the reset_time argument in the
+	  FLUSH_STOP event is set.
+	  Resetting flushes reset the running time to zero and clear any existing
+	  segment. These are the kind of flushes used by flushing seeks, and by far the
+	  most common. Non-resetting flushes are much more niche, used for instance for
+	  quality changes in adaptivedemux2 and MediaSource Extensions in WebKit.
+	  A key difference between the seek use case and the quality change use case is
+	  that the latter is much more removed from the player. Seeks generally occur
+	  because an user request it, whereas quality changes can be automatic.
+	  Currently, there are three notable cases where position queries fail:
+	  (a) before pre-roll, as there is no segment yet. This is one is understandable,
+	  as for at least some time before pre-roll, we cannot know if a media stream
+	  would start at 0 or any other position, or the duration of the stream for that
+	  matter.
+	  (b) after a resetting flush caused by a seek. This kind of flush resets the
+	  segment, so it's not surprising position queries fail. This is inconvenient for
+	  applications, as it means they always need to handle position reporting (e.g.
+	  in UI) separately every time they request a seek, e.g. by caching the seek
+	  target and using it when the position query fail. I'm not fond of this
+	  behavior, as it's unintuitive and makes GStreamer harder to use, but at this
+	  point could be difficult to change and it's not within the scope of this
+	  proposal.
+	  (c) after a non-resetting flush, e.g. caused by a quality change. The segment
+	  is not reset in this case. Position queries work until a FLUSH_STOP is sent.
+	  Querying position after a FLUSH_START but before a FLUSH_STOP works, and
+	  returns the position the sink was at the moment the FLUSH_START was received.
+	  **This in fact the only reliable way (short of adding probes to the sink
+	  element) to get this position**, as FLUSH_START receival is asynchronous with
+	  playback.
+	  In the case (c), as of currently, position queries fail once the FLUSH_STOP is
+	  received. But unlike in (b), the application has no position to fall back to,
+	  as the FLUSH_START was initiated by elements inside the pipeline that are in a
+	  lower layer of abstraction. Specific applications that have control of both the
+	  player and the internal element doing the flushing -- such as WebKit -- can
+	  still work around this problem through layer violations (lucky!), but this
+	  still puts in question this behavior in GStreamer.
+	  This patch fixes this case by amending the position query handler of basesink,
+	  which was previously erroneously returning early with "wrong state", even
+	  though the flush occurs in PAUSED or PLAYING.
+	  A unit test checking this behavior has also been added.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3471>
+
+2023-03-02 15:51:08 +0200  Vivia Nikolaidou <vivia@ahiru.eu>
 
-2022-05-12 20:15:44 +0300  Sebastian Dröge <sebastian@centricular.com>
+	* plugins/elements/gstinputselector.c:
+	* plugins/elements/gstinputselector.h:
+	  inputselector: Avoid deadlock when shutting down
+	  Transition from PLAYING to PAUSED unschedules any pending clock wait,
+	  but there was no guard that prevented another input buffer then waiting
+	  again while in PAUSED before dataflow stops. Use a new `playing` flag to
+	  avoid this, and exit the chain function if instead of playing we're now
+	  flushing. Basically the same as the clocksync element.
+	  Closes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1772
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4098>
 
-	* gst/gstelement.c:
-	  element: Add sanity check with a critical warning if a pad is requested for a pad template that is not installed on the element class
-	  Various elements are assuming that the pointer matches a pad template
-	  they know about, and also randomly created pad templates might be
-	  missing some important information that is necessary to create a valid
-	  pad.
-	  For example, creating a new pad template for audiomixer's sinkpad
-	  without providing the correct GType would cause audiomixer to create a
-	  GstAggregatorPad. That will then later fail spectacularly because it
-	  assumes that it got a GstAudioAggregatorPad.
-	  Passing a pad template that does not belong to the element class in here
-	  will easily lead to undefined behaviour.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2410>
-
-2022-04-25 11:03:35 +0200  Stéphane Cerveau <scerveau@collabora.com>
-
-	* tests/check/gst/gstcaps.c:
-	  tests: test fixed caps
-	  Add a test entry to check wether a caps is fixed
-	  or not.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2290>
-
-2022-04-25 10:59:21 +0200  Stéphane Cerveau <scerveau@collabora.com>
+2022-01-13 00:45:25 +0100  Mathieu Duponchelle <mathieu@centricular.com>
 
-	* gst/gstcaps.c:
-	* tests/check/pipelines/seek.c:
-	  caps: warn with wrong mediatype in gst_caps_new_empty_simple
-	  If passing ANY/EMPTY to gst_caps_new_empty_simple
-	  as a mediatype, a warning will be displayed to alert
-	  on this misuse of the API.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2290>
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: improve parsing in create_new_pad
+	  The previous implementation was a bit primitive, assuming the subclass
+	  had registered a template name starting with sink_ . Instead make
+	  the effort of parsing the actual template name, and use that to generate
+	  the final pad name.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4032>
 
-2022-05-05 20:39:52 +0300  Sebastian Dröge <sebastian@centricular.com>
+2022-01-29 19:36:16 +0100  Stefan Brüns <stefan.bruens@rwth-aachen.de>
 
-	* libs/gst/base/gstaggregator.c:
-	  aggregator: Don't send multiple caps events with the same caps
-	  Every time aggregator is reconfiguring it will try to negotiate new
-	  caps. If these resulting caps are the same as the previously negotiated
-	  caps then don't send a new caps event with the same caps again.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2372>
+	* tools/gst-inspect.c:
+	  gst-inspect: Enhance auto-install-info output for De/Encryptor class
+	  Without this it is not possible to lookup which plugin handles a specific
+	  encrypted mimetype (e.g. application/x-cenc or application/x-aavd).
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1604>
 
-2022-05-05 15:05:43 +0300  Sebastian Dröge <sebastian@centricular.com>
+2023-02-22 11:51:58 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* libs/gst/base/gstaggregator.c:
-	  aggregator: Only send events up to CAPS event from gst_aggregator_set_src_caps()
-	  Otherwise setting the srcpad caps based on the sinkpad caps event will
-	  already push a segment event downstream before the upstream segment is
-	  known.
-	  If the upstream segments are just forwarded when the upstream segment
-	  event arrives this would result in two segment events being sent
-	  downstream, of which the first one will usually be simply wrong.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2372>
+	* po/fur.po:
+	  gstreamer: update translations
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4040>
 
-2022-05-05 09:00:17 +0200  Edward Hervey <edward@centricular.com>
+2023-02-21 20:13:57 -0700  James Hilliard <james.hilliard1@gmail.com>
 
-	* plugins/elements/gstmultiqueue.c:
-	  multiqueue: Increase initial interleave growth rate
-	  In the case where not all streams have received any data, growing the interleave
-	  by only 100ms is too restrictive and would cause some (valid) mpeg-ts streams to
-	  hang.
-	  Bump up the interleave growth rate for those use-cases to 500ms per input (still
-	  up to the limit of 5s).
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2370>
+	* gst/gstbuffer.c:
+	  buffer: fix copy meta reference debug log formatting
+	  Fixes the following valgrind error:
+	  ==616== Conditional jump or move depends on uninitialised value(s)
+	  ==616==    at 0x4900E34: gst_debug_print_object (gstinfo.c:1143)
+	  ==616==    by 0x49010B6: gst_info_printf_pointer_extension_func (gstinfo.c:1215)
+	  ==616==    by 0x4959FDB: __gst_printf_pointer_extension_serialize (printf-extension.c:47)
+	  ==616==    by 0x495A487: printf_postprocess_args (vasnprintf.c:258)
+	  ==616==    by 0x495A52C: __gst_vasnprintf (vasnprintf.c:290)
+	  ==616==    by 0x4959F8F: __gst_vasprintf (printf.c:154)
+	  ==616==    by 0x4901C1F: gst_debug_message_get (gstinfo.c:791)
+	  ==616==    by 0x4901C75: _gst_debug_log_preamble (gstinfo.c:1431)
+	  ==616==    by 0x4903208: gst_debug_log_default (gstinfo.c:1575)
+	  ==616==    by 0x49020BA: gst_debug_log_full_valist (gstinfo.c:624)
+	  ==616==    by 0x490211D: gst_debug_log_valist (gstinfo.c:656)
+	  ==616==    by 0x49021AD: gst_debug_log (gstinfo.c:533)
+	  ==616==    by 0x48DDC11: gst_buffer_copy_into (gstbuffer.c:693)
+	  ==616==    by 0x48DF5F1: gst_buffer_copy_with_flags (gstbuffer.c:727)
+	  ==616==    by 0x48DF640: gst_buffer_copy_deep (gstbuffer.c:756)
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4034>
+
+2023-02-09 13:53:48 +0100  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
 
-2022-05-02 11:41:52 +0100  Tim-Philipp Müller <tim@centricular.com>
+	* gst/gstpad.c:
+	  pad: Don't leak user_data in gst_pad_start_task
+	  When the task already exists, we forgot to free the passed `user_data`.
+	  This wasn't an issue for most C code, which doesn't pass a
+	  `GDestroyNotify`, but bindings such as gstreamer-rs do!
+	  That said, allocating a trampoline in gstreamer-rs just for it to get
+	  thrown away again is awkward. Maybe we need a `gst_pad_resume_task`?
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3920>
 
-	* plugins/elements/gstfilesink.c:
-	  filesink: fix handling of non-existing paths with musl
-	  Fixes #1194
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2341>
+2023-01-30 23:49:25 -0300  Thibault Saunier <tsaunier@igalia.com>
 
-2022-04-09 21:07:43 +0100  Tim-Philipp Müller <tim@centricular.com>
+	* gst/gstbin.c:
+	  bin: Do not deactivate pad in NULL_TO_READY
+	  Since https://gitlab.freedesktop.org/gstreamer/gstreamer/-/commit/b76d3365497ded1fd4d536f0da2b9702f614b806
+	  pads are deactivated when going to READY but in `uridecodebin(3)`, the
+	  sources source pads are activated while in NULL state (when PULL mode is
+	  supported), meaning that we are ending up deactivating those pads in
+	  NULL_TO_READY, breaking the pipeline.
+	  The intent of the commit mentioned above is to ensure that the pads are
+	  deactivated either in PAUSED_TO_READY or READY_TO_READY, so it should
+	  be safe to avoid deactivating in NULL_TO_READY.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3849>
+
+2023-02-07 13:43:06 +0000  medithe <medithe@gmx.at>
 
-	* gst/gstregistry.c:
-	  registry: skip Rust dep builddirs when searching for plugins recursively
-	  These artefacts confuse the plugin scanner and may cause noisy warnings
-	  (and slow down things).
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gst-build/-/issues/68
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2146>
+	* gst/gstbin.c:
+	  gstreamer: bin: Don't unlock unlocked mutex in gst_bin_remove_func()
+	  Calling `g_mutex_unlock(mutex)` leads to an undefined behavior if the
+	  mutex is not locked by the current thread.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3903>
 
-2020-11-26 18:11:12 +0100  Mathieu Duponchelle <mathieu@centricular.com>
+2023-02-03 14:29:10 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-	* libs/gst/base/gstaggregator.c:
-	  aggregator: forward gap event information to gap buffer
-	  When the GAP event was flagged with MISSING_DATA, subclasses
-	  may want to adopt a different behaviour, for example by repeating
-	  the last buffer.
-	  As we turn these gap events into gap buffers, we need to flag
-	  those, we do so with a new custom meta.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/708>
+	* libs/gst/net/gstptpclock.c:
+	  net: ptp: Use GSubprocess instead of lower-level GLib APIs that don't work on Windows
+	  libgstnet depends on GIO already anyway so we can as well make use of it
+	  instead of a half-baked Windows implementation that doesn't actually
+	  work.
+	  As a next step, the helper process also needs to be made usable on
+	  Windows.
+	  See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1259
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3887>
 
-2022-02-25 16:54:37 -0500  Xavier Claessens <xavier.claessens@collabora.com>
+2023-01-28 02:32:13 +0900  Seungha Yang <seungha@centricular.com>
 
-	* libs/gst/helpers/meson.build:
-	  meson: Add PYTHONPATH to load GDB helper module
-	  Meson generates a gdbinit file that will automatically load gstreamer
-	  script. However that script uses a helper python module that needs
-	  PYTHONPATH to be pointing into the right location in the source
-	  tree to be able to find gst_gdb.py.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1796>
+	* tools/gst-inspect.c:
+	* tools/gst-launch.c:
+	* tools/gst-stats.c:
+	* tools/gst-typefind.c:
+	  tools: Make sure UTF-8 encoded command line arguments on Windows
+	  On Windows, arguments passed in main() are system codepage
+	  encoded and might not be valid UTF-8 string.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3828>
 
-2022-04-20 09:38:16 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+2023-02-03 04:02:26 +0900  Seungha Yang <seungha@centricular.com>
 
-	* plugins/tracers/gstleaks.c:
-	  gstleaks: log the number of alive objects
-	  Can help checking if the number of alive objects is growing over time or stays stable.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2245>
+	* gst/gstpluginloader-win32.c:
+	  pluginloader-win32: Prepend gstreamer-1.0-0.dll directory to PATH env for child process
+	  Usually gst-plugin-scanner.exe will be located under libexec/gstreamer-1.0
+	  or even somewhere user specified location via GST_PLUGIN_SCANNER
+	  environment. So, in order for child process to be able to load
+	  GStreamer DLLs, parent process will need to update PATH env
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3886>
 
-2022-04-19 14:05:16 +0300  Sebastian Dröge <sebastian@centricular.com>
+2022-11-26 02:49:33 +1100  Jan Schmidt <jan@centricular.com>
 
-	* gst/gstbuffer.h:
-	  gstreamer: Document various caps for the reference timestamp meta
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2132>
+	* gst/gsturi.c:
+	* gst/gsturi.h:
+	* tests/check/gst/gsturi.c:
+	  gsturi: Add API to order query strings
+	  Add gst_uri_get_query_string_ordered() and gst_uri_to_string_with_keys() that
+	  allow constructing the URI string with query arguments in a specific order.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3803>
 
-2022-03-25 10:18:34 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+2022-10-03 15:09:31 -0300  Thibault Saunier <tsaunier@igalia.com>
 
-	* docs/random/i18n:
-	  Always define ENABLE_NLS
-	  GLib guarantees libintl API is always available, provided by
-	  proxy-libintl as last resort. GLib itself unconditionally define
-	  ENABLE_NLS.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2028>
+	* gst/gstutils.c:
+	* gst/gstutils.h:
+	  gstutils: Add a utility to create a stream-id without a pad
+	  We already have functions to generate a stream-id from pads but in the
+	  end those pads are not even used in most cases. This adds functions to
+	  generate a stream-id even before creating the source pads for the
+	  element that is going to use it. For example a demuxer that is properly
+	  implements the GstStream/GstStreamCollection API will not have a Pad but
+	  already needs to generate a stream-id.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3160>
 
-2022-03-25 10:20:24 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+2023-02-02 00:25:53 +0900  Seungha Yang <seungha@centricular.com>
 
-	* docs/meson.build:
-	* gst/gettext.h:
-	* gst/gst-i18n-app.h:
-	* gst/gst-i18n-lib.h:
-	  Delete unused i18n headers
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2028>
+	* gst/gstpluginloader-win32.c:
+	  pluginloader-win32: Watch child process handle on connection
+	  ... so that parent can avoid waiting if child process got terminated
+	  unexpectedly
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3863>
 
-2022-03-25 09:59:23 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+2023-02-02 00:19:55 +0900  Seungha Yang <seungha@centricular.com>
 
-	* docs/gst-hotdoc-plugins-scanner.c:
-	* gst/gst.c:
-	* gst/gstelement.c:
-	* gst/gsterror.c:
-	* gst/gstpipeline.c:
-	* gst/gstregistry.c:
-	* gst/gsttaglist.c:
-	* gst/gsturi.c:
-	* gst/gstutils.c:
-	* gst/parse/grammar.y.in:
-	* libs/gst/base/gstbasesink.c:
-	* libs/gst/base/gstbasesrc.c:
-	* libs/gst/base/gstbasetransform.c:
-	* plugins/elements/gstcapsfilter.c:
-	* plugins/elements/gstdownloadbuffer.c:
-	* plugins/elements/gstfdsink.c:
-	* plugins/elements/gstfilesink.c:
-	* plugins/elements/gstfilesrc.c:
-	* plugins/elements/gstidentity.c:
-	* plugins/elements/gstqueue.c:
-	* plugins/elements/gstqueue2.c:
-	* plugins/elements/gsttypefindelement.c:
-	* tools/tools.h:
-	  Replace gst-i18n-*.h with gi18n-lib.h
-	  GLib guarantees libintl is always present, using proxy-libintl as
-	  last resort. There is no need to mock gettex API any more.
-	  This fix static build on Windows because G_INTL_STATIC_COMPILATION must
-	  be defined before including libintl.h, and glib does it for us as part
-	  as including glib.h.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2028>
+	* gst/gstpluginloader-win32.c:
+	  pluginloader-win32: Check pipe state in child process
+	  Retry if server is not ready for the connection
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3863>
 
-2022-04-18 15:44:47 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+2023-02-01 23:14:17 +0900  Seungha Yang <seungha@centricular.com>
 
-	* gst/meson.build:
-	* meson.build:
-	  meson: Add -Wl,-rpath,${libdir} on macOS
-	  We made the gstreamer installation prefix relocatable by picking up
-	  plugins relative to the location of libgstreamer-1.0.dylib, similar to
-	  how it's done for Windows:
-	  https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1627
-	  This had a lot of side-effects:
-	  https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1051
-	  https://gitlab.freedesktop.org/gstreamer/cerbero/-/issues/363
-	  https://gitlab.freedesktop.org/gstreamer/cerbero/-/issues/371
-	  https://gitlab.freedesktop.org/gstreamer/cerbero/-/issues/362
-	  A partial fix for the cerbero side of these was:
-	  https://gitlab.freedesktop.org/gstreamer/cerbero/-/merge_requests/807
-	  However, this relied on the consumers knowing that they need to add
-	  `LC_RPATH` entries to the libdir of the prefix. This is done
-	  automatically by build systems like Meson, but not by others, such as
-	  Autotools, CMake, Cargo, XCode, etc. For those, we need to add the
-	  RPATH entries to the gstreamer-1.0.pc file.
-	  This also has the side-effect of fixing the loading of gstreamer rust
-	  plugins on macOS:
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1159
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1149
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2218>
-
-2021-11-12 20:13:10 +0100  Ruben Gonzalez <rgonzalez@fluendo.com>
+	* gst/gstpluginloader-win32.c:
+	  pluginloader-win32: Enhance debug log
+	  Change log level to ERROR if it's unexpected, and print error reasons
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3863>
 
-	* gst/gstplugin.c:
-	  gst_plugin_load_file: force plugin reload if diff filename
-	  If a file includes a new version of a plugin that exits in the
-	  registry, the output of gst-inspect is incorrect. The output has the
-	  correct version but incorrect filename, and element description.
-	  This seems to have also fixed some documentation issues.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1344>
+2023-02-01 23:08:03 +0900  Seungha Yang <seungha@centricular.com>
 
-2020-05-29 11:29:56 -0300  Tulio Beloqui <tulio.beloqui@pexip.com>
+	* gst/gstpluginloader-win32.c:
+	  pluginloader-win32: Zero initialize overlapped struct before use
+	  Helper child process might be spawned multiple times for some reason
+	  then overlapped struct can hold garbage data. Always clear the struct.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3863>
 
-	* gst/gstdevicemonitor.c:
-	  gstdevicemonitor: added cleanup of signal handlers and hidden providers list
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2182>
+2022-04-18 16:33:40 +0000  Thibault Saunier <tsaunier@igalia.com>
 
-2022-04-15 17:00:24 +0200  Guillaume Desmottes <guillaume.desmottes@onestream.live>
+	* docs/plugins/gst_plugins_cache.json:
+	* plugins/elements/gstclocksync.c:
+	* plugins/elements/gstclocksync.h:
+	  clocksync: Add "QoS" support
+	  When ClockSync synchronizes the data stream on the clock, it should also
+	  push `QoS` events if the user wants to do it as, as stated in [the QoS
+	  design doc] "Elements that synchronize buffers on the pipeline clock
+	  will usually measure the current QoS".
+	  The logic has been replicated from `GstBaseSink`.
+	  [the QoS design doc]: https://gstreamer.freedesktop.org/documentation/plugin-development/advanced/qos.html
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2225>
+
+2023-01-27 19:29:24 +0100  Mathieu Duponchelle <mathieu@centricular.com>
+
+	* libs/gst/base/gstbasesrc.h:
+	  BaseSrc: fix transfer annotation for fixate virtual method
+	  The fixate virtual method has the same semantics as gst_caps_fixate(),
+	  so the caps parameter must be marked as (transfer full).
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3830>
+
+2023-01-26 15:42:18 +0100  Mathieu Duponchelle <mathieu@centricular.com>
+
+	* libs/gst/base/gstbasesrc.h:
+	* libs/gst/base/gstpushsrc.h:
+	  BaseSrc, PushSrc: add nullable annotations to virtual methods
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3806>
+
+2023-01-26 10:33:26 +0100  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
 
-	* plugins/tracers/gstleaks.c:
-	  gstleaks: fix pthread_atfork return value check
-	  pthread_atfork() returns 0 on success.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2195>
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: Warn about the right segment's format
+	  We were checking the head segment here, not the current segment.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/611>
 
-2022-04-13 16:59:50 +0300  Sebastian Dröge <sebastian@centricular.com>
+2020-09-02 17:59:30 +0200  Jan Alexander Steffens (heftig) <jan.steffens@ltnglobal.com>
 
-	* libs/gst/net/gstptpclock.c:
-	  ptpclock: Fix wrong condition order from last commit
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2171>
+	* libs/gst/base/gstaggregator.c:
+	  aggregator: Always lock aggpad around update_time_level
+	  `aggpad->segment` is protected by the `aggpad`'s object lock. We need to
+	  take the lock before calling `update_time_level`.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/611>
 
-2022-04-12 19:22:51 +0300  Sebastian Dröge <sebastian@centricular.com>
+2022-12-20 10:01:12 -0800  Daniel Ulery <dan.ulery@gmail.com>
 
-	* libs/gst/net/gstptpclock.c:
-	  ptpclock: Allow at least 100ms delay between Sync/Follow_Up and Delay_Req/Delay_Resp messages
-	  It doesn't matter for measurement purposes whether receiving them takes
-	  a while and various PTP servers are not prioritizing to send them,
-	  causing them to be dropped unnecessarily and preventing proper
-	  synchronization with such servers.
-	  This is especially a problem if the RTTs in the network are very low
-	  compared to the additional delay imposed by the server.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2161>
+	* docs/plugins/gst_plugins_cache.json:
+	* plugins/elements/gstfilesink.c:
+	* plugins/elements/gstfilesink.h:
+	  filesink: Adds rb+ file mode
+	  Adds rb+ file mode to filesink so that files can be pre-allocated. This
+	  can be use to keep reduce fragmentation over time with splitmuxsink.
+	  Fixes  #955
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1532>
 
-2022-04-12 01:01:23 +0900  Seungha Yang <seungha@centricular.com>
+2022-12-02 23:48:45 +0900  Seungha Yang <seungha@centricular.com>
 
-	* tools/gst-launch.c:
-	* tools/meson.build:
-	  win32: Enable high-resolution timer for MinGW build
-	  timeapi.h is missing in our MinGW toolchain. Include mmsystem.h
-	  header instead, which defines struct and APIs in case of our MinGW
-	  toolchain. Note that in case of native Windows10 SDK (MSVC build),
-	  mmsystem.h will include timeapi.h
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2153>
+	* gst/gst_private.h:
+	* gst/gstpluginloader-win32.c:
+	* gst/gstpluginloader.c:
+	* gst/gstregistry.c:
+	* gst/meson.build:
+	* libs/gst/helpers/gst-plugin-scanner.c:
+	  gst-plugin-scanner: Add support for Windows
+	  Adding Win32 specific plugin loader implementation.
+	  Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/11
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3512>
 
-2022-04-08 13:44:53 +1000  Matthew Waters <matthew@centricular.com>
+2023-01-25 13:26:08 +0200  Sebastian Dröge <sebastian@centricular.com>
 
-	* gst/gst.c:
-	  gst: remove custom logger for critical/warnings/fatals
-	  It's not really needed anymore (only calls out to
-	  g_log_default_handler() and interferes with applications using
-	  g_log_set_default_handler().
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2135>
+	* gst/gsttypefind.c:
+	  gst: Fix gst_type_find_peek() return value annotation
+	  It's not possible to annotate a in-parameter for a return value array as
+	  the array length. Both are assumed to have the same direction and the
+	  current annotation causes the size parameter to be considered an out
+	  parameter.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3787>
 
-2022-04-01 21:47:59 +0800  Haihua Hu <jared.hu@nxp.com>
+2023-01-23 17:26:07 +0100  Edward Hervey <edward@centricular.com>
 
-	* tools/gst-launch.c:
-	  ximagesink/xvimagesink: use GST_XINITTHREADS to ensure call to XInitThreads
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2098>
+	* plugins/elements/gstmultiqueue.c:
+	  multiqueue: Handle use-interleave latency live pipelines
+	  Due to the dynamic nature of multiqueue, when `use-interleave` is used we can't
+	  report a maximum tolerated latency (when queried) since it is calculated
+	  dynamically.
+	  When in such live pipelines, we need to make sure multiqueue can handle the
+	  lowest global latency (provided by this event). Failure to do that would
+	  result in not providing enough buffering for a realtime pipeline.
+	  Fixes #1732
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3772>
+
+2023-01-24 09:24:03 -0300  Thibault Saunier <tsaunier@igalia.com>
 
-2022-04-02 00:16:29 +1100  Jan Schmidt <jan@centricular.com>
+	* gst/gstelementfactory.c:
+	* gst/gstelementfactory.h:
+	  factory: Add "Timestamper" as new factory type
+	  This will be used by elements that correct timestamps (like the
+	  h264timestamper for example)
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3779>
 
-	* libs/gst/base/gstaggregator.c:
-	  aggregator: Improve debugging of arriving buffers
-	  Log some details about the buffers that are arriving and
-	  being enqueued on each sink pad.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2096>
+2023-01-08 02:02:53 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-04-02 00:46:21 +1100  Jan Schmidt <jan@centricular.com>
+	* libs/gst/base/gstbitwriter.c:
+	  base: bitwriter: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* gst/gstpad.c:
-	  gstreamer: Remove GST_DATAFLOW debug category
-	  Nothing has logged anything to this category since event and
-	  buffer dataflow was de-unified in 2005.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2097>
+2023-01-08 01:32:50 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-03-30 11:06:02 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+	* plugins/elements/gstinputselector.c:
+	  inputselector: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* meson.build:
-	  Use gmodule-no-export-2.0
-	  We don't need `-Wl,--export-dynamic`, that's used only for executables
-	  that needs to export an API to be used by plugins they load.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2031>
+2023-01-08 01:32:32 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-03-25 15:00:20 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+	* plugins/elements/gstmultiqueue.c:
+	  multiqueue: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* docs/meson.build:
-	* libs/gst/base/meson.build:
-	* libs/gst/check/meson.build:
-	* libs/gst/controller/meson.build:
-	* libs/gst/helpers/meson.build:
-	* meson.build:
-	* plugins/elements/meson.build:
-	* tests/benchmarks/meson.build:
-	* tests/check/meson.build:
-	* tests/examples/adapter/meson.build:
-	* tests/examples/controller/meson.build:
-	* tests/examples/helloworld/meson.build:
-	* tests/examples/memory/meson.build:
-	* tests/examples/netclock/meson.build:
-	* tests/examples/ptp/meson.build:
-	* tests/examples/stepping/meson.build:
-	* tests/examples/streamiddemux/meson.build:
-	* tests/examples/streams/meson.build:
-	  Remove glib and gobject dependencies everywhere
-	  They are part of gst_dep already and we have to make sure to always have
-	  gst_dep. The order in dependencies matters, because it is also the order
-	  in which Meson will set -I args. We want gstreamer's config.h to take
-	  precedence over glib's private config.h when it's a subproject.
-	  While at it, remove useless fallback args for gmodule/gio dependencies,
-	  only gstreamer core needs it.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2031>
-
-2022-03-24 14:15:00 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+2023-01-08 01:32:13 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* meson.build:
-	  Fix cross build with mingw32
-	  At least on Ubuntu 20.04 the x86_64-w64-mingw32-gcc toolchain defaults
-	  to WinXP. We require at least Vista for FILE_STANDARD_INFO.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2022>
+	* plugins/elements/gstqueue2.c:
+	* plugins/elements/gstsparsefile.c:
+	  queue2: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2020-09-04 20:52:47 -0400  Xavier Claessens <xavier.claessens@collabora.com>
+2023-01-08 01:31:21 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* data/android/GStreamer.java:
-	* data/meson.build:
-	* gst/gstandroid.c:
-	* gst/meson.build:
-	  Android: Implement JNI_OnLoad()
-	  When building for Android, chances are that gstreamer is going to be
-	  loaded from Java using System.loadLibrary(). In that case we can
-	  initialize GStreamer (including static plugins), redirect log functions,
-	  etc.
-	  This code is copied from cerbero because it can be used with
-	  gstreamer-full-1.0 too. Cerbero needs to be adapted to drop that code
-	  and generate gst_init_static_plugins() function.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/617>
-
-2021-09-11 12:17:56 -0300  Thibault Saunier <tsaunier@igalia.com>
+	* plugins/tracers/gstrusage.c:
+	* plugins/tracers/gststats.c:
+	* tools/gst-stats.c:
+	  tracers: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* meson.build:
-	* tools/meson.build:
-	  tools: Add support for building gstreamer tools against gst-full
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1581>
+2023-01-08 01:30:36 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-03-30 10:01:33 +0200  Edward Hervey <edward@centricular.com>
+	* libs/gst/base/gstbitreader.c:
+	* libs/gst/base/gstbytereader.c:
+	* libs/gst/base/gstbytewriter.c:
+	* libs/gst/base/gstflowcombiner.c:
+	* libs/gst/base/gstqueuearray.c:
+	* libs/gst/base/gsttypefindhelper.c:
+	  libs: base: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* gst/gstquark.c:
-	* gst/gstquark.h:
-	* gst/gstquery.c:
-	* gst/gstquery.h:
-	  query: Add a new stream selection query
-	  This new API allows querying whether elements can handle stream selection
-	  themselves or not.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1905>
+2023-01-08 01:30:20 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-03-18 13:42:27 +0530  Nirbheek Chauhan <nirbheek@centricular.com>
+	* gst/parse/grammar.y.in:
+	* libs/gst/base/gstbaseparse.c:
+	* libs/gst/base/gstindex.c:
+	* libs/gst/base/gstmemindex.c:
+	  baseparse: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* meson.build:
-	  meson: Bump all meson requirements to 0.60
-	  Lots of new warnings ever since
-	  https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1934
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1977>
+2023-01-08 01:28:43 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-01-05 19:33:06 +0100  Vivienne Watermeier <vwatermeier@igalia.com>
+	* libs/gst/check/gstcheck.c:
+	* libs/gst/check/gstharness.c:
+	* libs/gst/check/gsttestclock.c:
+	  gstcheck: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* libs/gst/base/gstaggregator.c:
-	  compositor: send translated navigation events to the relevant sink pads
-	  Fixes #888
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1495>
+2023-01-08 01:27:54 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-02-23 17:39:18 +0100  Vivienne Watermeier <vwatermeier@igalia.com>
+	* libs/gst/controller/gsttimedvaluecontrolsource.c:
+	  controller: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* gst/gstevent.c:
-	* gst/gstmessage.c:
-	  documentation: improve misleading wording
-	  The documentation for several gst_*_writable_structure functions stated
-	  that they would never return NULL, without making clear that the passed
-	  object is required to be writable. This changes the wording in those
-	  cases to make that requirement more clear.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1784>
+2023-01-08 00:57:25 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-03-10 18:22:49 +0000  Philippe Normand <philn@igalia.com>
+	* gst/gsttracerutils.c:
+	  tracerutils: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* gst/gsturi.c:
-	  uri: Build doubly-linked list by prepending items
-	  As outlined in the API documentation, g_list_append() iterates over the whole
-	  list, which can quickly introduce performance issues when the list becomes very
-	  big, such as for data URIs for instance.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1909>
+2023-01-08 00:57:01 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-03-08 12:04:41 +0000  Philippe Normand <philn@igalia.com>
+	* gst/gsttaskpool.c:
+	  taskpool: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* plugins/elements/gsttypefindelement.c:
-	  typefind: Skip parsing of data URIs
-	  Commit a46ab2ced20d757e0e770d4de1edc3a152cc4f2f introduced a regression,
-	  breaking typefinding for media content muxed in mp4 container and serialized to
-	  data URIs. For this case it doesn't make sense to look for a file extension, so
-	  skip URI parsing.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1909>
+2023-01-08 00:56:41 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-03-15 14:00:06 +0100  Corentin Noël <tintou@noel.tf>
+	* gst/gstsegment.c:
+	  segment: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* libs/gst/base/gstbasesink.h:
-	  basesink: Fix annotations
-	  We should annotate the Class and not the object itself.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1965>
+2023-01-08 00:56:23 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-03-11 18:08:14 -0500  Xavier Claessens <xavier.claessens@collabora.com>
+	* gst/gstsample.c:
+	  sample: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* data/bash-completion/helpers/meson.build:
-	* data/meson.build:
-	* libs/gst/helpers/meson.build:
-	  Meson: Set install_tag on some files
-	  Meson tries to guess the tag (runtime, devel, etc) for every installed
-	  file, but it cannot guess them all. There is a list at the end of
-	  meson-log.txt of files we need to tag manually.
-	  See https://mesonbuild.com/Installing.html#installation-tags.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1934>
+2023-01-08 00:55:27 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-03-02 17:07:37 +0100  Edward Hervey <edward@centricular.com>
+	* gst/gstquery.c:
+	  query: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* plugins/elements/gstmultiqueue.c:
-	  multiqueue: Fix interleave calculation for data before segment start
-	  This commit modifies the interleave calculation to allow growing when incoming
-	  data is before the segment start.
-	  The rationale is that there is no requirement whatsoever for data before the
-	  segment start to be "coherent" on all streams.
-	  For example, a demuxer could rightfully send data from the video stream from the
-	  previous keyframe (potentially quite a bit before the segment start) and the
-	  audio from just before the segment start.
-	  This will activate the same logic as growing the interleave when some streams
-	  haven't received buffers yet.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1892>
-
-2021-08-06 08:30:39 +0200  Edward Hervey <edward@centricular.com>
+2023-01-08 00:55:04 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* plugins/elements/gstmultiqueue.c:
-	* plugins/elements/gstmultiqueue.h:
-	  multiqueue: Improve interleave calculation at startup and EOS
-	  * When a stream receives EOS, it will no longer change, we shouldn't take that
-	  stream into account for interleave calculation.
-	  * When streams (re)appear, we do not want to grow the initial interleave values
-	  to excessive values. Instead of setting it to a default of 5s, progressively
-	  grow it to that maximum.
-	  * When the status of input streams change (i.e. going to/from "some haven't
-	  received data yet" and "all have received data"), update the interleave
-	  immediately instead of waiting for (potentially) 5s of data before updating
-	  it.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1892>
-
-2021-12-20 17:31:17 +0100  sergei.kovalev <sergei@pexip.com>
+	* gst/gstiterator.c:
+	  iterator: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* tests/check/gstreamer.supp:
-	  check: Fix valgrind suppression for debug function list
-	  Fix suppression to support release and debug builds.
-	  Here is the debug build call stack:
-	  ```
-	  ==10707==    by 0x48B5520: g_malloc (gmem.c:106)
-	  ==10707==    by 0x48D19DC: g_slice_alloc (gslice.c:1069)
-	  ==10707==    by 0x48D3947: g_slist_copy_deep (gslist.c:619)
-	  ==10707==    by 0x48D38B8: g_slist_copy (gslist.c:567)
-	  ==10707==    by 0x4ADC90B: gst_debug_remove_with_compare_func (gstinfo.c:1504)
-	  ```
-	  In release build `g_slist_copy (gslist.c:567)` got inlined:
-	  ```
-	  ==15419==    by 0x48963E0: g_malloc (gmem.c:106)
-	  ==15419==    by 0x48AA382: g_slice_alloc (gslice.c:1069)
-	  ==15419==    by 0x48AB732: g_slist_copy_deep (gslist.c:619)
-	  ==15419==    by 0x4A39B8F: gst_debug_remove_with_compare_func (gstinfo.c:1504)
-	  ```
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1814>
+2023-01-08 00:54:41 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-2022-02-21 10:49:15 +0100  Sebastian Fricke <sebastian.fricke@collabora.com>
+	* gst/gstevent.c:
+	  event: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* docs/gst/running.md:
-	* docs/index.md:
-	* gst/gstregistry.c:
-	  Remove the uninstalled term
-	  Remove the symbolic link `gst-uninstalled` which points to `gst-env`.
-	  The `uninstalled` is the old name and the project should stick to a
-	  single name for the procedure.
-	  Remove the term from all the files, exceptions are variables from
-	  dependencies like `uninstalled_variables` from pkgconfig and
-	  `meson-uninstalled`.
-	  Adjust mentions of the script in the documentation and README.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1743>
-
-2022-02-23 11:10:11 +0100  Sebastian Fricke <sebastian.fricke@collabora.com>
+2023-01-08 00:54:03 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* README.md:
-	  Maintain build instructions at a single location
-	  Do not maintain similar build instructions within each gst-plugins-*
-	  subproject and the subproject/gstreamer subproject. Use the build
-	  instructions from the mono-repository and link to them via hyperlink.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1743>
+	* gst/gstinfo.c:
+	  info: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-23 10:13:54 +0200  Sebastian Dröge <sebastian@centricular.com>
+2023-01-08 00:49:19 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstbuffer.h:
-	  buffer: Clarify that the MARKER flag maps to the corresponding RTP header flag
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1776>
+	* gst/gstdevicemonitor.c:
+	  devicemonitor: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-27 13:17:40 +0200  Sebastian Dröge <sebastian@centricular.com>
+2023-01-08 00:49:00 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstregistry.c:
-	  registry: Fix multi-line `#warning` compiler warning
-	  subprojects/gstreamer/gst/gstregistry.c:1593: unexpected character `"'
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1802>
+	* gst/gstdatetime.c:
+	  datetime: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-21 11:37:26 -0500  Xavier Claessens <xavier.claessens@collabora.com>
+2023-01-08 00:48:46 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* libs/gst/helpers/meson.build:
-	  devenv: Add some missing GStreamer specific env variables
-	  This should make "meson devenv" closer to what "gst-env.py" sets.
-	  - GST_VALIDATE_SCENARIOS_PATH
-	  - GST_VALIDATE_APPS_DIR
-	  - GST_OMX_CONFIG_DIR
-	  - GST_ENCODING_TARGET_PATH
-	  - GST_PRESET_PATH
-	  - GST_PLUGIN_SCANNER
-	  - GST_PTP_HELPER
-	  - _GI_OVERRIDES_PATH
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1768>
-
-2021-11-03 17:05:07 +1100  Matthew Waters <matthew@centricular.com>
+	* gst/gstclock.c:
+	  clockentry: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-	* libs/gst/check/gsttestclock.c:
-	  tests/clock: avoid a race cranking
-	  Scenario:
-	  - Source 1 requesting and waiting a clock id
-	  - Source 2 requesting and waiting on a clock id
-	  - Test attempting to crank both sources in the same GstHarness
-	  gst_test_clock_crank() originally dropped locks between the retrieving
-	  of the next clock id and advancing to the next clock id.  This would
-	  mean that both sources would race each other attempting to complete
-	  their clock waits.  Sometimes the operations would be performed in the
-	  correct order, other times they would not and a FALSE return value would
-	  be produced.
-	  This would lead to an assertion in gst_harness_push_from_src() expecting
-	  that all clock cranks to succeed.
-	  Fix by ensuring that the clock wait produced is dealt with before
-	  processing the next by not dropping the relevant locks after retrieving
-	  the next clock id.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1299>
-
-2021-11-02 15:58:49 -0400  Nicolas Dufresne <nicolas.dufresne@collabora.com>
-
-	  doc: Fix doc comment for GstChildProxy
-	  This removes warning like:
-	  ../subprojects/gstreamer/gst/gstchildproxy.h:57: Error: Gst: identifier not found on the first line:
-	  * #GstChildProxyInterface::get_child_by_name:
-	  ^
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1297>
-
-2022-02-06 22:54:42 +0900  Seungha Yang <seungha@centricular.com>
+2023-01-08 00:48:07 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstinfo.c:
-	* libs/gst/check/libcheck/libcompat/libcompat.h:
-	* libs/gst/net/gstptpclock.c:
-	  gstinfo,ptpclock,libcheck: Use GetCurrentProcessId() instead of getpid() on Windows
-	  getpid() shouldn't be used in case of UWP. Use GetCurrentProcessId()
-	  instead which provides exactly the same functionality and can be
-	  used with UWP as well.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1006>
+	* gst/gstcontext.c:
+	  context: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-07 02:49:15 +0900  Seungha Yang <seungha@centricular.com>
+2023-01-08 00:47:38 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* meson.build:
-	* tests/check/elements/fdsrc.c:
-	* tests/check/gst/gstpoll.c:
-	  check: Disable some tests if pipe() is unavailable for UWP build
-	  pipe() and _pipe() are not allowed on UWP
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1006>
+	* gst/gsturi.c:
+	  uri: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2021-10-01 20:27:28 +0900  Seungha Yang <seungha@centricular.com>
+2023-01-08 00:46:42 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* meson.build:
-	* tests/check/gst/gstmeta.c:
-	* tests/check/gst/gstpoll.c:
-	* tools/gst-inspect.c:
-	  meson: Do hard build error for some MSVC warnings
-	  Handle various MSVC warnings as errors for development version.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1006>
+	* gst/gstformat.c:
+	* gst/gstmeta.c:
+	  meta: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-08 23:30:00 +0900  Seungha Yang <seungha@centricular.com>
+2023-01-08 00:41:38 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* libs/gst/check/libcheck/libcompat/libcompat.h:
-	  Remove some trailing white spaces
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1006>
+	* gst/gstmessage.c:
+	  message: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-01-31 13:01:10 +0100  Vivienne Watermeier <vwatermeier@igalia.com>
+2023-01-08 00:19:23 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstevent.c:
-	  navigation: add more constructors for navigation events
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1610>
+	* gst/gstvalue.c:
+	  gstvalue: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-08 12:58:52 +1100  Matthew Waters <matthew@centricular.com>
+2023-01-07 19:43:02 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstregistry.c:
-	  registry: enable relocatable builds for anywhere with dladdr()
-	  Such as Linux/BSD's.
-	  Matches the Windows/macOS behaviour.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1662>
+	* gst/gstcaps.c:
+	* gst/gstcapsfeatures.c:
+	  caps, capsfeatures: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2021-12-08 22:13:15 +0000  Jose Quaresma <quaresma.jose@gmail.com>
+2023-01-07 19:42:29 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstpluginloader.c:
-	  gstpluginloader: show the reason when spawning of gst-plugin-scanner fail
-	  This fix helps in cross compiling when the meson tests runs using a qemu wraper
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1578>
+	* gst/gstbus.c:
+	* gst/gstpoll.c:
+	  bus, poll: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2021-10-22 18:40:07 -0300  Martin Reboredo <yakoyoku@gmail.com>
+2023-01-07 19:41:31 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstvalue.c:
-	  gstvalue: De/Serialization of GBytes
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1232>
+	* gst/gstbin.c:
+	  bin: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-08 16:24:13 +1100  Sebastian Mueller <sebastian.mueller@nirovision.com>
+2023-01-07 19:40:42 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstcontext.c:
-	  context: fix transfer annotation
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1663>
+	* gst/gsttaglist.c:
+	* gst/gsttagsetter.c:
+	  taglist, tagsetter: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2020-02-17 21:50:54 -0600  Zebediah Figura <zfigura@codeweavers.com>
+2023-01-07 19:40:16 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* libs/gst/base/gstbaseparse.c:
-	* tests/check/libs/baseparse.c:
-	  baseparse: Don't truncate the duration to milliseconds in gst_base_parse_convert_default().
-	  There's no need to do this, and it can make seeking far less accurate.
-	  For a specific use case: I am working with a long (45-minute) MPEG-1 layer 3 file, which has a constant bit rate but no seeking tables. Trying to seek the pipeline immediately after pausing it, without the ACCURATE flag, to a location 41 minutes in, yields a location that is potentially over ten seconds ahead of where it should be. This patch improves that drastically.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/374>
+	* gst/gsttoc.c:
+	* gst/gsttocsetter.c:
+	  toc, tocsetter: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-07 19:33:31 -0600  Zebediah Figura <zfigura@codeweavers.com>
+2023-01-07 19:37:52 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* libs/gst/base/gstbaseparse.c:
-	  baseparse: Trace time with GST_TIME_FORAMT in gst_base_parse_convert_default().
-	  Be consistent with how we trace time in general.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/374>
+	* gst/gstallocator.c:
+	* gst/gstbuffer.c:
+	* gst/gstbufferlist.c:
+	  allocator, buffer, bufferlist: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-07 09:46:46 +0200  Sebastian Dröge <sebastian@centricular.com>
+2023-01-07 19:27:30 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstbufferpool.c:
-	  bufferpool: Deactivate pool and get rid of references to other objects from dispose instead of finalize
-	  During dispose the pool will still have a reference count of 1 and all
-	  API on it can still be safely called.
-	  Subclasses will have already freed their own data before finalize is
-	  called but would nonetheless be called into again via the pool
-	  deactivation.
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1645>
+	* gst/gstregistrychunks.c:
+	* gst/gstregistrychunks.h:
+	  registrychunks: get rid of internal GST_REGISTRY_CHUNK_FLAG_MALLOC
+	  Not actually needed.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-07 16:51:25 +1100  Matthew Waters <matthew@centricular.com>
+2023-01-07 19:20:41 +0000  Tim-Philipp Müller <tim@centricular.com>
 
+	* gst/gstelementfactory.c:
+	* gst/gstplugin.c:
 	* gst/gstpluginloader.c:
-	* meson.build:
-	  pluginloader: support multiple subdirectories for GST_PLUGIN_SUBDIR (libdir)
-	  i.e. if GST_PLUGIN_SUBDIR is 'some/lib/path', then the default plugin
-	  loading assumed that there was only 'lib' as it only went up a single
-	  directory to then find the plugin scanner.
-	  Fix to support multiple subdirectories for GST_PLUGIN_SUBDIR (libdir).
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/995
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1644>
+	* gst/gstregistrybinary.c:
+	* gst/gstregistrychunks.c:
+	* gst/gstregistrychunks.h:
+	* tests/check/gst/gstelementfactory.c:
+	  registry: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-07 16:36:13 +1100  Matthew Waters <matthew@centricular.com>
+2023-01-06 01:40:08 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstregistry.c:
-	  registry: check the value of dladdr()
-	  info.dli_fname could be NULL.
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/994
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1644>
+	* gst/gstparse.c:
+	* gst/parse/grammar.y.in:
+	* gst/parse/types.h:
+	  gstparse: drop use of GSlice allocator
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-07 16:33:03 +1100  Matthew Waters <matthew@centricular.com>
+2023-01-06 01:37:39 +0000  Tim-Philipp Müller <tim@centricular.com>
 
-	* gst/gstregistry.c:
-	  registry: check the return value of g_win32_get_package_installation_directory_of_module()
-	  g_win32_get_package_installation_directory_of_module() may return NULL
-	  in some circumstances and we need to deal with that.
-	  Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/996
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1644>
+	* tests/examples/memory/my-memory.c:
+	* tests/examples/memory/my-vidmem.c:
+	* tests/examples/streams/testrtpool.c:
+	  core: examples: drop use of GSlice
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
+
+2023-01-04 17:58:13 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tests/check/gst/gstelementfactory.c:
+	* tests/check/gst/gstmemory.c:
+	* tests/check/libs/gsttestclock.c:
+	  core: tests: drop use of GSlice allocator
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
 
-2022-02-04 11:15:47 +0000  Tim-Philipp Müller <tim@centricular.com>
+2023-01-04 17:57:05 +0000  Tim-Philipp Müller <tim@centricular.com>
+
+	* tools/gst-stats.c:
+	  tools: gst-stats: drop use of GSlice allocator
+	  https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/291
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3695>
+
+2019-07-23 17:53:18 +0200  Alicia Boya García <aboya@igalia.com>
+
+	* libs/gst/base/gstaggregator.c:
+	* plugins/elements/gstconcat.c:
+	* plugins/elements/gstfunnel.c:
+	* plugins/elements/gstinputselector.c:
+	  Use automatic pad activation in elements that can take advantage of it
+	  Pads are activated automatically when they are added if the element
+	  state is >=PAUSED, so it's not necessary to activate them manually
+	  anymore.
+	  This patch removes manual pad activation from gstaggregator, gstconcat,
+	  gstfunnel, and gstinputselector.
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3636>
+
+2023-01-23 23:04:53 +0000  Tim-Philipp Müller <tim@centricular.com>
 
 	* meson.build:
 	  Back to development
-	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1635>
+	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3775>
 
-=== release 1.20.0 ===
+=== release 1.22.0 ===
 
diff --git a/NEWS b/NEWS
index 9802493..ddf0da3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,1151 +1,1295 @@
-GStreamer 1.22 Release Notes
-
-GStreamer 1.22.0 was originally released on 23 January 2023.
-
-See https://gstreamer.freedesktop.org/releases/1.22/ for the latest
-version of this document.
-
-Last updated: Monday 23 January 2023, 17:00 UTC (log)
-
-Introduction
-
-The GStreamer team is proud to announce a new major feature release in
-the stable 1.x API series of your favourite cross-platform multimedia
-framework!
-
-As always, this release is again packed with many new features, bug
-fixes and other improvements.
-
-Highlights
-
--   AV1 video codec support improvements
--   New HLS, DASH and Microsoft Smooth Streaming adaptive streaming
-    clients
--   Qt6 support for rendering video inside a QML scene
--   Minimal builds optimised for binary size, including only the
-    individual elements needed
--   Playbin3, Decodebin3, UriDecodebin3, Parsebin enhancements and
-    stabilisation
--   WebRTC simulcast support and support for Google Congestion Control
--   WebRTC-based media server ingestion/egress (WHIP/WHEP) support
--   New easy to use batteries-included WebRTC sender plugin
--   Easy RTP sender timestamp reconstruction for RTP and RTSP
--   ONVIF timed metadata support
--   New fragmented MP4 muxer and non-fragmented MP4 muxer
--   New plugins for Amazon AWS storage and audio transcription services
--   New gtk4paintablesink and gtkwaylandsink renderers
--   New videocolorscale element that can convert and scale in one go for
-    better performance
--   High bit-depth video improvements
--   Touchscreen event support in navigation API
--   Rust plugins now shipped in macOS and Windows/MSVC binary packages
--   H.264/H.265 timestamp correction elements for PTS/DTS reconstruction
-    before muxers
--   Improved design for DMA buffer sharing and modifier handling for
-    hardware-accelerated video decoders/encoders/filters and
-    capturing/rendering on Linux
--   Video4Linux2 hardware accelerated decoder improvements
--   CUDA integration and Direct3D11 integration and plugin improvements
--   New H.264 / AVC, H.265 / HEVC and AV1 hardware-accelerated video
-    encoders for AMD GPUs using the Advanced Media Framework (AMF) SDK
--   applemedia: H.265 / HEVC video encoding + decoding support
--   androidmedia: H.265 / HEVC video encoding support
--   New “force-live” property for audiomixer, compositor, glvideomixer,
-    d3d11compositor etc.
--   Lots of new plugins, features, performance improvements and bug
-    fixes
-
-Major new features and changes
-
-AV1 video codec support improvements
-
-AV1 is a royalty free next-generation video codec by AOMedia and a free
-alternative to H.265/HEVC.
-
-While supported in earlier versions of GStreamer already, this release
-saw a lot of improvements across the board:
-
--   Support for hardware encoding and decoding via VAAPI/VA, AMF, D3D11,
-    NVCODEC, QSV and Intel MediaSDK. Hardware codecs for AV1 are slowly
-    becoming available in embedded systems and desktop GPUs (AMD, Intel,
-    NVIDIA), and these can now be used via GStreamer.
-
--   New AV1 RTP payloader and depayloader elements.
-
--   New encoder settings in the AOM reference encoder-based av1enc
-    element.
-
--   Various improvements in the AV1 parser and in the MP4/Matroska/WebM
-    muxers/demuxers.
-
--   dav1d and rav1e based software decoder/encoder elements shipped as
-    part of the binaries.
-
--   AV1 parser improvements and various bugfixes all over the place.
-
-Touchscreen event support in Navigation API
-
-The Navigation API supports the sending of key press events and mouse
-events through a GStreamer pipeline. Typically these will be picked up
-by a video sink on which these events happen and then the event is
-transmitted into the pipeline so it can be handled by elements inside
-the pipeline if it wasn’t handled by the application.
-
-This has traditionally been used for DVD menu support, but can also be
-used to forward such inputs to source elements that render a web page
-using a browser engine such as WebKit or Chromium.
-
-This API has now gained support for touchscreen events, and this has
-been implemented in various plugins such as the GTK, Qt, XV, and x11
-video sinks as well as the wpevideosrc element.
-
-GStreamer CUDA integration
-
--   New gst-cuda library
--   integration with D3D11 and NVIDIA dGPU NVMM elements
--   new cudaconvertscale element
+GStreamer 1.24 Release Notes
 
-GStreamer Direct3D11 integration
+GStreamer 1.24.0 was originally released on 4 March 2024.
 
--   New gst-d3d11 public library
-    -   gst-d3d11 library is not integrated with GStreamer documentation
-        system yet. Please refer to the examples
--   d3d11screencapture: Add Windows Graphics Capture API based capture
-    mode, including Win32 application window capturing
--   d3d11videosink and d3d11convert can support flip/rotation and crop
-    meta
--   d3d11videosink: New emit-present property and present signal so that
-    applications can overlay an image on Direct3D11 swapchain’s
-    backbuffer via Direct3D/Direct2D APIs. See also C++ and Rust
-    examples
--   d3d11compositor supports YUV blending/composing without intermediate
-    RGB(A) conversion to improve performance
--   Direct3D11 video decoders are promoted to GST_RANK_PRIMARY or
-    higher, except for the MPEG2 decoder
-
-H.264/H.265 timestamp correction elements
-
--   Muxers are often picky and need proper PTS/DTS timestamps set on the
-    input buffers, but that can be a problem if the encoded input media
-    stream comes from a source that doesn’t provide proper signalling of
-    DTS, such as is often the case for RTP, RTSP and WebRTC streams or
-    Matroska container files. Theoretically parsers should be able to
-    fix this up, but it would probably require fairly invasive changes
-    in the parsers, so two new elements h264timestamper and
-    h265timestamper bridge the gap in the meantime and can reconstruct
-    missing PTS/DTS.
+The latest bug-fix release in the stable 1.24 series is 1.24.10 and was released on 06 January 2025.
 
-Easy sender timestamp reconstruction for RTP and RTSP
+See https://gstreamer.freedesktop.org/releases/1.24/ for the latest version of this document.
 
--   it was always possible to reconstruct and retrieve the original RTP
-    sender timestamps in GStreamer, but required a fair bit of
-    understanding of the internal mechanisms and the right property
-    configuration and clock setup.
+Last updated: Tuesday 06 January 2025, 19:30 UTC (log)
 
--   rtspsrc and rtpjitterbuffer gained a new
-    “add-reference-timestamp-meta” property that if set puts the
-    original absolute reconstructed sender timestamps on the output
-    buffers via a meta. This is particularly useful if the sender is
-    synced to an NTP clock or PTP clock. The original sender timestamps
-    are either based on the RTCP NTP times, NTP RTP header extensions
-    (RFC6051) or RFC7273-style clock signalling.
+## Introduction
 
-Qt6 support
+The GStreamer team is proud to announce a new major feature release in the stable 1.x API series of your favourite
+cross-platform multimedia framework!
 
--   new qml6glsink element for Qt6 similar to the existing Qt5 element.
-    Matching source and overlay elements will hopefully follow in the
-    near future.
+As always, this release is again packed with many new features, bug fixes and other improvements.
 
-OpenGL + Video library enhancements
+## Highlights
 
--   Support for new video formats (NV12_4L4, NV12_16L32S, NV12_8L128,
-    NV12_10BE_8L128) and dmabuf import in more formats (Y410, Y212_LE,
-    Y212_BE, Y210, NV21, NV61)
+-   New Discourse forum and Matrix chat space
+-   New Analytics and Machine Learning abstractions and elements
+-   Playbin3 and decodebin3 are now stable and the default in gst-play-1.0, GstPlay/GstPlayer
+-   The va plugin is now preferred over gst-vaapi and has higher ranks
+-   GstMeta serialization/deserialization and other GstMeta improvements
+-   New GstMeta for SMPTE ST-291M HANC/VANC Ancillary Data
+-   New unixfd plugin for efficient 1:N inter-process communication on Linux
+-   cudaipc source and sink for zero-copy CUDA memory sharing between processes
+-   New intersink and intersrc elements for 1:N pipeline decoupling within the same process
+-   Qt5 + Qt6 QML integration improvements including qml6glsrc, qml6glmixer, qml6gloverlay, and qml6d3d11sink elements
+-   DRM Modifier Support for dmabufs on Linux
+-   OpenGL, Vulkan and CUDA integration enhancements
+-   Vulkan H.264 and H.265 video decoders
+-   RTP stack improvements including new RFC7273 modes and more correct header extension handling in depayloaders
+-   WebRTC improvements such as support for ICE consent freshness, and a new webrtcsrc element to complement webrtcsink
+-   WebRTC signallers and webrtcsink implementations for LiveKit and AWS Kinesis Video Streams
+-   WHIP server source and client sink, and a WHEP source
+-   Precision Time Protocol (PTP) clock support for Windows and other additions
+-   Low-Latency HLS (LL-HLS) support and many other HLS and DASH enhancements
+-   New W3C Media Source Extensions library
+-   Countless closed caption handling improvements including new cea608mux and cea608tocea708 elements
+-   Translation support for awstranscriber
+-   Bayer 10/12/14/16-bit depth support
+-   MPEG-TS support for asynchronous KLV demuxing and segment seeking, plus various new muxer features
+-   Capture source and sink for AJA capture and playout cards
+-   SVT-AV1 and VA-API AV1 encoders, stateless AV1 video decoder
+-   New uvcsink element for exporting streams as UVC camera
+-   DirectWrite text rendering plugin for windows
+-   Direct3D12-based video decoding, conversion, composition, and rendering
+-   AMD Advanced Media Framework AV1 + H.265 video encoders with 10-bit and HDR support
+-   AVX/AVX2 support and NEON support on macOS on Apple ARM64 CPUs via new liborc
+-   GStreamer C# bindings have been updated
+-   Rust bindings improvements and many new and improved Rust plugins
+-   Rust plugins now shipped in packages for all major platforms including Android and iOS
+-   Lots of new plugins, features, performance improvements and bug fixes
 
--   Improved support for tiled formats with arbitrary tile dimensions,
-    as needed by certain hardware decoders/encoders
+## Major new features and changes
 
--   glvideomixer: New “crop-left,”crop-right, “crop-top” and
-    “crop-bottom” pad properties for cropping inputs
+### Discourse forum and Matrix chat space
 
--   OpenGL support for gst_video_sample_convert():
+-   The new Discourse forum and Matrix chat space are now our preferred communication channels for support and developer chat.
 
-    -   Used for video snapshotting and thumbnailing, to convert buffers
-        retrieved from appsinks or sink “last-sample” properties in
-        JPG/PNG thumbnails.
-    -   This function can now take samples and buffers backed by GL
-        textures as input and will automatically plug a gldownload
-        element in that case.
-
-High bit-depth support (10, 12, 16 bits per component value) improvements
-
--   compositor can now handle any supported input format and also mix
-    high-bitdepth (10-16 bit) formats (naively)
-
--   videoflip has gained support for higher bit depth formats.
-
--   vp9enc, vp9dec now support 12-bit formats and also 10-bit 4:4:4
-
-WebRTC
-
--   Allow insertion of bandwidth estimation elements e.g. for Google
-    Congestion Control (GCC) support
-
--   Initial support for sending or receiving simulcast streams
-
--   Support for asynchronous host resolution for STUN/TURN servers
-
--   GstWebRTCICE was split into base classes and implementation to make
-    it possible to plug custom ICE implementations
-
--   webrtcsink: batteries-included WebRTC sender (Rust)
-
--   whipsink: WebRTC HTTP ingest (WHIP) to a MediaServer (Rust)
-
--   whepsrc: WebRTC HTTP egress (WHEP) from a MediaServer (Rust)
-
--   Many other improvements and bug fixes
-
-New HLS, DASH and MSS adaptive streaming clients
-
-A new set of “adaptive demuxers” to support HLS, DASH and MSS adaptive
-streaming protocols has been added. They provide improved performance,
-new features and better stream compatibility compared to the previous
-elements. These new elements require a “streams-aware” pipeline such as
-playbin3, uridecodebin3 or urisourcebin.
-
-The previous elements’ design prevented implementing several use-cases
-and fixing long-standing issues. The new elements were re-designed from
-scratch to tackle those:
-
--   Scheduling Only 3 threads are present, regardless of the number of
-    streams selected. One in charge of downloading fragments and
-    manifests, one in charge of outputting parsed data downstream, and
-    one in charge of scheduling. This improves performance, resource
-    usage and latency.
-
--   Better download control The elements now directly control the
-    scheduling and download of manifests and fragments using libsoup
-    directly instead of depending on external elements for downloading.
-
--   Stream selection, only the selected streams are downloaded. This
-    improves bandwith usage. Switching stream is done in such a way to
-    ensure there are no gaps, meaning the new stream will be switched to
-    only once enough data for it has been downloaded.
-
--   Internal parsing, the downloaded streams are parsed internally. This
-    allows the element to fully respect the various specifications and
-    offer accurate buffering, seeking and playback. This is especially
-    important for HLS streams which require parsing for proper
-    positioning of streams.
-
--   Buffering and adaptive rate switching, the new elements handle
-    buffering internally which allows them to have a more accurate
-    visibility of which bandwith variant to switch to.
-
-Playbin3, Decodebin3, UriDecodebin3, Parsebin improvements
-
-The “new” playback elements introduced in 1.18 (playbin3 and its various
-components) have been refactored to allow more use-cases and improve
-performance. They are no longer considered experimental, so applications
-using the legacy playback elements (playbin and (uri)decodebin) can
-migrate to the new components to benefit from these improvements.
-
--   Gapless The “gapless” feature allows files and streams to be
-    fetched, buffered and decoded in order to provide a “gapless”
-    output. This feature has been refactored extensively in the new
-    components:
-    -   A single (uri)decodebin3 (and therefore a single set of
-        decoders) is used. This improves memory and cpu usage, since on
-        identical codecs a single decoder will be used.
-    -   The “next” stream to play will be pre-rolled “just-in-time”
-        thanks to the buffering improvements in urisourcebin (see below)
-    -   This feature is now handled at the uridecodebin3 level.
-        Applications that wish to have a “gapless” stream and process it
-        (instead of just outputting it, for example for transcoding,
-        retransmission, …) can now use uridecodebin3 directly. Note that
-        a streamsynchronizer element is required in that case.
--   Buffering improvements The urisourcebin element is in charge of
-    fetching and (optionally) buffering/downloading the stream. It has
-    been extended and improved:
-    -   When the parse-streams property is used (by default in
-        uridecodebin3 and playbin3), compatible streams will be demuxed
-        and parsed (via parsebin) and buffering will be done on the
-        elementary streams. This provides a more accurate handling of
-        buffering. Previously buffering was done on a best-effort basis
-        and was mostly wrong (i.e. downloading more than needed).
-    -   Applications can use urisourcebin with this property as a
-        convenient way of getting elementary streams from a given URI.
-    -   Elements can handle buffering themselves (such as the new
-        adaptive demuxers) by answering the GST_QUERY_BUFFERING query.
-        In that case urisourcebin will not handle it.
--   Stream Selection Efficient stream selection was previously only
-    possible within decodebin3. The downside is that this meant that
-    upstream elements had to provide all the streams from which to chose
-    from, which is inefficient. With the addition of the
-    GST_QUERY_SELECTABLE query, this can now be handled by elements
-    upstream (i.e. sources)
-    -   Elements that can handle stream selection internally (such as
-        the new adaptive demuxer elements) answer that query, and handle
-        the stream selection events themselves.
-    -   In this case, decodebin3 will always process all streams that
-        are provided to it.
--   Instant URI switching This new feature allows switching URIs
-    “instantly” in playbin3 (and uridecodebin3) without having to change
-    states. This mimics switching channels on a television.
-    -   If compatible, decoders will be re-used, providing lower
-        latency/cpu/memory than by switching states.
-    -   This is enabled by setting the instant-uri property to true,
-        setting the URI to switch to immediately, and then disabling the
-        instant-uri property again afterwards.
--   playbin3, decodebin3, uridecodebin3, parsebin, and urisrc are no
-    longer experimental
-    -   They were originally marked as ‘technology preview’ but have
-        since seen extensive usage in production settings, so are
-        considered ready for general use now.
-
-Fraunhofer AAC audio encoder HE-AAC and AAC-LD profile support
-
--   fdkaacenc:
-    -   Support for encoding to HE-AACv1 and HE-AACv2 profile
-    -   Support for encoding to AAC Low Delay (LD) profile
-    -   Advanced bitrate control options via new “rate-control”,
-        “vbr-preset”, “peak-bitrate”, and “afterburner” properties
-
-RTP rapid synchronization support in the RTP stack (RFC6051)
-
-RTP provides several mechanisms how streams can be synchronized relative
-to each other, and how absolute sender times for RTP packets can be
-obtained. One of these mechanisms is via RTCP, which has the
-disadvantage that the synchronization information is only distributed
-out-of-band and usually some time after the start.
-
-GStreamer’s RTP stack, specifically the rtpbin, rtpsession and
-rtpjitterbuffer elements, now also have support for retrieving and
-sending the same synchronization information in-band via RTP header
-extensions according to RFC6051 (Rapid Synchronisation of RTP Flows).
-Only 64-bit timestamps are supported currently.
-
-This provides per packet synchronization information from the very
-beginning of a stream and allows accurate inter-stream, and (depending
-on setup) inter-device, synchronization at the receiver side.
-
-ONVIF XML Timed Metadata support
-
-The ONVIF standard implemented by various security cameras also
-specifies a format for timed metadata that is transmitted together with
-the audio/video streams, usually over RTSP.
-
-Support for this timed metadata is implemented in the MP4 demuxer now as
-well as the new fragmented MP4 muxer and the new non-fragmented MP4
-muxer from the GStreamer Rust plugins. Additionally, the new onvif
-plugin ‒ which is part of the GStreamer Rust plugins ‒ provides general
-elements for handling the metadata and e.g. overlaying certain parts of
-it over a video stream.
-
-As part of this support for absolute UTC times was also implemented
-according to the requirements of the ONVIF standards in the
-corresponding elements.
-
-MP3 gapless playback support
-
-While MP3 can probably considered a legacy format at this point, a new
-feature was added with this release.
-
-When playing back plain MP3 files, i.e. outside a container format,
-switches between files can now be completely gapless if the required
-metadata is provided inside the file. There is no standardized metadata
-for this, but the LAME MP3 encoder writes metadata that can be parsed by
-the mpegaudioparse element now and forwarded to decoders for ensuring
-removal of padding samples at the front and end of MP3 files.
-
-“force-live” property for audio + video aggregators
-
-This is a quality of life fix for playout and streaming applications
-where it is common to have audio and video mixer elements that should
-operate in live mode from the start and produce output continuously.
-
-Often one would start a pipeline without any inputs hooked up to these
-mixers in the beginning, and up until now there was no way to easily
-force these elements into live mode from the start. One would have to
-add an initial live video or audio test source as dummy input to achieve
-this.
-
-The new “force-live” property makes these audio and video aggregators
-start in live mode without the need for any dummy inputs, which is
-useful for scenarios where inputs are only added after starting the
-pipeline.
-
-This new property should usually be used in connection with the
-“min-upstream-latency” property, i.e. you should always set a non-0
-minimum upstream latency then.
-
-This is now supported in all GstAudioAggregator and GstVideoAggregator
-subclasses such as audiomixer, audiointerleave, compositor,
-glvideomixer, d3d11compositor, etc.
+-   The mailing lists and IRC channel are on their way to being phased out, but Discourse can be used via e-mail as well.
 
-New elements and plugins
+-   For release announcements please subscribe to the News + Announcements category on Discourse, although we will continue to
+    also send announcements to the mailing list for the time being.
 
--   new cudaconvertscale element that can convert and scale in one pass
+### Playbin3, decodebin3 now stable and default
 
--   new gtkwaylandsink element based on gtksink, but similar to
-    waylandsink and uses Wayland APIs directly instead of rendering with
-    Gtk/Cairo primitives. This approach is only compatible with Gtk3,
-    and like gtksink this element only supports Gtk3.
+-   After a year of stability, testing and more improvements, playbin3, and its various components (uridecodebin3, decodebin3
+    and urisourcebin), are now the recommended playback components.
 
--   new h264timestamper and h265timestamper elements to reconstruct
-    missing pts/dts from inputs that might not provide them such as
-    e.g. RTP/RTSP/WebRTC inputs (see above)
+-   Some playback components have now switched to defaulting to playbin3: gst-play-1.0 and the GstPlay / GstPlayer libraries.
+    Application developers are strongly recommended to switch to using those components instead of the legacy playbin and
+    (uri)decodebin.
 
--   mfaacdec, mfmp3dec: Windows MediaFoundation AAC and MP3 decoders
+Improvements in this cycle:
 
--   new msdkav1enc AV1 video encoder element
+-   Better support missing/faulty decoders, attempt to use another one or gracefully un-select the stream.
 
--   new nvcudah264enc, nvcudah265enc, nvd3d11h264enc, and nvd3d11h265enc
-    NVIDIA GPU encoder elements to support zero-copy encoding, via CUDA
-    and Direct3D11 APIs, respectively
+-   Many fixes for more complex gapless and instant-switching scenarios
 
--   new nvautogpuh264enc and nvautogpuh265enc NVIDIA GPU encoder
-    elements: The auto GPU elements will automatically select a target
-    GPU instance in case multiple NVIDIA desktop GPUs are present, also
-    taking into account the input memory. On Windows CUDA or Direct3D11
-    mode will be determined by the elements automatically as well. Those
-    new elements are useful if target GPU and/or API mode (either CUDA
-    or Direct3D11 in case of Windows) is undeterminable from the encoder
-    point of view at the time when pipeline is configured, and therefore
-    lazy target GPU and/or API selection are required in order to avoid
-    unnecessary memory copy operations.
+-   Lower latency for live pipelines
 
--   new nvav1dec AV1 NVIDIA desktop GPU decoder element
+-   Fix for “chained” streams (ex: Ogg, or PMT update in MPEG-TS)
 
--   new qml6glsink element to render video with Qt6
+-   Fixes for hardware-accelerated playback with subtitles (provided the sink can handle offloading composition). This was also
+    partly due to a historical confusion between subtitle “decoders” (which decode the format to text and “parsers” (which only
+    do timing detection and optional seeking).
 
--   qsv: New Intel OneVPL/MediaSDK (a.k.a Intel Quick Sync) based
-    decoder and encoder elements, with gst-d3d11 (on Windows) and gst-va
-    (on Linux) integration
+### GstMeta serialization/deserialization and other GstMeta improvements
 
-    -   Support multi-GPU environment, for example, concurrent video
-        encoding using Intel iGPU and dGPU in a single pipeline
-    -   H.264 / H.265 / VP9 and JPEG decoders
-    -   H.264 / H.265 / VP9 / AV1 / JPEG encoders with dynamic encoding
-        bitrate update
-    -   New plugin does not require external SDK for building on Windows
+-   GstMeta serialization/deserialization allows metas to be transmitted or stored. This is used by the unixfd and cudaipc
+    plugins for inter-process communication (IPC). Implemented so far for GstCustomMeta, GstVideoMeta, GstAudioMeta and
+    GstReferenceTimestampMeta.
 
--   vulkanoverlaycompositor: new vulkan overlay compositor element to
-    overlay upstream GstVideoOverlayCompositonMeta onto the video
-    stream.
+-   Simplified GstCustomMeta registration with gst_meta_register_custom_simple() for the simple case where tags and transform
+    functions are not needed.
 
--   vulkanshaderspv: performs operations with SPIRV shaders in Vulkan
+-   GstMetaClearFunction clears the content of the meta. This will be called by buffer pools when a pooled buffer is returned to
+    the pool.
 
--   win32ipcvideosink, win32ipcvideosrc: new shared memory videosrc/sink
-    elements for Windows
+-   Add gst_meta_info_new() and gst_meta_info_register() to register a GstMeta in two steps for easier extensibility.
 
--   wicjpegdec, wicpngdec: Windows Imaging Component (WIC) based JPEG
-    and PNG decoder elements.
+### New unixfd plugin for efficient 1:N inter-process communication on Linux
 
--   Many exciting new Rust elements, see Rust section below
+-   unixfdsink and unixfdsrc are elements that, inspired by shmsink andn shmsrc, send UNIX file descriptors (e.g. memfd, dmabuf)
+    from one sink to multiple source elements in other processes on Linux.
 
-New element features and additions
+-   The unixfdsink proposes a memfd/shm allocator to upstream elements which allows for example videotestsrc to write directly
+    into memory that can be transfered to other processes without copying.
 
--   audioconvert: Dithering now uses a slightly slower, less biased PRNG
-    which results in better quality output. Also dithering can now be
-    enabled via the new “dithering-threshold” property for target bit
-    depths of more than 20 bits.
+### New GstMeta for SMPTE ST-291M HANC/VANC Ancillary Data
 
--   av1enc: Add “keyframe-max-dist” property for controlling max
-    distance between keyframes, as well as “enc-pass”, “keyframe-mode”,
-    “lag-in-frames” and “usage-profile” properties.
+-   Previously only various specific GstMeta for ancillary data were provided, such as GstVideoCaptionMeta and GstVideoAFDMeta.
+    The new GstAncillaryMeta allows passing arbitrary ancillary data between elements, including custom and non-standard
+    ancillary data. See GstAncillaryMeta for details.
 
--   cccombiner: new “output-padding” property
+-   Add with gst_buffer_add_ancillary_meta() and retrieve with gst_buffer_get_ancillary_meta() or
+    gst_buffer_iterate_ancillary_meta().
 
--   decklink: Add support for 4k DCI, 8k/UHD2 and 8k DCI modes
+-   Supported by the newly added AJA sink and source elements
 
--   dvbsubenc: Support for >SD resolutions is working correctly now.
+### DSD audio support
 
--   fdkaacenc: Add HE-AAC / HE-AACv2 profile support
+-   DSD audio is a non-PCM raw audio format representation and the GstAudio library gained support for this in form of new
+    GstDsdInfo and GstDsdFormat API.
 
--   glvideomixer: New “crop-left,”crop-right, “crop-top” and
-    “crop-bottom” pad properties for cropping inputs
+-   Support for DSD audio has been implemented in alsasink as well as the GstAudioSink and GstAudioRingBuffer base classes, and
+    the gst-libav plugin to enable FFmpeg-based DSD elements and functionality.
 
--   gssink: new ‘content-type’ property. Useful when one wants to upload
-    a video as video/mp4 instead of ’video/quicktime` for example.
+### Analytics and Machine Learning
 
--   jpegparse: Rewritten using the common parser library
+-   A new library, GstAnalytics, has been added. It defines a GstAnalyticsRelationMeta that can efficiently hold a large number
+    of observations from a data analysis process, for example from machine learning. It also contains a matrix of the
+    relationship between those observations.
+
+-   Three types of metadata are already defined in the library: object detection, classification and tracking.
+
+-   A new objectdetectionoverlay element has been merged that draws the bounding boxes and the classes from the object detection
+    and classification metadata types.
+
+-   The onnxinference element has been split into two parts. The first part works with the ONNX Runtime library to do the actual
+    inference, while the second part called ssdobjectdetector interprets the produced tensor. This new element creates
+    GstAnalyticsRelationMeta.
+
+-   The onnxinference element now accepts video frames without transformation if the module declares that it accepts the “Image”
+    type and the format is something that GStreamer knows.
+
+-   In the next release, tensor decoders such as ssdobjectdetector will live outside of the ONNX plugin so they can be used with
+    other machine learning acceleration frameworks.
+
+### Qt5 + Qt6 QML integration improvements
+
+-   The Qt5 qmlglsink, qmlgloverlay, qmlglmixer received support for directly consuming BGRA and YV12 video frames without a
+    prior glcolorconvert.
+
+-   New qml6glsrc, qml6glmixer, and qml6gloverlay elements as Qt6 counterparts to the existing Qt5 elements, also with support
+    for directly consuming BGRA and YV12 video frames without a prior glcolorconvert.
+
+-   qml6d3d11sink is a new Direct3D11 Qt6 QML sink for Windows as an alternative to the existing qml6glsink.
+
+### DRM Modifier Support for dmabufs on Linux
+
+The Linux dmabuf subsystem provides buffer sharing across different hardware device drivers and subsystems, and is used
+extensively by the DRM subsystem to exchange buffers between processes, contexts, and library APIs within the same process, and
+also to exchange buffers with other subsystems such as Linux Media.
+
+In GStreamer, it’s used on the capture side (v4l2src, pipewire), hardware-accelerated video decoders and encoders, OpenGL
+integration, Wayland renderers, etc.
+
+GStreamer has had support for dmabufs for a long time and was able to negotiate “zero-copy” paths between different components,
+however it only supported and assumed simple linear formats and was not able to negotiate complex non-linear formats. This meant
+that dmabuf support actually had to be disabled in many scenarios to avoid “garbled video”.
+
+With GStreamer 1.24 there is now full DRM modifier support and complex non-linear formats can be supported and negotiated
+between components.
+
+This is achieved with an extra drm_format field in video/x-raw(memory:DMABuf), format=(string)DMA_DRM caps, e.g.
+drm-format=(string)NV12:0x0x0100000000000001.
+
+See the GStreamer DMA buffers design documentation for more details.
+
+This is used in the VA-API va plugin, waylandsink, the MSDK plugin, and the OpenGL integration. Video4Linux support is expected
+to land in one of the next minor releases.
+
+New API has been added for easy handling of these new caps:
+
+-   GstVideoInfoDmaDrm plus associated functions, similar to GstVideoInfo, including conversion to and from GstVideoInfo with
+    gst_video_info_dma_drm_from_video_info() and gst_video_info_dma_drm_to_video_info()
+
+-   GST_VIDEO_DMA_DRM_CAPS_MAKE
+
+-   GST_VIDEO_FORMAT_DMA_DRM
+
+### OpenGL integration enhancements
+
+-   When using EGL, if both OpenGL ES and OpenGL are available, OpenGL ES is preferred over OpenGL. OpenGL ES supports some
+    necessary features required for dmabuf support. This does not apply if an external library/application chooses an OpenGL API
+    first.
+
+-   Improved support for dmabuf use cases. The glupload element now supports the new and improved dmabuf negotiation with
+    explicit modifiers.
+
+-   Base classes for mixing with OpenGL are now public API. GstGLBaseMixer and GstGLMixer are exposed matching the existing
+    filter-based GstGLBaseFilter and GstGLFilter base classes. The new OpenGL mixer base classes are based on
+    GstVideoAggregator.
+
+-   Add support for a ‘surfaceless’ EGL context using EGL_MESA_platform_surfaceless.
+
+-   Expose Vivante Framebuffer build-related files (pkg-config, gir) as public API
+
+-   Add support for more video formats:
+
+    -   A420 8/10/12/16-bit.
+    -   A422 8/10/12/16-bit.
+    -   A444 8/10/12/16-bit.
+    -   I420 10/12 bit.
+    -   RBGA.
+
+-   Add support for tiled video formats
+
+    -   NV12_16L32S (Mediatek format)
+    -   NV12_4L4 (Verisilicon Hantro format)
+
+-   glcolorconvert now has API for retrieving shader strings for:
+
+    -   swizzling (reordering components).
+    -   YUV->RGB conversion.
+    -   RGB->YUV conversion.
+
+-   Add more helpers for information about a particular video and/or GL format e.g. number of components, bytes used, or pixel
+    ordering.
+
+-   glvideomixer has new sink pad properties sizing-policy, xalign, yalign matching compositor.
+
+-   GstGLBufferPool now has a configuration option for allowing a number of buffers to be always outstanding allowing for
+    reducing the potential synchronisation delay when reusing OpenGL memory backed buffers.
+
+### Vulkan integration enhancements
+
+-   Add support for the Vulkan H.264 and H.265 decoders.
+
+-   Add support for timeline semaphores.
+
+-   Optionally use newer Vulkan functions for format selection.
+
+-   Add support for GPU-assisted validation.
+
+-   Vulkan/Wayland: add support for xdg_wm_base protocol for creating a visible debug window. Required as the previous wl_shell
+    interface is being removed from compositors.
+
+### CUDA / NVCODEC integration and feature additions
+
+-   New cudaipcsrc and cudaipcsink elements for zero-copy CUDA memory sharing between processes
+
+-   New nvJPEG library based nvjpegenc JPEG encoder element
+
+-   The NVIDIA desktop GPU decoder nvh264sldec, nvh265sldec, nvvp8sldec, and nvvp9sldec elements were renamed to nvh264dec,
+    nvh265dec, nvvp8dec, and nvvp9dec, respectively.
+
+-   GStreamer NVIDIA H.264 and H.265 encoders except for nvh264enc and nvh265enc gained support for CEA708 Closed Caption
+    inserting.
+
+-   OpenGL memory support is added to nv{cuda,autogpu}h264enc and nv{cuda,autogpu}h265enc elements
+
+-   CUDA stream integration: As of 1.24, CUDA stream synchronization is an application’s responsibility, and GStreamer will not
+    execute unnecessary synchronization operations. If an application needs direct access to CUDA memory via GST_MAP_CUDA map
+    flag, cuStreamSynchronize() or gst_cuda_memory_sync() call is required unless application-side CUDA operation is executed
+    with the GstCudaMemory’s associated CUDA stream.
+
+### RTP stack improvements
+
+-   New rtppassthroughpay element which just passes RTP packets through unchanged, but appears like an RTP payloader element.
+    This is useful for relaying an RTP stream as-is through gst-rtsp-server, which expects an RTP payloader with certain
+    properties at the end of an RTSP media sub-pipeline.
+
+-   New “timeout-inactive-rtp-sources” property on rtpbin, sdpdemux and rtpsession to allow applications to disable automatic
+    timeout of sources from which no data has been received for a while.
+
+-   rtpvp8pay, rtpvp9pay: expose “picture-id” as a property, and add a “picture-id-offset” property to the VP9 payloader to
+    bring it in line with the VP8 payloader.
+
+-   rtpjitterbuffer has seen improved media clock handling (clock equality and clock setting/resetting), as well as two new
+    properties that allow reconstruction of absolute PTP timestamps without actually syncing to the PTP clock, which can be
+    useful in scenarios where one wants to reconstruct the absolute PTP clock timestamps on a machine that doesn’t have access
+    to the network of the PTP clock provider. The two new properties are:
+
+    -   “rfc7273-use-system-clock”: allows the jitter buffer to assume that the system clock is synced sufficiently close to the
+        media clock used by an RFC7273 stream. By default the property is disabled and the jitter buffer will create a media
+        clock and try to sync to it, but this is only required to determine in which wraparound period from the media clock’s
+        Epoch the current RTP timestamps refer to (and thus to reconstruct absolute time stamps from them). If the property is
+        enabled the wraparound period and current offset from the Epoch will be determined based on the local system clock,
+        which means that no direct network connection to the media clock provider is needed to reconstruct absolute timestamps.
+        There is also no start-up delay, because there’s no clock sync that needs to be established first.
+
+    -   “rfc7273-reference-timestamp-meta-only”: If this property is enabled then the jitter buffer will do the normal timestamp
+        calculations for the output buffers according to the configured mode instead of making use of the RFC7273 media clock
+        for that. It will still calculate RFC7273 media clock timestamps, but only attach them to the output buffers in form of
+        a clock reference meta.
+
+-   RTP payloaders and depayloaders now have an “extensions” property for retrieving the list of currently enabled RTP header
+    extensions.
+
+-   rtpbin and webrtcbin no longer blindly set properties on the jitter buffer assuming it’s a standard rtpjitterbuffer, but
+    instead check if the property is available first, to better support non-standard jitterbuffers or even an identity element
+    in lieu of a jitter buffer.
+
+-   RTP header extension handling fixes for depayloaders that aggregate multiple input buffers into a single output buffer.
+    Before, only the last RTP input buffer was checked for header extensions. Now the depayloader remembers all RTP packets
+    pushed before an output buffer is produced and checks all RTP input buffers for header extensions.
+
+    -   Affected depayloaders: rtph264depay, rtph265depay, rtpvp8depay, rtpvp9depay, rtpxqtdepay, rtpasfdepay, rtpmp4gdepay,
+        rtpsbcdepay, rtpvorbisdepay, rtpmp4vdepay, rtptheoradepay, rtpsv3vdepay, rtpmp4adepay, rtpklvdepay, rtpjpegdepay,
+        rtpj2kdepay, rtph263pdepay, rtph263depay, rtph261depay. rtpgstdepay.
+
+### WebRTC improvements
+
+-   Add support for ICE consent freshness (RFC 7675). This requires libnice >= 0.1.22.
+
+-   Advertise the local side of an end-of-candidates with an empty candidate string.
+
+-   Add the number of Data Channels opened and closed to webrtcbin’s statistics.
+
+-   Various improvements and feature additions in the Rust webrtc plugin, which provides webrtcsrc and webrtcsink elements as
+    well as specific elements for different WebRTC signalling protocols. See the Rust plugins section below for more details.
+
+### Adaptive Streaming improvements and Low-Latency HLS (LL-HLS) support
+
+-   hlsdemux2 now supports Low-Latency HLS (LL-HLS)
+
+-   hlsdemux2 asynchronous playlist download and update improves responsiveness and bandwith usage.
+
+-   hlsdemux2 handles fallback variant URLs.
+
+-   hlsdemux2 is more responsive and accurate when handling seeks.
+
+-   dashdemux2 and hlsdemux2 have a new “start-bitrate” property, improving the decision for which initial stream variant that
+    will be used.
+
+-   dashdemux2, hlsdemux2, mssdemux2 have received many improvements regarding seeking, along with support for “early-seek”
+    which allows playback to start immediately from the requested position without any previous download.
+
+-   dashdemux2, hlsdemux2, mssdemux2 better handle errors on or near the live edge.
+
+-   dashsink can now use the dashmp4mux muxer from the Rust plugins and will also produce better and RFC 6381-compatible codec
+    strings. The “suggested-presentation-delay” property allows to set the suggested presentation delay in the MPD.
+
+-   No development took place on the legacy demuxers (dashdemux, hlsdemux, mssdemux). Application developers are reminded to use
+    the new demuxers instead. They are automatically picked up when using urisourcebin, uridecodebin3 or playbin3.
+
+### W3C Media Source Extensions library
+
+-   A new GStreamer library (mse) implementing the W3C Media Source Extensions specification was added.
+
+-   Applications can embed this library along with GStreamer in order to integrate software that uses the Media Source APIs
+    without relying on a web browser engine. Typically an application consuming this library will wrap the C API with JavaScript
+    bindings that match the Media Source API so their existing code can integrate with this library.
+
+### Closed Caption handling improvements
+
+-   ccconverter supports converting between the two CEA-608 fields.
+
+-   New cea608mux element for muxing multiple CEA-608 streams together.
+
+-   Various improvements and feature additions in the Rust-based closed caption elements. Check out the Rust plugins section
+    below for more details.
+
+### Precision Time Protocol (PTP) clock improvements
+
+-   Many fixes and compatibility/interoperability improvements.
+
+-   Better support for running on devices with multiple network interfaces.
+
+-   Allow sync to master clock on same host.
+
+-   PTP clock support is now also available on Windows.
+
+-   The standalone ptp-helper binary has been rewritten in Rust for portability and security. This works on Linux, Android,
+    Windows, macOS, FreeBSD, NetBSD, OpenBSD, DragonFlyBSD, Solaris and Illumos. Newly supported compared to the C version is
+    Windows. Compared to the C version various error paths are handled more correctly and a couple of memory leaks are fixed.
+    Otherwise it should work identically. The minimum required Rust version for compiling this is 1.48, i.e. the version
+    currently in Debian oldstable. On Windows, Rust 1.54 is needed at least.
+
+-   New ptp-helper Meson build option so PTP support can be disabled or required.
+
+-   gst_ptp_init_full() allows for a more fine-grained and extensible configuration and initialization of the GStreamer PTP
+    subsystem, including TTL configuration.
+
+### Bayer 10/12/14/16-bit depth support
+
+-   bayer2rgb and rgb2bayer now support bayer with 10/12/14/16 bit depths
+
+-   v4l2src and videotestsrc now support bayer with 10/12/14/16 bit depths
+
+-   imagefreeze gained bayer support as well
+
+### MPEG-TS improvements
+
+-   mpegtsdemux gained support for
+    -   segment seeking for seamless non-flushing looping, and
+    -   synchronous KLV
+-   mpegtsmux now
+    -   allows attaching PCR to non-PES streams
+    -   allows setting of the PES stream number for AAC audio and AVC video streams via a new “stream-number” property on the
+        muxer sink pads. Currently the PES stream number is hard-coded to zero for these stream types.
+    -   allows writing arbitrary Opus channel mapping families and up to 255 channels
+    -   separate handling of DVB and ATSC AC3 descriptors
+
+## New elements and plugins
+
+-   analyticsoverlay visualises object-detection metas on a video stream.
+
+-   autovideoflip and autodeinterlace are two new auto elements.
+
+-   AJA source and sink elements plus device provider for AJA capture and playout cards, including support for HANC/VANC
+    ancillary data.
+
+-   New cea608mux element for muxing multiple CEA-608 streams together.
+
+-   The codec2json plugin adds av12json, h2642json, h2652json and vp82json elements which convert AV1, H.264, H.265 and VP8
+    frame parameters into human readable JSON data, which is useful for debugging and testing purposes.
+
+-   New lc3 plugin with a decoder and encoder for the Bluetooth LC3 audio codec.
+
+-   New onnxinference element to run ONNX inference models on video buffers.
+
+-   New rtppassthroughpay element which just passes RTP packets through unchanged, but appears like an RTP payloader element.
+    This is mostly useful for medias that simply pass through an existing RTP stream in gst-rtsp-server.
+
+-   Qt6: qml6glsrc, qml6glmixer, qml6gloverlay, and qml6d3d11sink
+
+-   New SVT-AV1 encoder plugin, imported from SVT-AV1 but with many fixes.
+
+-   Many exciting new Rust elements, see Rust section below.
+
+-   New DirectWrite text rendering and Direct3D12 plugins (see Windows section below).
+
+-   New vaav1enc element for encoding video in AV1 (See VA-API section)
+
+-   New uvcsink element for exporting streams as UVC camera
+
+## New element features and additions
+
+-   alphacombine supports I420_10LE now for 10-bit WebM/alpha support.
+
+-   The amfcodec for hardware-accelerated video encoding using the Advanced Media Framework (AMF) SDK for AMD GPUs gained some
+    new features:
+
+    -   10-bit and HDR support for H.265 / HEVC and AV1 video encoders
+    -   B-frame support in the H.264 encoder
+    -   Initial support of pre-analysis and pre-encoding
+    -   Initial support of Smart Access Video for optimal distribution amongst multiple AMD hardware instances.
+
+-   appsink: new “propose-allocation” signal so applications can provide a buffer pool or allocators to the upstream elements,
+    as well as “max-time” and “max-buffers” properties to configure the maximum size of the appsink-internal queue in addition
+    to the existing “max-bytes” property.
+
+-   autovideoconvert exposes colorspace and scaler elements for well know elements
+
+-   avtp: add AVTP Raw Video Format payload and de-payload support.
+
+-   cacasink’s output driver can now be selected via the “driver” property.
+
+-   camerabin: various fixes and stability improvements
+
+-   clocksync: “QoS” property to optionally send QoS events upstream like a synchronising sink would.
+
+-   cutter: can add GstAudioLevelMeta on output buffers, which can be enabled via the new “audio-level-meta” property.
+
+-   dashdemux2 has a new “start-bitrate” property.
+
+-   dashsink can now use the dashmp4mux muxer from the Rust plugins and will also produce better and RFC 6381-compatible codec
+    strings. The “suggested-presentation-delay” property allows to set the suggested presentation delay in the MPD.
+
+-   deinterlace: Add support for 10/12/16-bit planar YUV formats
+
+-   The dvdspu subpicture overlay now implements GstVideoOverlayComposition support to make it work better with hardware
+    decoders where the video data should ideally stay on the GPU/VPU and the overlay blitting be delegated to the renderer.
+
+-   encodebin now automatically autoplugs timestamper elements such as h264timestamper or h265timestamper, based on new
+    “Timestamper” element factory type and rank.
+
+-   New fakevideodec element (see debugging section below).
+
+-   filesink: “file-mode” property to allow the ability to specify rb+ file mode, which overwrites an existing file. This is
+    useful in combination with splitmuxsink so that files can be pre-allocated which can be useful to reduce disk fragmentation
+    over time.
+
+-   flvmux: add “enforce-increasing-timestamps” property to allow disabling a hack that was added back in the day because
+    librtmp as used in rtmpsink would get confused by timestamps going backwards, but this is no longer required with rtmpsink2.
+    If set to true (still the default, for backwards compatibility), flvmux will modify buffers timestamps to ensure they are
+    always strictly increasing, inside one stream and also between the audio and video streams.
+
+-   giostreamsink: Add a property to close the stream on stop().
+
+-   h264parse improved its AU boundary detection.
+
+-   h264parse, h265parse, mpegvideoparse now support multiple unregistered user data SEI messages.
+
+-   insertbin is now a registered element and available via the registry, so can be constructed via parse-launch and not just
+    via the insertbin API.
+
+-   jack: libjack is now loaded dynamically at runtime instead of linking it at build time. This means the plugin can be shipped
+    on Windows and macOS and will work if there’s a user-installed JACK server/library setup.
+
+-   jpegparse now has a rank so it will be autoplugged if needed.
+
+-   kmssink: Add auto-detection for NXP i.MX8M Plus LCDIFv3, ST STM32 LTDC, and Texas Instruments TIDSS display controllers.
+
+-   matroskademux and matroskamux gained support for more raw video formats, namely RGBA64_LE, BGRA64_LE, GRAY10_BE32, GRAY16_LE
+
+-   mpg123audiodec’s rank was changed from MARGINAL to PRIMARY so it’s now higher than avdec_mp3, as it works better with
+    “freeformat” MP3s.
 
 -   msdk:
 
-    -   new msdkav1enc AV1 video encoder element
-    -   msdk decoders: Add support for Scaler Format Converter (SFC) on
-        supported Intel platforms for hardware accelerated conversion
-        and scaling
-    -   msdk encoders: support import of dmabuf, va memory and D3D11
-        memory
-    -   msdk encoders: add properties for low delay bitrate control and
-        max frame sizes for I/P frames
-    -   msdkh264enc, msdkh265enc: more properties to control intra
-        refresh
-    -   note that on systems with multi GPUs the Windows D3D11
-        integration might only work reliably if the Intel GPU is the
-        primary GPU
+    -   DRM modifier support on Linux
 
--   mxfdemux: Add support for Canon XF-HEVC
+    -   only expose codecs and capabilities actually supported by the platform
 
--   openaptx: Support the freeaptx library
+    -   msdkvpp video post-processing:
 
--   qroverlay:
+        -   new “hdr-tone-mapping” property to enable HDR-to-SDR tone mapping
+        -   new compute scaling mode
 
-    -   new “qrcode-case-sensitive” property allows encoding case
-        sensitive strings like wifi SSIDs or passwords.
-    -   added the ability to pick up data to render from an
-        upstream-provided custom GstQROverlay meta
+    -   Decoders sport D3D11 and VA integration, and the VP9 decoder supports certain resolution changes.
 
--   qtdemux: Add support for ONVIF XML Timed MetaData and AVC-Intra
-    video
+    -   Encoders:
 
--   rfbsrc now supports the uri handler interface, so applications can
-    use RFB/VNC sources in uridecodebin(3) and playbin, with
-    e.g. rfb://:password@10.1.2.3:5903?shared=1
+        -   msdkh264enc, msdkh265enc**: “pic-timing-sei” property to insert pic timing SEI
+        -   msdkh264enc, msdkh265enc**: Add properties to allow different max/min-qp values for I/P/B frames
+        -   msdkh264enc: Added BGRx format DMABuf support
+        -   Advertise special image formats in low power mode
 
--   rtponviftimestamp: Add support for using reference timestamps
+-   mxfdemux gained support for FFV1 demuxing
 
--   rtpvp9depay now has the same keyframe-related properties as
-    rtpvp8depay and rtph264depay: “request-keyframe” and
-    “wait-for-keyframe”
+-   opusenc, opusdec now support decoding and encoding more than 8 channels, and can also handle unknown/unpositioned channel
+    layouts.
 
--   rtspsrc: Various RTSP servers are using invalid URL operations for
-    constructing the control URL. Until GStreamer 1.16 these worked
-    correctly because GStreamer was just appending strings itself to
-    construct the control URL, but starting version 1.18 the correct URL
-    operations were used. With GStreamer 1.22, rtspsrc now first tries
-    with the correct control URL and if that fails it will retry with
-    the wrongly constructed control URL to restore support for such
-    servers.
+-   The oss plugin gained a device provider for audio device discovery
 
--   rtspsrc and rtpjitterbuffer gained a new
-    “add-reference-timestamp-meta” property that makes them put the
-    unmodified original sender timestamp on output buffers for NTP or
-    PTP clock synced senders
+-   pcapparse learned how to handle the Linux “cooked” capture encapsulation v2
 
--   srtsrc, srtsink: new “auto-reconnect” property to make it possible
-    to disable automatic reconnects (in caller mode) and make the
-    elements post an error immediately instead; also stats improvements
+-   Intel Quick Sync plugin improvements:
 
--   srtsrc: new “keep-listening” property to avoid EOS on disconnect and
-    keep the source running while it waits for a new connection.
+    -   qsvh264enc gained more encoding options
+    -   qsvh265dec now supports GBR decoding and HEVC RExt profiles
 
--   videocodectestsink: added YUV 4:2:2 support
+-   qtdemux now adds audio clipping meta when playing gapless m4a content, supports CENC sample grouping, as well as the SpeedHQ
+    video codec.
 
--   wasapi2src: Add support for process loopback capture
+-   ristsrc gained support for dynamic payloads via the new “caps” and “encoding-name” properties. These can be used to make the
+    ristsrc receive other payload types than MPEG-TS.
 
--   wpesrc: Add support for modifiers in key/touch/pointer events
+-   rtmp2src: a new “no-eof-is-error” property was added: There is currently no way for applications to know if the stream has
+    been properly terminated by the server or if the network connection was disconnected, as an EOS is sent in both cases. With
+    the property set, connection errors will be reported as errors, allowing applications to distinguish between both scenarios.
 
-Plugin and library moves
+-   rtspsrc: new “extra-http-request-headers” property for adding custom http request headers when using http tunnelling.
 
--   The xingmux plugin has been moved from gst-plugins-ugly into
-    gst-plugins-good.
+-   sdpdemux now supports SDP source filters as per RFC 4570; audio-only or video-only streaming can be selected via the new
+    “media” property, and RTCP feedback can be disabled via the “rtcp-mode” property.
 
--   The various Windows directshow plugins in gst-plugins-bad have been
-    unified into a single directshow plugin.
+-   splitmuxsrc uses natural ordering to sort globbed filenames now, i.e. 0, 1, 2, 10, 11 instead of 0, 1, 10, 11, 2, …
 
-Plugin removals
+-   srt: Add more fields to the statistics to see how many packets were retransmitted and how many were dropped.
 
--   The dxgiscreencapsrc element has been removed, use
-    d3d11screencapturesrc instead
+-   switchbin: many improvements, especially for caps handling and passthrough.
 
-Miscellaneous API additions
+-   taginject: a “scope” property was added to allow injection of global tags in addition to the current default which is stream
+    tags.
 
--   GST_AUDIO_FORMAT_INFO_IS_VALID_RAW() and
-    GST_VIDEO_FORMAT_INFO_IS_VALID_RAW() can be used to check if a
-    GstAudioFormatInfo or GstVideoFormatInfo has been initialised to a
-    valid raw format.
+-   timeoverlay: add buffer-count and buffer-offset time modes.
 
--   Video SEI meta: new GstVideoSEIUserDataUnregisteredMeta to carry
-    H.264 and H.265 metadata from SEI User Data Unregistered messages.
+-   udpsrc: new “multicast-source” property to support IGMPv3 Source Specific Muliticast (SSM) as per RFC 4604.
 
--   vulkan: Expose gst_vulkan_result_to_string()
+-   videoconvertscale, videoconvert: add a “converter-config” property to allow fine-tuning conversion parameters that are not
+    exposed directly as property.
 
-Miscellaneous performance, latency and memory optimisations
+-   videoflip: many orientation tag handling fixes and improvements
 
--   liborc 0.4.33 adds support for aarch64 (64-bit ARM) architecture
-    (not enabled by default on Windows yet though) and improvements for
-    32-bit ARM and should greatly enhance performance for certain
-    operations that use ORC.
+-   videorate: add “drop-out-of-segment” property to force dropping of out-of-segment buffers.
 
--   as always there have been plenty of performance, latency and memory
-    optimisations all over the place.
+-   volume now supports arbitrarily-large positive gains via a new “volume-full-range” property (it was not possibly to just
+    allow a bigger maximum value for the existing “volume” property for GstController-related backwards-compatibility reasons).
 
-Miscellaneous other changes and enhancements
+-   waylandsink, gtkwaylandsink: improved frame scheduling reducing frame drops and improve throughput.
 
--   the audio/video decoder base classes will not consider decoding
-    errors a hard error by default anymore but will continue trying to
-    decode. Previously more than 10 consecutive errors were considered a
-    hard error but this caused various partially broken streams to fail.
-    The threshold is configurable via the “max-errors” property.
+-   webpenc now has support for animated WebP which can be enabled via the new “animated” property. By default it will just
+    output a stand-alone WebP image for each input buffer, just like before.
 
--   compatibility of the GStreamer PTP clock implementation with
-    different PTP server implementations was improved, and
-    synchronization is achieved successfully in various scenarios that
-    failed before.
+-   wpe: added a WebProcess crash handler; gained WPEWebKit 2.0 API support.
 
-Tracing framework and debugging improvements
+-   x264enc gained support for 8-bit monochrome video (GRAY8).
 
-New tracers
+-   ximagesrc gained navigation support (mouse and keyboard events).
+
+-   y4mdec now parses extended headers to support high bit depth video.
+
+## Plugin and library moves
+
+-   The AMR-NB and AMR-WB plugins have been moved from -ugly to -good.
+
+## Plugin and element removals
+
+-   The entire gst-omx package and plugin has been retired. See the OMX section below for more details.
+
+-   The RealServer RTSP extension, RDT handling and PNM source have been removed from the realmedia plugin.
+
+-   The kate subtitle plugin has been removed.
+
+## Miscellaneous API additions
+
+GStreamer Core
+
+-   gst_pipeline_get_configured_latency() and gst_pipeline_is_live() convenience functions to query liveness and configured
+    latency of a pipeline.
+
+-   Plugins can now provide status info messages for plugins that will be displayed in gst-inspect-1.0 and is useful for dynamic
+    plugins that register features at runtime. They are now able to provide information to the user why features might not be
+    available. This is now used in the amfcodec, nvcodec, qsv, and va plugins.
+
+-   GST_OBJECT_AUTO_LOCK() and GST_PAD_STREAM_AUTO_LOCK() are g_autoptr(GMutexLocker)-based helpers for GstPad and GstObject
+    that unlock the mutex automatically when the helper goes out of scope. This is not portable so should not be used in
+    GStreamer code that needs to be portable to e.g. Windows with MSVC.
+
+-   gst_clear_context(), gst_clear_promise(), gst_clear_sample()
+
+-   gst_util_ceil_log2() and gst_util_simplify_fraction() utility functions
+
+-   New TAG_CONTAINER_SPECIFIC_TRACK_ID tag for container specific track ID as used in an HTML5 context, plus basic support in
+    matroskademux, qtdemux, dashdemux and dashdemux2
+
+-   New utility functions to create a stream-id without a pad for elements:
+
+    -   gst_element_decorate_stream_id()
+    -   gst_element_decorate_stream_id_printf_valist()
+    -   gst_element_decorate_stream_id_printf()
+
+-   GstQueueArray gained API for sorting and sorted insertion
+
+-   Add strict GstStructure serialisation with gst_structure_serialize_full() in combination with GST_SERIALIZE_FLAG_STRICT
+    which only succeeds if the result can later be fully deserialised again.
+
+-   GstBaseSrc enhancements: the “automatic-eos” property can be used to do the equivalent to gst_base_src_set_automatic_eos().
+    gst_base_src_push_segment() sends a segment event right away which can be useful for subclasses like appsrc which have their
+    own internal queuing.
 
--   buffer-lateness: Records lateness of buffers and the reported
-    latency for each pad in a CSV file. Comes with a script for
-    visualisation.
+-   GstBaseSink gained a new custom GST_BASE_SINK_FLOW_DROPPED flow return which can be used by subclasses from the virtual
+    ::render method to signal to the base class that a frame is not being rendered. This is used in e.g. waylandsink and ensures
+    that elements such as fpsdisplaysink will correctly report the rate of frames rendered and dropped.
 
--   pipeline-snapshot: Creates a .dot file of all pipelines in the
-    application whenever requested via SIGUSR1 (on UNIX systems)
+GstDiscoverer
 
--   queue-levels: Records queue levels for each queue in a CSV file.
-    Comes with a script for visualisation.
+-   New “load-serialized-info” signal to retrieve a serialized GstDiscovererInfo
+
+GstSDP
+
+-   Add gst_sdp_message_remove_media()
+
+Video Library
+
+DRM Modifier Support for dmabufs on Linux
+
+See section above.
+
+List of Video Formats for Passthrough
+
+New helper API was added to get a list of all supported video formats, including DMA_DRM formats, and can be used to advertise
+all supported formats for passthrough purposes:
+
+-   GST_VIDEO_FORMATS_ANY_STR, GST_VIDEO_FORMATS_ANY
+-   gst_video_formats_any() which can be used by bindings or for code that prefers GstVideoFormat values instead of strings.
+
+New Video Formats
+
+-   12-bit and 16-bit A420 / A422 / A444 (YUV with alpha channel) variants:
+
+    -   A444_12BE, A444_12LE
+    -   A422_12BE, A422_12LE
+    -   A420_12BE, A420_12LE
+    -   A444_16BE, A444_16LE
+    -   A422_16BE, A422_16LE
+    -   A420_16BE, A420_16LE
+
+-   8-bit A422 / A444 (YUV with alpha channel) variant:
+
+    -   A422
+    -   A444
+
+-   Planar 16-bit 4:4:4 RGB formats:
+
+    -   GBR_16BE
+    -   GBR_16LE
+
+-   RBGA, intended to be used by hardware decoders where VUYA is only supported 4:4:4 decoding surface but the stream is encoded
+    with GBR color space, such as HEVC and VP9 GBR streams for example.
+
+-   Two tiled Mediatek 10-bit formats:
+
+    -   MT2110T
+    -   MT2110R
+
+-   Tiled 10-bit NV12 format NV12_10LE40_4L4 (Verisilicon Hantro)
+
+## Miscellaneous performance, latency and memory optimisations
+
+-   liborc 0.4.35 (latest: 0.4.38) adds support for AVX/AVX2 and contains improvements for the SSE backend.
+
+-   liborc 0.4.37 adds support for NEON on macOS on Apple ARM64 CPUs.
+
+-   Most direct use of the GLib GSLice allocator has been removed, as there is little evidence that it actually still provides
+    much advantage over the standard system allocator on Linux or Windows in 2024. There is strong evidence however that it
+    causes memory fragmentation for standard GStreamer workloads such as RTSP/RTP/WebRTC streaming.
+
+-   As always there have been plenty of performance, latency and memory optimisations all over the place.
+
+## Tracing framework and debugging improvements
+
+-   The gst-stats tool can now be passed a custom regular expression
+
+-   gst-debug-viewer from the devtools module has seen minor improvements and fixes
+
+New tracers
+
+-   None in this release.
 
 Debug logging system improvements
 
--   new log macros GST_LOG_ID, GST_DEBUG_ID, GST_INFO_ID,
-    GST_WARNING_ID, GST_ERROR_ID, and GST_TRACE_ID allow passing a
-    string identifier instead of a GObject. This makes it easier to log
-    non-gobject-based items and also has performance benefits.
+-   Nothing major in this cycle.
 
-Tools
+Fake video decoder
 
--   gst-play-1.0 gained a --no-position command line option to suppress
-    position/duration queries, which can be useful to reduce debug log
-    noise.
+-   The new fakevideodec element does not decode the input bitstream, it only reads video width, height and framerate from the
+    caps and then pushes out raw video frames of the expected size in RGB format.
 
-GStreamer FFMPEG wrapper
+-   It draws a snake moving from left to right in the middle of the frame, which is reasonably light weight and still provides
+    an idea about how smooth the rendering is.
 
--   Fixed bitrate management and timestamp inaccuracies for video
-    encoders
+## Tools
 
--   Fix synchronization issues and errors created by the (wrong)
-    forwarding of upstream segment events by ffmpeg demuxers.
+-   gst-launch-1.0 gained a new --prog-name command line option to set the program name, which will be used by GTK and GStreamer
+    to set the class or app-id.
 
--   Clipping meta support for gapless mp3 playback
+-   gst-play-1.0 now defaults to using playbin3, but can still be made to use the old playbin by passing the --use-playbin2
+    command line argument.
 
-GStreamer RTSP server
+## GStreamer FFmpeg wrapper
 
--   Add RFC5576 Source-specific media attribute to the SDP media for
-    signalling the CNAME
+-   New avvideocompare element to compare two incoming video buffers using a specified comparison method (e.g. SSIM or PSNR).
 
--   Add support for adjusting request response on pipeline errors
+-   Prefer using FFmpeg Musepack decoder/demuxer over musepackdec as they work better with decodebin3 and playbin3 which likes
+    to have parsers and decoders separate.
 
-    -   Give the application the possibility to adjust the error code
-        when responding to a request. For that purpose the pipeline’s
-        bus messages are emitted to subscribers through a
-        “handle-message” signal. The subscribers can then check those
-        messages for errors and adjust the response error code by
-        overriding the virtual method
-        GstRTSPClientClass::adjust_error_code().
+-   Added codec mappings for AV1, MxPEG, FFVHuff video
 
--   Add gst_rtsp_context_set_token() method to make it possible to set
-    the RTSPToken on some RTSPContext from bindings such as the Python
-    bindings.
+-   Added raw video format support for P010, VUYA, Y410, P012, Y212 and Y412.
 
--   rtspclientsink gained a “publish-clock-mode” property to configure
-    whether the pipeline clock should be published according to RFC7273
-    (RTP Clock Source Signalling), similar to the same API on
-    GstRTSPMedia.
+-   Newer, non-deprecated APIs are used by the plugin when built with FFmpeg 6.0 or newer.
 
-GStreamer VA-API support
+-   The FFmpeg meson subproject wrap has been updated to v6.1
 
--   Development activity has shifted towards the new va plugin, with
-    gstreamer-vaapi now basically in maintenance-only mode. Most of the
-    below refers to the va plugin (not gstreamer-vaapi).
+-   Note: see Known Issues section below for known issues with FFmpeg 6.0.0 and the latest FFmpeg 7.x release
 
--   new gst-va library for GStreamer VA-API integration
+## GStreamer RTSP server
 
--   vajpegdec: new JPEG decoder
+-   New “ensure-keyunit-on-start” property: While the suspend modes NONE and PAUSED provided a low startup latency for
+    connecting clients, it did not ensure that streams started on fresh data. With this new property it is possible to maintain
+    the low startup latency of those suspend modes while also ensuring that a stream starts on a key unit. Furthermore, by
+    setting the new “ensure-keyunit-on-start-timeout” property it is also possible to accept a key unit of a certain age, but
+    discard it if too much time has passed and instead force a new key unit.
 
--   vah264enc, vah265enc: new H.264/H.265 encoders
+-   rtspclientsink: apply “port-range” property for RTCP port selection as well
 
--   vah264lpenc, vah265lpenc: new low power mode encoders
+## GStreamer VA-API support
 
--   vah265enc: Add extended formats support such as 10/12 bits, 4:2:2
-    and 4:4:4
+GstVA
 
--   Support encoder reconfiguration
+-   vah264dec, vah265dec, vavp8dec, vavp9dec, vampeg2dec and vaav1dec were promoted to rank PRIMARY+1 on Linux
 
--   vacompositor: Add new compositor element using the VA-API VPP
-    interface
+-   Improved support for dmabuf use cases. All va elements now negotiate the new and improved dmabuf capabilities with explicit
+    modifiers. This supports both import and export of dmabufs.
 
--   vapostproc:
+-   Added vaav1enc element, available in recent Intel and AMD GPUs
 
-    -   new “scale-method” property
-    -   Process HDR caps if supported
-    -   parse video orientation from tags
+-   Added support for the experimental VA-Win32 backend. It needs at least libva 1.18
 
--   vaapipostproc: Enable the use of DMA-Buf import and export
-    (gstreamer-vaapi)
+-   Improved handling of multi-GPU systems. Still, sharing buffers among them is not advised.
 
-GStreamer Video4Linux2 support
+-   Bumped minimum libva version to 1.12
 
--   Added support for Mediatek Stateless CODEC (VP8, H.264, VP9)
+-   Enhanced support for RadeonSI Mesa driver for 10bit decoding
 
--   Stateless H.264 interlaced decoder support
+-   Register elements only for allowed drivers (Intel and Mesa, for the moment)
 
--   Stateless H.265 decoder support
+GStreamer-VAAPI
 
--   Stateful decoder support for driver resolution change events
+-   The new GstVA elements (see above) should be preferred when possible.
 
--   Stateful decoding support fixes for NXP/Amphion driver
+-   Ranks of decoders were demoted to NONE so they won’t be used automatically by playbin and similar elements anymore.
 
--   Support for hardware crop in v4l2src
+-   Clean-ups and minimal fixes.
 
--   Conformance test improvement for stateful decoders
+-   gstreamer-vaapi should be considered deprecated and may be discontinued as soon as the va plugin is fully feature
+    equivalent. Users who rely on gstreamer-vaapi are encouraged to migrate and test the va elements at the earliest
+    opportunity.
 
--   Fixes for Raspberry Pi CODEC
+## GStreamer Video4Linux2 support
 
-GStreamer OMX
+-   New uvcsink element, based on v4l2sink allow streaming your pipeline as a UVC camera using Linux UVC Gadget driver.
 
--   There were no changes in this module
+-   v4l2src now supports 10/12/14/16-bit bayer formats.
 
-GStreamer Editing Services and NLE
+-   Stateful decoders now pass too large encoded frames over multiple buffers.
 
--   Handle compositors that are bins around the actual compositor
-    implementation (like glvideomixers which wraps several elements)
+-   AV1 Stateless video decoder.
 
--   Add a mode to disable timeline editing API so the user can be in
-    full control of its layout (meaning that the user is responsible for
-    ensuring its validity/coherency)
+-   Stateless decoders now tested using Virtual driver (visl), making it possible to run the tests in the cloud based CI
 
--   Add a new fade-in transition type
+## GStreamer OMX
 
--   Add support for non-1/1 PAR source videos
+-   The gst-omx module has been removed. The OpenMAX standard is long dead and even the Raspberry Pi OS no longer supports it.
+    There has not been any development since 1.22 was released. Users of these elements should switch to the Video4Linux-based
+    video encoders and decoders which have been the standard on embedded Linux for quite some time now.
 
--   Fix frame accuracy when working with very low framerate streams
+-   Hardware vendors which still use OpenMAX are known to have non-standard forks and it is recommended that they maintain it
+    while planning their move to the Video4Linux API.
 
-GStreamer validate
+## GStreamer Editing Services and NLE
 
--   Clean up and stabilize API so we can now generate rust bindings
+-   Implement a gesvideoscale effect which gives user the ability to chooses where a clip has to be scaled in the chain of
+    effects. By default scaling is done in the compositor.
 
--   Enhance the appsrc-push action type allowing to find tune the
-    buffers more in details
+-   Add support for gessrc as sub-timeline element so third party can implement their own formatters and use their timelines as
+    sub-timelines. Before that, only timelines serialized as files on the filesystem could be loaded as sub-timelines (using
+    gesdemux).
 
--   Add an action type to verify currently configured pad caps
+-   Implement a new GESDiscovererManager singleton object making management of the discoverers used to discoverer media files
+    cleaner and allowing to expose the following APIs:
 
--   Add a way to run checks from any thread after executing a ‘wait’
-    action. This is useful when waiting on a signal and want to check
-    the value of a property right when it is emited for example.
+    -   load-serialize-info signal so GstDiscovererInfo can be serialized by users the way they like and load them without
+        requiring discovering the file when reloading a project.
+    -   source-setup signal so user can tweak source elements during discovery
 
-GStreamer Python Bindings
+-   Expose GESFrameCompositionMeta in public API so user can implement their own effects targetting GES which take into account
+    that meta.
 
--   Add a Gst.init_python() function to be called from plugins which
-    will initialise everything needed for the GStreamer Python bindings
-    but not call Gst.init() again since this will have been called
-    already.
+-   Expose audioconvert:mix-matrix property in audio sources
 
--   Add support for the GstURIHandlerInterface that allows elements to
-    advertise what URI protocols they support.
+-   Port GESPipeline rendering to use encodebin2. This allows rendering timelines directly with a muxing sink (like hlssinkX
+    etc..) and leverage all new features of that new element.
 
-GStreamer C# Bindings
+ges-launch
 
--   Fix AppSrc and AppSink constructors
+-   Fix setting keyframes
 
--   The C# bindings have yet to be updated to include new 1.22 API,
-    which requires improvements in various places in the bindings /
-    binding generator stack. See issue #1718 in GitLab for more
-    information and to track progress.
+-   Add an ignore-eos option
 
-GStreamer Rust Bindings and Rust Plugins
+-   Allow overriding container profile so that the user can build encoding profiles following the media format of a specific
+    media file, for example, but ensuring it is muxed using a specific format
 
-The GStreamer Rust bindings are released separately with a different
-release cadence that’s tied to gtk-rs, but the latest release has
-already been updated for the new GStreamer 1.22 API. Check the bindings
-release notes for details of the changes since 0.18, which was released
-around GStreamer 1.20.
+-   Ensure sink elements are inside a GstBin and never in a GstPipeline
 
-gst-plugins-rs, the module containing GStreamer plugins written in Rust,
-has also seen lots of activity with many new elements and plugins. A
-list of all Rust plugins and elements provided with the 0.9 release can
-be found in the repository.
+-   Move +effect stack effects from source to last effect added, so it feels more natural to user as adding them at the
+    beginning of the chain while the syntax is +effect felt wrong
 
--   33% of GStreamer commits are now in Rust (bindings + plugins), and
-    the Rust plugins module is also where most of the new plugins are
-    added these days.
+## GStreamer validate
 
--   The Rust plugins are now shipped as part of the Windows MSVC + macOS
-    binary packages. See below for the list of shipped plugins and the
-    status of Rust support in cerbero.
+-   In action types, add a way to avoid checking property value after setting it, in case elements do it async for example.
 
--   The Rust plugins are also part of the documentation on the GStreamer
-    website now.
+-   Add a vmethod to free GstValidateActionParameters to be more binding friendly.
 
--   Rust plugins can be used from any programming language. To the
-    outside they look just like a plugin written in C or C++.
+-   Allow scenarios to define the pipeline state target in the metadata instead of assuming PLAYING state.
 
-New Rust plugins and elements
+-   Add support to run sub-pipelines/scenarios
 
--   rtpav1pay / rtpav1depay: RTP (de)payloader for the AV1 video codec
--   gtk4paintablesink: a GTK4 video sink that provides a GdkPaintable
-    for rendering a video in any place inside a GTK UI. Supports
-    zero-copy rendering via OpenGL on Linux and macOS.
--   ndi: source, sink and device provider for NewTek NDI protocol
--   onvif: Various elements for parsing, RTP (de)payloading, overlaying
-    of ONVIF timed metadata.
--   livesync: Element for converting a live stream into a continuous
-    stream without gaps and timestamp jumps while preserving live
-    latency requirements.
--   raptorq: Encoder/decoder elements for the RaptorQ FEC mechanism that
-    can be used for RTP streams (RFC6330).
+    -   Added support to forward buffers from appsink to appsrc
 
-WebRTC elements
+-   Add a way to set pipeline base-time, start-time and force using the system clock.
 
--   webrtcsink: a WebRTC sink (batteries included WebRTC sender with
-    specific signalling)
--   whipsink: WebRTC HTTP ingest (WHIP) to MediaServer
--   whepsrc: WebRTC HTTP egress (WHEP) from MediaServer
--   rtpgccbwe: RTP bandwidth estimator based on the Google Congestion
-    Control algorithm (GCC), used by webrtcsink
+-   Add a ‘fill-mode’ to the appsrc-push action type so we can create some type of streams easily using an appsrc, giving
+    control when writing scenarios without requiring files with the content.
 
-Amazon AWS services
+-   Add a “select-streams” action type to test “stream aware” elements.
 
--   awss3src / awss3sink: A source and sink element to talk to the
-    Amazon S3 object storage system.
--   awss3hlssink: A sink element to store HLS streams on Amazon S3.
--   awstranscriber: an element wrapping the AWS Transcriber service.
--   awstranscribeparse: an element parsing the packets of the AWS
-    Transcriber service.
+-   Add a way to wait for a property to reach a specified value before executing an action. For example it is possible to wait
+    for a pad to get some specific caps set before executing an action.
 
-Video Effects (videofx)
+-   validate: Add support to replace variables in deeply nested structures in particular for more complex action types where
+    some of the properties are inside structures.
 
--   roundedcorners: Element to make the corners of a video rounded via
-    the alpha channel.
--   colordetect: A pass-through filter able to detect the dominant
-    color(s) on incoming frames, using color-thief.
--   videocompare: Compare similarity of video frames. The element can
-    use different hashing algorithms like Blockhash, DSSIM, and others.
+-   Fixed compatibility with Python 3.12.
 
-New MP4 muxer + Fragmented MP4 muxer
+## GStreamer Python Bindings
 
--   fmp4mux: New fragmented MP4/ISOBMFF/CMAF muxer for generating
-    e.g. DASH/HLS media fragments.
--   isomp4mux: New non-fragmented, normal MP4 muxer.
+gst-python is an extension of the regular GStreamer Python bindings based on gobject-introspection information and PyGObject,
+and provides “syntactic sugar” in form of overrides for various GStreamer APIs that makes them easier to use in Python and more
+pythonic; as well as support for APIs that aren’t available through the regular gobject-introspection based bindings, such as
+e.g. GStreamer’s fundamental GLib types such as Gst.Fraction, Gst.IntRange etc.
 
-Both plugins provides elements that replace the existing qtmux/mp4mux
-element from gst-plugins-good. While not feature-equivalent yet, the new
-codebase and using separate elements for the fragment and non-fragmented
-case allows for easier extensability in the future.
+-   Added a GstTagList override that makes a tag list act like a dict
 
-Cerbero Rust support
+-   Fix build and usage in Windows
 
--   Starting this release, cerbero has support for building and shipping
-    Rust code on Linux, Windows (MSVC) and macOS. The Windows (MSVC) and
-    macOS binaries also ship the GStreamer Rust plugins in this release.
-    Only dynamic plugins are built and shipped currently.
+-   Various fixes for Python >= 3.12
 
--   Preliminary support for Android, iOS and Windows (MinGW) exists but
-    more work is needed. Check the tracker issue for more details about
-    future work.
+-   Rework libpython loading to be relocatable
 
--   The following plugins are included currently: audiofx, aws, cdg,
-    claxon, closedcaption, dav1d, fallbackswitch, ffv1, fmp4, gif,
-    hlssink3, hsv, json, livesync, lewton, mp4, ndi, onvif, rav1e,
-    regex, reqwest, raptorq, png, rtp, textahead, textwrap, threadshare,
-    togglerecord, tracers, uriplaylistbin, videofx, webrtc, webrtchttp.
+-   Fix libpython dlopen on macOS
 
-Build and Dependencies
+## GStreamer C# Bindings
 
--   meson 0.62 or newer is required
+-   The GStreamer C# bindings have been updated to a more recent version of GtkSharp and the bindings have been regenerated with
+    that version.
 
--   GLib >= 2.62 is now required (but GLib >= 2.64 is strongly
-    recommended)
+-   GStreamer API added in recent GStreamer releases is now available
 
--   libnice >= 0.1.21 is now required and contains important fixes for
-    GStreamer’s WebRTC stack.
+-   GstRtspServer bindings have been added, plus an RTSP server example
 
--   liborc >= 0.4.33 is recommended for 64-bit ARM support and 32-bit
-    ARM improvements
+## GStreamer Rust Bindings and Rust Plugins
 
--   onnx: OnnxRT >= 1.13.1 is now required
+The GStreamer Rust bindings and plugins are released separately with a different release cadence that’s tied to the twice-a-year
+GNOME release cycle.
 
--   openaptx: can now be built against libfreeaptx
+The latest release of the bindings (0.22) has already been updated for the new GStreamer 1.24 APIs, and works with any GStreamer
+version starting at 1.14.
 
--   opencv: allow building against any 4.x version
+gst-plugins-rs, the module containing GStreamer plugins written in Rust, has also seen lots of activity with many new elements
+and plugins. The GStreamer 1.24 binaries track the 0.12 release series of gst-plugins-rs, and fixes from newer versions will be
+backported as needed to the 0.12 brach for future 1.24.x bugfix releases.
 
--   shout: libshout >= 2.4.3 is now required
+Rust plugins can be used from any programming language. To applications they look just like a plugin written in C or C++.
 
--   gstreamer-vaapi’s Meson build options have been switched from a
-    custom combo type (yes/no/auto) to the built-in Meson feature type
-    (enabled/disabled/auto)
+### WebRTC
 
--   The GStreamer Rust plugins module gst-plugins-rs is now considered
-    an essential part of the GStreamer plugin offering and packagers and
-    distributors are strongly encouraged to package and ship those
-    plugins alongside the existing plugin modules.
+-   New element webrtcsrc that can act as a recvonly WebRTC client. Just like the opposite direction, webrtcsink, this can
+    support various different WebRTC signalling protocols. Some are included with the plugin and provide their own element
+    factory for easier usage but it is also possible for applications to provide new signalling protocol implementations.
 
--   we now make use of Meson’s install tags feature which allows
-    selective installation of installl components and might be useful
-    for packagers.
+-   webrtcsink now exposes the signaller as property and allows implementing a custom signaller by connecting signal handlers to
+    the default signaller.
 
-Monorepo build (gst-build)
+-   A new signaller and webrtcsink implementation for Janus’ VideoRoom implementation. The corresponding webrtcsrc signaller
+    implementation is currently in a merge request in GitLab.
 
--   new “orc-source” build option to allow build against a
-    system-installed liborc instead of forcing the use of orc as a
-    subproject.
+-   New whepsrc element that can receive WHEP WebRTC streams. This is currently not based on webrtcsrc but in the future a new
+    element around webrtcsrc will be added.
 
--   GStreamer command line tools can now be linked to the gstreamer-full
-    library if it’s built
+-   New whipserversrc element around webrtcsrc for ingesting WHIP WebRTC streams in GStreamer.
 
-Cerbero
+-   New whipclientsink element around webrtcsink for publishing WHIP WebRTC streams from GStreamer. This deprecates the old
+    whipsink element.
 
-Cerbero is a meta build system used to build GStreamer plus dependencies
-on platforms where dependencies are not readily available, such as
-Windows, Android, iOS, and macOS.
+-   A new signaller and webrtcsink implementation for LiveKit. The corresponding webrtcsrc signaller implementation was merged
+    into the git repository recently.
 
-General improvements
+-   A new signaller and webrtcsink implementation for AWS Kinesis Video Streams
 
--   Rust support was added for all support configurations, controlled by
-    the rust variant; see above for more details
--   All pkgconfig files are now reliably relocatable without requiring
-    pkg-config --define-prefix. This also fixes statically linking with
-    GStreamer plugins using the corresponding pkgconfig files.
--   New documentation on how to build a custom GStreamer repository
-    using Cerbero, please see the README
--   HTTPS certificate checking is enabled for downloads on all platforms
-    now
--   Fetching now automatically retries on error for robustness against
-    transient errors
--   Support for building the new Qt6 plugin was added
--   pkgconfig files for various recipes were fixed
--   Several recipes were updated to newer versions
--   New plugins: adaptivedemux2 aes codectimestamper dav1d
--   New libraries: cuda webrtcnice
-
-macOS / iOS
-
--   Added support for running Cerbero on ARM64 macOS
--   GStreamer.framework and all libraries in it are now relocatable,
-    which means they use LC_RPATH entries to find dependencies instead
-    of using an absolute path. If you link to GStreamer using the
-    pkgconfig files, no action is necessary. However, if you use the
-    framework directly or link to the libraries inside the framework by
-    hand, then you need to pass -Wl,-rpath,<path_to_libdir> to the
-    linker.
--   Apple bitcode support was dropped, since Apple has deprecated it
--   macOS installer now correctly advertises support for both x86_64 and
-    arm64
--   macOS framework now ships the gst-rtsp-server-1.0 library
--   Various fixes were made to make static linking to gstreamer
-    libraries and plugins work correctly on macOS
--   When statically linking to the applemedia plugin using Xcode 13, you
-    will need to pass -fno-objc-msgsend-selector-stubs which works
-    around a backwards-incompatible change in Xcode 14. This is not
-    required for the rest of GStreamer at present, but will be in the
-    future.
--   macOS installer now shows the GStreamer logo correctly
+-   webrtcsink has a new payloader-setup signal to allow the application more fine grained control over the RTP payloader
+    configuration, similar to the already existing encoder-setup signal for encoders.
 
-Windows
+-   webrtcsrc gained support for a custom navigation event protocol over the data channel, which is compatible with the
+    navigation event protocol supported by webrtcsink.
 
--   MSVC is now required by default on Windows, and the Visual Studio
-    variant is enabled by default
-    -   To build with MinGW, use the mingw variant
--   Visual Studio props files were updated for newer Visual Studio
-    versions
--   Visual Studio 2015 support was dropped
--   MSYS2 is now supported as the base instead of MSYS. Please see the
-    README for more details. Some advantages include:
-    -   Faster build times, since parallel make works
-    -   Faster bootstrap, since some tools are provided by MSYS2
-    -   Other speed-ups due to using MSYS2 tools instead of MSYS
--   Faster download by using powershell instead of hand-rolled Python
-    code
--   Many recipes were ported from Autotools to Meson, speeding up the
-    build
--   Universal Windows Platform is no longer supported, and binaries are
-    no longer shipped for it
--   New documentation on how to force a specific Visual Studio
-    installation in Cerbero, please see the README
--   New plugins: qsv wavpack directshow amfcodec wic win32ipc
--   New libraries: d3d11
-
-Windows MSI installer
-
--   Universal Windows Platform prebuilt binaries are no longer available
+-   webrtcsink supports encoded streams as input. Using encoded streams will disable webrtcsinks congestion control changing any
+    encoded stream parameters.
 
-Linux
+-   webrtcsink and webrtcsrc have a new signal ‘request-encoded-filter’ to allow transformations of the encoded stream. This can
+    be used, for example, for the same use-cases as the WebRTC Insertable Streams API.
 
--   Various fixes for RHEL/CentOS 7 support
--   Added support for running on Linux ARM64
+-   gstwebrtc-api: JavaScript API for interacting with the default signalling protocol used by webrtcsink / webrtcsrc.
 
-Android
+… and various other smaller improvements!
 
--   Android support now requires Android API version 21 (Lollipop)
--   Support for Android Gradle plugin 7.2
+### RTSP
 
-Platform-specific changes and improvements
+-   New rtspsrc2 element. Only a subset of RTSP features are implemented so far:
+    -   RTSP 1.0 support
+    -   TCP, UDP, UDP-Multicast lower transports
+    -   RTCP SR, RTCP RR, RTCP-based A/V sync
+        -   Tested for correctness in multicast cases too
+    -   Lower transport selection and order (NEW!)
+        -   The existing rtspsrc has a hard-coded order list for lower transports
+    -   Many advanced features are not implemented yet, such as non-live support. See the README for the current status.
 
-Android
+### GTK4
 
--   Android SDK 21 is required now as minimum SDK version
+-   Support for rendering GL textures on X11/EGL, X11/GLX, Wayland, macOS, and WGL/EGL on Windows.
 
--   androidmedia: Add H.265 / HEVC video encoder mapping
+-   Create a window for testing purposes when running in gst-launch-1.0 or if GST_GTK4_WINDOW=1 is set.
 
--   Implement JNI_OnLoad() to register static plugins etc. automatically
-    in case GStreamer is loaded from Java using System.loadLibrary(),
-    which is also useful for the gst-full deployment scenario.
+-   New background-color property for setting the color of the background of the frame and the borders, if any. This also allows
+    setting a fully transparent background.
 
-Apple macOS and iOS
+-   New scale-filter property for defining how to scale the frames.
 
--   The GLib version shipped with the GStreamer binaries does not
-    initialize an NSApp and does not run a NSRunLoop on the main thread
-    anymore. This was a custom GLib patch and caused it to behave
-    different from the GLib shipped by Homebrew or anybody else.
+-   Add Python example application to the repository.
 
-    The change was originally introduced because various macOS APIs
-    require a NSRunLoop to run on the main thread to function correctly
-    but as this change will never get merged into GLib and it was
-    reverted for 1.22. Applications that relied on this behaviour should
-    move to the new gst_macos_main() function, which also does not
-    require the usage of a GMainLoop.
+-   Various bugfixes, including support for the new GTK 4.14 GL renderer. The plugin needs to be built with at least the
+    gtk_v4_10 feature to work with the new GTK 4.14 GL renderer, and will work best if built with the gtk_v4_14 feature.
 
-    See e.g. gst-play.c for an example for the usage of
-    gst_macos_main().
+### Closed Caption
 
--   GStreamer.framework and all libraries in it are now relocatable,
-    which means they use LC_RPATH entries to find dependencies instead
-    of using an absolute path. If you link to GStreamer using the
-    pkgconfig files, no action is necessary. However, if you use the
-    framework directly or link to the libraries inside the framework by
-    hand, then you need to pass -Wl,-rpath,<path_to_libdir> to the
-    linker.
+-   Add cea608tocea708 element for upconverting CEA-608 captions to their CEA-708 representation.
 
--   avfvideosrc: Allow specifying crop coordinates during screen capture
+-   Add support for translations within transcriberbin.
 
--   vtenc, vtdec: H.265 / HEVC video encoding + decoding support
+-   awstranscriber supports translating the transcribed text into different languages, including multiple languages at the same
+    time.
 
--   osxaudiosrc: Support a device as both input and output
+-   awstranscriber is using the new HTTP/2-based API now instead of the WebSocket-based one.
 
-    -   osxaudiodeviceprovider now probes devices more than once to
-        determine if the device can function as both an input AND and
-        output device. Previously, if the device provider detected that
-        a device had any output capabilities, it was treated solely as
-        an Audio/Sink. This caused issues for devices that have both
-        input and output capabilities (for example, USB interfaces for
-        professional audio have both input and output channels). Such
-        devicesare now listed as both an Audio/Sink as well as an
-        Audio/Source.
+### Other new elements
 
--   osxaudio: support hidden devices on macOS
+-   New awss3putobjectsink that works similar to awss3sink but with a different upload strategy.
 
-    -   These are devices that will not be shown in the macOS UIs and
-        that cannot be retrieved without having the specific UID of the
-        hidden device. There are cases when you might want to have a
-        hidden device, for example when having a virtual speaker that
-        forwards the data to a virtual hidden input device from which
-        you can then grab the audio. The blackhole project supports
-        these hidden devices and this change provides a way that if the
-        device id is a hidden device it will use it instead of checkinf
-        the hardware list of devices to understand if the device is
-        valid.
+-   New hlscmafsink element for writing HLS streams with CMAF/ISOBMFF fragments.
 
-Windows
+-   New inter plugin with new intersink and intersrc elements that allow to 1:N connect different pipelines in the same process.
+    This is implemented around the appsrc / appsink-based StreamProducer API that is provided as part of the GStreamer Rust
+    bindings, and is also used inside webrtcsrc and webrtcsink.
+
+-   New livesync element that allows maintaining a contiguous live stream without gaps from a potentially unstable source.
+
+-   New isomp4mux non-fragmented MP4 muxer element.
+
+### Other improvements
+
+-   audiornnoise
+    -   Attach audio level meta to output buffers.
+    -   Add voice detection threshold property
+-   fmp4mux
+    -   Add support for CMAF-style chunking, e.g. low-latency / LL HLS and DASH
+    -   Add support for muxing Opus, VP8, VP9 and AV1 streams
+    -   Add ‘offset-to-zero’ property and make media/track timescales configurable
+-   hlssink3
+    -   Allow adding EXT-X-PROGRAM-DATE-TIME tag to the manifest.
+    -   Allow generating I-frame-only playlist
+-   ndi
+    -   Closed Caption support in ndisrc / ndisink
+    -   Zero-copy output support in ndisrc for raw video and audio
+-   spotifyaudiosrc: Support configurable bitrate
+
+For a full list of changes in the Rust plugins see the gst-plugins-rs ChangeLog between versions 0.9 (shipped with GStreamer
+1.22) and 0.12 (shipped with GStreamer 1.24).
+
+## Cerbero Rust support
+
+-   As of GStreamer 1.24, the GStreamer Rust plugins are shipped as part of our binary packages on all major platforms. This
+    includes Android and iOS now in addition to macOS and Windows/MSVC.
+
+## Build and Dependencies
+
+-   Meson >= 1.1 is now required for all modules
+
+-   The GLib requirement has been bumped to >= 2.64
+
+-   liborc >= 0.4.38 is strongly recommended
+
+-   libnice >= 0.1.22 is strongly recommended, as it is required for WebRTC ICE consent freshness (RFC 7675).
+
+-   gst-libav was updated for FFmpeg API deprecations and removals
+
+-   libwebpmux is required for the animated WebP support
+
+-   The wpe plugin gained support for the WPEWebKit 2.0 API version
+
+-   Bumped minimum libva version to 1.12 for the va plugin.
+
+-   zxing: added support for the zxing-c++ 2.0 API
+
+-   The ptp-helper for Precision Time Protocol (PTP) support in GStreamer core has been rewritten in Rust, and the minimum
+    required Rust version for building this is 1.48, i.e. the version currently in Debian oldstable. On Windows, at least Rust
+    1.54 is needed. There is a new ptp-helper Meson feature option that can be used to make sure everything needed for PTP
+    support is available (if set to ptp-helper=enabled). cargo is not required for building.
+
+-   gst-plugins-rs requires Rust 1.70 or newer.
+
+-   Link to libsoup at build time in all cases on non-Linux, and only load it dynamically on Linux systems where we might need
+    to support a mix of applications with dependencies that might be using libsoup2 or libsoup3. A “soup-version” meson build
+    option was added to prefer a specific version. Distros should make sure that libsoup is still a package dependency, since
+    it’s still required at runtime for the soup and adaptivedemux2 plugins to function.
+
+-   libjack is now dynamically loaded at runtime by the JACK audio plugin, and no longer a hard build dependency. However, it
+    still is a runtime dependency, so distros should make sure it remains a package dependency.
+
+Monorepo build (née gst-build)
+
+-   There is now a top-level meson build option to enable/require webrtc
+
+-   The FFmpeg subproject wrap was udpated to 6.1
+
+-   A libvpx wrap was added (for VP8/VP9 software encoding/decoding)
+
+gstreamer-full
+
+-   Add full static build support, including on Windows: Allow a project to use gstreamer-full as a static library and link to
+    create a binary without dependencies. Introduce the meson build option gst-full-target-type to select the build type:
+    dynamic (default) or static.
+
+-   Registers all full features in a plugin now to offer the possibility to get information at the plugin level and get it from
+    the registry. All the full features are now registered in a fullstaticfeatures meta plugin instead of having a NULL plugin.
 
--   win32ipcvideosink, win32ipcvideosrc: new shared memory videosrc/sink
-    elements
+Development environment
 
--   wasapi2: Add support for process loopback capture for a specified
-    PID (requires Windows 11/Windows Server 2022)
+-   add VSCode IDE integration
 
--   The Windows universal UWP build is currently non-functional and will
-    need updating after the recent GLib upgrade. It is unclear if anyone
-    is using these binaries, so if you are please make yourself known.
+-   gst-env.py: Output a setting for the prompt with --only-environment
 
--   wicjpegdec, wicpngdec: Windows Imaging Component (WIC) based JPEG
-    and PNG decoder elements.
+### Cerbero
 
--   mfaacdec, mfmp3dec: Windows MediaFoundation AAC and MP3 decoders
+Cerbero is a meta build system used to build GStreamer plus dependencies on platforms where dependencies are not readily
+available, such as Windows, Android, iOS, and macOS.
 
--   The uninstalled development environment supports PowerShell 7 now
+General improvements
+
+-   New plugins have been added
+    -   codecalpha dvbsubenc rtponvif switchbin videosignal isac ivfparse inter rtspsrc2
+-   JACK plugin is now available all platforms (previously only Linux), and will be loaded if the JACK library is found at
+    plugin load time
+-   Several recipes were ported to meson, leading to faster builds and better MSVC support
+    -   ffmpeg, gperf, lame, libvpx, ogg, opencore-amr, sbc, speex, tiff, webrtc-audio-processing
+    -   For more information, please see the tracker issue
+-   Some recipes are now outdated or unnecessary and have been removed:
+    -   intltool, libkate
+-   Various recipe updated to their latest versions
+-   Rust toolchain updated to 1.76.0 (latest as of writing)
+-   Rust plugins are now stripped and debug info split out correctly, reducing their size
+-   Fix several spurious build issues, especially with the Rust toolchain
+-   CMake is picked up from the system if available
+-   Cerbero will no longer OOM or consume excessive resources on low-end systems
+-   Python recipes have been moved from setuptools to virtualenv
+-   Fixed support for Python 3.12+
+
+macOS
+
+-   Minimum macOS version has been increased to 10.13 (High Sierra)
+    -   Released 5½ years ago, >95% marketshare
+-   Fix macOS app store validation issue caused by absolute RPATHs
+-   Rosetta is automatically installed if required for universal builds on Apple Silicon
+-   The official macOS binaries now also include static libs for the GStreamer Rust plugins
+
+iOS
+
+-   Minimum iOS version has been increased to 12.0
+-   The iOS binary packages now include the GStreamer Rust plugins
+-   tremor and ivorbisdec plugins are no longer shipped on iOS
+
+Windows
+
+-   New features shipped with the official binaries:
+    -   plugins: dwrite d3d12 (MSVC) soundtouch (MSVC) taglib (MSVC) webrtcdsp (MSVC)
+    -   plugin features: d3d11-wgc (Windows Graphics Capture Support)
+    -   libraries: gstdxva-1.0
+-   New qml6 plugin can be built on Windows with the qt6 variant enabled
+    -   Similar to qt5, this plugin cannot be included in the official binaries
+-   GLib process handling helpers for Windows are now shipped
+-   Windows 11 SDK is now required for builds
+    -   Visual Studio 2019 and newer ship this SDK
+-   MSYS is now deprecated for building Windows binaries, will be removed in the next release
+    -   MSYS2 is required, and the bootstrap script tools/bootstrap-windows.ps can install it for you
+-   Windows bootstrap script tools/bootstrap-windows.ps1 is much more interactive and user-friendly now
+-   Fixed Pango crash on 32-bit Windows
+-   WiX packaging now works with cross-windows builds from linux
 
 Linux
 
--   Improved design for DMA buffer sharing and modifier handling for
-    hardware-accelerated video decoders/encoders/filters and
-    capture/rendering on Linux and Linux-like system.
+-   Linux packages will now also include static libs for the GStreamer Rust plugins
+-   Add Python support for multiarch distributions
+-   Build fixes for various recipes on multiarch distributions
+-   Use arch-specific libdir correctly on multiarch distributions
+-   gst-omx was removed from gstreamer, and hence is no longer shipped
+-   Fixed Gentoo support
+-   Added support for RHEL 9
+-   Added support for Rocky Linux
+-   Added support for Manjaro Linux
+
+Android
+
+-   Android NDK has been updated to r25c
+    -   Only the Clang toolchain is used from the NDK now (both target and host)
+    -   gnustl has been completely removed
+-   The Android binary packages now include the GStreamer Rust plugins
+-   tremor and ivorbisdec plugins are no longer shipped on Android
+-   openh264 plugin no longer enables ASM optimizations on Android x86 due to relocation errors
+
+## Platform-specific changes and improvements
+
+### Android
+
+-   Add NDK implementation of Android MediaCodec. This reduces the amount of Java <-> native calls, which should reduce
+    overhead.
+
+-   Add support for AV1 to the androidmedia video encoder and decoder.
+
+### Apple macOS and iOS
+
+-   osxaudio: audio clock improvements (interpolate based on system time)
+
+-   Set activation policy in gst_macos_main() and in osxvideosink and glimagesink. Setting the policy to
+    NSApplicationActivationPolicyAccessory by default makes sure that we can activate windows programmatically or by clicking on
+    them. Without that, windows would disappear if you clicked outside them and there would be no way to bring them to front
+    again. This change also allows osxvideosink to receive navigation events correctly.
+
+### Windows
 
--   kmssink
+-   New DirectWrite text rendering plugin with dwriteclockoverlay, dwritetimeoverlay, dwritetextoverlay, dwritesubtitlemux, and
+    dwritesubtitleoverlay elements, including closed caption overlay support in dwritetextoverlay.
 
-    -   new “fd” property which allows an application to provide their
-        own opened DRM device fd handle to kmssink. That way an
-        application can lease multiple fd’s from a DRM master to display
-        on different CRTC outputs at the same time with multiple kmssink
-        instances, for example.
-    -   new “skip-vsync” property to achieve full framerate with legacy
-        emulation in drivers.
-    -   HDR10 infoframe support
+-   PTP clock support is now also available on Windows
 
--   va plugin and gstreamer-vaapi improvements (see above)
+-   qml6d3d11sink is a new Direct3D11 Qt6 QML sink for Windows as an alternative to the existing qml6glsink.
 
--   waylandsink: Add “rotate-method” property and “render-rectangle”
-    property
+-   wasapi2 audio plugin:
 
--   new gtkwaylandsink element based on gtksink, but similar to
-    waylandsink and uses Wayland APIs directly instead of rendering with
-    Gtk/Cairo primitives. This approach is only compatible with Gtk3,
-    and like gtksink this element only supports Gtk3.
+    -   Added an option to monitor a loopback device’s mute state
+    -   Allows process loopback capture on Windows 10
 
-Documentation improvements
+-   win32ipc supports zero-copy rendering now through a shared bufferpool.
 
--   The GStreamer Rust plugins are now included and documented in the
-    plugin documentation.
+-   Add a Windows-specific plugin loader implementation (gst-plugin-scanner), so plugin loading during registry updates happens
+    in an external process on Windows as well.
 
-Possibly Breaking Changes
+-   gst_video_convert_sample() which is often used for thumbnailing gained a D3D11 specific conversion path.
 
--   the Opus audio RTP payloader and depayloader no longer accept the
-    lower case encoding-format=multiopus but instead produce and accept
-    only the upper case variant encoding-format=MULTIOPUS, since those
-    should always be upper case in GStreamer (caps fields are always
-    case sensitive). This should hopefully only affect applications
-    where RTP caps are set manually and multi-channel audio (>= 3
-    channels) is used.
+-   d3d11 plugin:
 
--   wpesrc: the URI handler protocols changed from wpe:// and web:// to
-    web+http://, web+https://, and web+file:// which means URIs are RFC
-    3986 compliant and the source can simply strip the prefix from the
-    protocol.
+    -   d3d11mpeg2dec element is promoted to PRIMARY + 1 rank
+    -   Added d3d11ipcsrc and d3d11ipcsink elements for zero-copy GPU memory sharing between multiple processes.
+    -   Added HLSL shader pre-compilation (at binary build time) support in MSVC build.
+    -   d3d11videosink and d3d11convert elements support 3D transform, MSAA (MultiSampling Anti-Aliasing) and anisotropic
+        sampling method.
+    -   Added support for more raw video formats by using compute shader. A list of supported raw video formats can be found in
+        the d3d11videosink plugin documentation.
+    -   Added d3d11overlay element for applications to be able to draw/blend an overlay image on Direct3D11 texture directly.
 
--   The Windows screen capture element dxgiscreencapsrc has been
-    removed, please use d3d11screencapturesrc instead.
+-   New Direct3D12 plugin: From a video decoding, conversion, composition, and rendering point of view, this new d3d12 plugin is
+    feature-wise near equivalent to the d3d11 plugin. Notable differences between d3d12 and d3d11 are:
+    -   The GStreamer Direct3D12 integration layer is not exposed as a GStreamer API yet. Thus, other plugins such as amfcodec,
+        nvcodec, qsv, and dwrite are not integrated with d3d12 yet.
+    -   H.264 video encoding support via d3d12h264enc element.
+        -   Direct3D12 video encoding API requires Windows 11 or DirectX 12 Agility SDK
+    -   IPC, overlay, and deinterlace elements are not implemented in d3d12
+    -   Windows Graphics Capture API based screen capturing is not implemented in d3d12
+    -   In this release, MSVC is the only officially supported toolchain for the d3d12 plugin build.
+    -   All d3d12 elements are zero ranked for now. Users will need to adjust rank of each d3d12 element via GST_PLUGIN_RANK
+        environment or appropriate plugin feature APIs if they want these elements autoplugged.
 
--   On Android the minimum supported Android API version is now version
-    21 and has been increased from 16.
+## Documentation improvements
 
--   On macOS, the GLib version shipped with the GStreamer binaries will
-    no longer initialize an NSApp or run an NSRunLoop on the main
-    thread. See macOS/iOS section above for details.
+-   hotdoc has been updated to the latest version, and the theme has also been updated, which should fix various usability
+    issues.
 
--   decklink: The decklink plugin is now using the 12.2.2 version of the
-    SDK and will not work with drivers older than version 12.
+## Possibly Breaking Changes
 
--   On iOS Apple Bitcode support was removed from the binaries. This
-    feature is deprecated since XCode 14 and not used on the App Store
-    anymore.
+-   gst_plugin_feature_check_version() has been updated to fix unexpected version check behaviour for git versions. It would
+    return TRUE if the plugin version is for a git development version (e.g. 1.24.0.1) and the check is for the “next” micro
+    version (1.24.1). Now it no longer does this. This just brings the runtime version check in line with the build time version
+    checks which have been fixed some time ago.
 
--   The MP4/Matroska/WebM muxers now require the “stream-format” to be
-    provided as part of the AV1 caps as only the original “obu-stream”
-    format is supported in these containers and not the “annexb” format.
+-   GstAudioAggregator and subclasses such as audiomixer now sync property values to output timestamp, which is what
+    GstVideoAggregator has been doing already since 2019, and which makes sense, as the properties need to change at every
+    output frame based on the output time because they may change even though the input frame is not changing.
 
-Known Issues
+-   rtpac3depay now outputs audio/x-ac3 instead of audio/ac3 as that is the canonical media format in GStreamer. audio/ac3 is
+    still sometimes accepted as input format for backwards compatibility (e.g. in rtpac3pay or ac3parse), but shouldn’t be
+    output.
 
--   The Windows UWP build in Cerbero needs fixing after the recent GLib
-    upgrade (see above)
+-   timecodestamper: The “drop-frame” property now defaults to TRUE
 
--   The C# bindings have not been updated to include new 1.22 API yet
-    (see above)
+-   The NVIDIA desktop GPU decoders nvh264sldec, nvh265sldec, nvvp8sldec and nvvp9sldec were renamed to nvh264dec, nvh265dec,
+    nvvp8dec and nvvp9dec, respectively.
 
-Statistics
+## Known Issues
 
--   4072 commits
+-   There are known issues with FFmpeg version 6.0.0 due to opaque passing being broken in that version. This affects at least
+    avdec_h264, but may affect other decoders as well. Versions before 6.0.0, and 6.0.1 or higher are not affected.
 
--   2224 Merge Requests
+-   gst-libav < 1.24.6 didn’t build against the latest FFmpeg 7.0 release. This has been worked on and tracked in this “libav:
+    Fix compatibility with ffmpeg 7” Merge Request.
 
--   716 Issues
+## Statistics
 
--   200+ Contributors
+-   4643 commits
 
--   ~33% of all commits and Merge Requests were in Rust modules
+-   2405 Merge Requests
+
+-   850 Issues
+
+-   290+ Contributors
+
+-   ~25% of all commits and Merge Requests were in Rust modules
 
 -   4747 files changed
 
@@ -1155,85 +1299,1891 @@ Statistics
 
 -   259791 lines added (net)
 
-Contributors
-
-Ádám Balázs, Adam Doupe, Adrian Fiergolski, Adrian Perez de Castro, Alba
-Mendez, Aleix Conchillo Flaqué, Aleksandr Slobodeniuk, Alicia Boya
-García, Alireza Miryazdi, Andoni Morales Alastruey, Andrew Pritchard,
-Arun Raghavan, A. Wilcox, Bastian Krause, Bastien Nocera, Benjamin
-Gaignard, Bill Hofmann, Bo Elmgreen, Boyuan Zhang, Brad Hards, Branko
-Subasic, Bruce Liang, Bunio FH, byran77, Camilo Celis Guzman, Carlos
-Falgueras García, Carlos Rafael Giani, Célestin Marot, Christian Wick,
-Christopher Obbard, Christoph Reiter, Chris Wiggins, Chun-wei Fan, Colin
-Kinloch, Corentin Damman, Corentin Noël, Damian Hobson-Garcia, Daniel
-Almeida, Daniel Morin, Daniel Stone, Daniels Umanovskis, Danny Smith,
-David Svensson Fors, Devin Anderson, Diogo Goncalves, Dmitry Osipenko,
-Dongil Park, Doug Nazar, Edward Hervey, ekwange, Eli Schwartz, Elliot
-Chen, Enrique Ocaña González, Eric Knapp, Erwann Gouesbet, Evgeny
-Pavlov, Fabian Orccon, Fabrice Fontaine, Fan F He, F. Duncanh, Filip
-Hanes, Florian Zwoch, François Laignel, Fuga Kato, George Kiagiadakis,
-Guillaume Desmottes, Gu Yanjie, Haihao Xiang, Haihua Hu, Havard Graff,
-Heiko Becker, He Junyan, Henry Hoegelow, Hiero32, Hoonhee Lee, Hosang
-Lee, Hou Qi, Hugo Svirak, Ignacio Casal Quinteiro, Ignazio Pillai, Igor
-V. Kovalenko, Jacek Skiba, Jakub Adam, James Cowgill, James Hilliard,
-Jan Alexander Steffens (heftig), Jan Lorenz, Jan Schmidt, Jianhui Dai,
-jinsl00000, Johan Sternerup, Jonas Bonn, Jonas Danielsson, Jordan
-Petridis, Joseph Donofry, Jose Quaresma, Julian Bouzas, Junsoo Park,
-Justin Chadwell, Khem Raj, Krystian Wojtas, László Károlyi, Linus
-Svensson, Loïc Le Page, Ludvig Rappe, Marc Leeman, Marek Olejnik, Marek
-Vasut, Marijn Suijten, Mark Nauwelaerts, Martin Dørum, Martin Reboredo,
-Mart Raudsepp, Mathieu Duponchelle, Matt Crane, Matthew Waters, Matthias
-Clasen, Matthias Fuchs, Mengkejiergeli Ba, MGlolenstine, Michael Gruner,
-Michiel Konstapel, Mikhail Fludkov, Ming Qian, Mingyang Ma, Myles
-Inglis, Nicolas Dufresne, Nirbheek Chauhan, Olivier Crête, Pablo Marcos
-Oltra, Patricia Muscalu, Patrick Griffis, Paweł Stawicki, Peter
-Stensson, Philippe Normand, Philipp Zabel, Pierre Bourré, Piotr
-Brzeziński, Rabindra Harlalka, Rafael Caricio, Rafael Sobral, Rafał
-Dzięgiel, Raul Tambre, Robert Mader, Robert Rosengren, Rodrigo
-Bernardes, Rouven Czerwinski, Ruben Gonzalez, Sam Van Den Berge,
-Sanchayan Maity, Sangchul Lee, Sebastian Dröge, Sebastian Fricke,
-Sebastian Groß, Sebastian Mueller, Sebastian Wick, Sergei Kovalev,
-Seungha Yang, Seungmin Kim, sezanzeb, Sherrill Lin, Shingo Kitagawa,
-Stéphane Cerveau, Talha Khan, Taruntej Kanakamalla, Thibault Saunier,
-Tim Mooney, Tim-Philipp Müller, Tomasz Andrzejak, Tom Schuring, Tong Wu,
-toor, Tristan Matthews, Tulio Beloqui, U. Artie Eoff, Víctor Manuel
-Jáquez Leal, Vincent Cheah Beng Keat, Vivia Nikolaidou, Vivienne
-Watermeier, WANG Xuerui, Wojciech Kapsa, Wonchul Lee, Wu Tong, Xabier
-Rodriguez Calvar, Xavier Claessens, Yatin Mann, Yeongjin Jeong, Zebediah
-Figura, Zhao Zhili, Zhiyuaniu, مهدي شينون (Mehdi Chinoune),
-
-… and many others who have contributed bug reports, translations, sent
-suggestions or helped testing.
-
-Stable 1.22 branch
-
-After the 1.22.0 release there will be several 1.22.x bug-fix releases
-which will contain bug fixes which have been deemed suitable for a
-stable branch, but no new features or intrusive changes will be added to
-a bug-fix release usually. The 1.22.x bug-fix releases will be made from
-the git 1.22 branch, which will be a stable branch.
-
-1.22.0
-
-1.22.0 was originally released on 23 January 2023.
-
-Schedule for 1.24
-
-Our next major feature release will be 1.24, and 1.23 will be the
-unstable development version leading up to the stable 1.24 release. The
-development of 1.23/1.24 will happen in the git main branch of the
-GStreamer mono repository.
-
-The plan for the 1.24 development cycle is yet to be confirmed.
-
-1.24 will be backwards-compatible to the stable 1.22, 1.20, 1.18, 1.16,
-1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series.
-
-------------------------------------------------------------------------
-
-These release notes have been prepared by Tim-Philipp Müller with
-contributions from Edward Hervey, Matthew Waters, Nicolas Dufresne,
-Nirbheek Chauhan, Olivier Crête, Sebastian Dröge, Seungha Yang, and
-Thibault Saunier.
+## Contributors
+
+Aaron Boxer, Aaron Huang, Acky Xu, adixonn, Adrian Fiergolski, Adrien De Coninck, Akihiro Sagawa, Albert Sjölund, Alessandro
+Bono, Alexande B, Alexander Slobodeniuk, Alicia Boya García, amindfv, Amir Naghdinezhad, anaghdin, Anders Hellerup Madsen,
+Andoni Morales Alastruey, Antonio Kevo, Antonio Rojas, Arnaud Rebillout, Arnaud Vrac, Arun Raghavan, badcel, Balló György, Bart
+Van Severen, Bastien Nocera, Benjamin Gaignard, Bilal Elmoussaoui, Brad Hards, Camilo Celis Guzman, Carlo Cabrera, Carlos
+Falgueras García, Carlos Rafael Giani, Célestin Marot, Chao Guo, Charlie Blevins, Cheah, Vincent Beng Keat, Chris Degawa, Chris
+Spencer, Christian Curtis Veng, Christian Meissl, Christopher Degawa, Chris Wiggins, Cidana-Developers, Colin Kinloch, Damian
+Hobson-Garcia, Daniel Almeida, Daniel Knobe, Daniel Moberg, Daniel Morin, Daniel Pendse, Daniel Stone, Daniel Ulery, Dan
+Searles, Dario Marino Saccavino, Dave Patrick Caberto, David Craven, David Revay, David Rosca, David Svensson Fors, Detlev
+Casanova, Diego Nieto, Dominique Leroux, Dongyun Seo, Doug Nazar, Edward Hervey, Ekwang Lee, elenril, Elliot Chen, Enrique Ocaña
+González, Erik Fröbrant, Eva Pace, Evgeny Pavlov, Fabian Orccon, Felix Yan, Fernando Jiménez Moreno, Florian Zwoch, François
+Laignel, Frank Dana, Georges Basile Stavracas Neto, Guillaume Desmottes, Guillaume Gomez, Gwyn Ciesla, Haihua Hu, Hassene Tmar,
+hassount, Heiko Becker, He Junyan, hguermaz, Hiero32, Hosang Lee, Hou Qi, Hugo Svirak, Hugues Fruchet, Hu Qian, Hyung Song,
+Ignazio Pillai, Ilie Halip, Itamar Marom, Ivan Molodetskikh, Ivan Tishchenko, JackZhouVCD, Jacob Johnsson, jainl28patel, Jakub
+Adam, James Cowgill, James Hilliard, James Oliver, Jan Alexander Steffens (heftig), Jan Beich, Jan Schmidt, Jan Vermaete, Jayson
+Reis, Jeff Wilson, Jeongki Kim, Jeri Li, Jimmi Holst Christensen, Jimmy Ohn, Jochen Henneberg, Johan Adam Nilsson, Johan
+Sternerup, John King, Jonas Danielsson, Jonas K Danielsson, Jonas Kvinge, Jordan Petridis, Jordan Yelloz, Josef Kolář, Juan
+Navarro, Julien Isorce, Jun Zhao, Jurijs Satcs, Kalev Lember, Kamal Mostafa, kelvinhu325, Kevin Song, Khem Raj, Kourosh
+Firoozbakht, Leander Schulten, Leif Andersen, L. E. Segovia, Lieven Paulissen, lijing0010, Lily Foster, Link Mauve, Li Yuanheng,
+Loïc Le Page, Loïc Molinari, Lukas Geiger, Luke McGartland, Maksym Khomenko, Ma, Mingyang, Manel J, Marcin Kolny, Marc Leeman,
+Marc Solsona, Marc Wiblishauser, Marek Vasut, Marijn Suijten, Mark Hymers, Markus Ebner, Martin Nordholts, Martin Robinson, Mart
+Raudsepp, Marvin Schmidt, Mathieu Duponchelle, Matt Feury, Matthew Waters, Matthias Fuchs, Matthieu Volat, Maxim P. Dementyev,
+medithe, Mengkejiergeli Ba, Michael Bunk, Michael Gruner, Michael Grzeschik, Michael Olbrich, Michael Tretter, Michiel
+Westerbeek, Mihail Ivanchev, Ming Qian, Nader Mahdi, naglis, Nick Steel, Nicolas Beland, Nicolas Dufresne, Nirbheek Chauhan,
+Olivier Babasse, Olivier Blin, Olivier Crête, Omar Khlif, Onur Demiralay, Patricia Muscalu, Paul Fee, Pawel Stawicki, Peter
+Stensson, Philippe Normand, Philipp Zabel, PhoenixWorthVCD, Piotr Brzeziński, Priit Laes, Qian Hu, Rabindra Harlalka, Rafał
+Dzięgiel, Rahul T R, rajneeshksoni, Ratchanan Srirattanamet, renjun wang, Rhythm Narula, Robert Ayrapetyan, Robert Mader, Robert
+Rosengren, Robin Gustavsson, Roman Lebedev, Rouven Czerwinski, Ruben Gonzalez, Ruslan Khamidullin, Ryan Pavlik, Sanchayan Maity,
+Sangchul Lee, Scott Kanowitz, Scott Moreau, SeaDve, Sean DuBois, Sebastian Dröge, Sebastian Szczepaniak, Sergey Radionov,
+Seungha Yang, Shengqi Yu, Simon Himmelbauer, Slava Andrejev, Slawomir Pawlowski, soak, Stefan Brüns, Stéphane Cerveau, Stephan
+Seitz, Stijn Last, Talha Khan, Taruntej Kanakamalla, Jin Chung Teng, Théo Maillart, Thibault Saunier, Thomas Schneider,
+Tim-Philipp Müller, Tobias Rapp, Tong Wu, Tristan van Berkom, ttrigui, U. Artie Eoff, utzcoz, Víctor Manuel Jáquez Leal, Vivia
+Nikolaidou, Wang Chuan, William Manley, Wojciech Kapsa, Xabier Rodriguez Calvar, Xavier Claessens, Xuchen Yang, Yatin Maan,
+Yinhang Liu, Yorick Smilda, Yuri Fedoseev, Gang Zhao, Jack Zhou, …
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+Stable 1.24 branch
+
+After the 1.24.0 release there will be several 1.24.x bug-fix releases which will contain bug fixes which have been deemed
+suitable for a stable branch, but no new features or intrusive changes will be added to a bug-fix release usually. The 1.24.x
+bug-fix releases will be made from the git 1.24 branch, which will be a stable branch.
+
+1.24.0
+
+GStreamer 1.24.0 was released on 4 March 2024.
+
+1.24.1
+
+The first 1.24 bug-fix release (1.24.1) was released on 21 March 2024.
+
+This release only contains bugfixes and it should be safe to update from 1.24.0.
+
+Highlighted bugfixes in 1.24.1
+
+-   Fix instant-EOS regression in audio sinks in some cases when volume is 0
+-   rtspsrc: server compatibility improvements and ONVIF trick mode fixes
+-   rtsp-server: fix issues if RTSP media was set to be both shared and reusable
+-   (uri)decodebin3 and playbin3 fixes
+-   adaptivdemux2/hlsdemux2: Fix issues with failure updating playlists
+-   mpeg123 audio decoder fixes
+-   v4l2codecs: DMA_DRM caps support for decoders
+-   va: various AV1 / H.264 / H.265 video encoder fixes
+-   vtdec: fix potential deadlock regression with ProRes playback
+-   gst-libav: fixes for video decoder frame handling, interlaced mode detection
+-   avenc_aac: support for 7.1 and 16 channel modes
+-   glimagesink: Fix the sink not always respecting preferred size on macOS
+-   gtk4paintablesink: Fix scaling of texture position
+-   webrtc: Allow resolution and framerate changes, and many other improvements
+-   webrtc: Add new LiveKit source element
+-   Fix usability of binary packages on arm64 iOS
+-   various bug fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   registry, ptp: Canonicalize the library path returned by dladdr
+-   segment: Don’t use g_return_val_if_fail() in gst_segment_to_running_time_full()
+-   uri: Sort uri protocol sources/sinks by feature name to break a feature rank tie
+-   ptp: Initialize expected DELAY_REQ seqnum to an invalid value
+-   ptp: Don’t install test executable
+-   gst-inspect: fix –exists for plugins with versions other than GStreamer’s version, like the Rust plugins
+-   identity: Don’t refuse seeks unless single-segment=true
+
+gst-plugins-base
+
+-   audiobasesink: Don’t wait on gap events
+-   audioencoder: Avoid using temporarily mapped memory as base for input buffers
+-   decodebin3: Be more specific when sending missing plugin messages
+-   decodebin3: Fix re-usability issues
+-   decodebin3: Provide clear error message if no decoders present
+-   playbin3: Remove un-needed URI NULL check
+-   uridecodebin3: Don’t hold lock when posting messages or signals
+-   uridecodebin3: Handle potential double redirection errors
+-   glimagesink: Fix the sink not always respecting preferred size on macOS
+-   glupload: Do not propose allocators with sysmem, fixes warning when playing VP9 with alpha
+-   shmallocator: fix build on Illumos
+-   meson: Fix the condition to skip theoradec test
+
+gst-plugins-good
+
+-   adaptivdemux/hlsdemux2: Fix issues with failure updating playlists
+-   mpg123audiodec: Correctly handle the case of clipping all decoded samples
+-   mpg123audiodec: gst_audio_decoder_allocate_output_buffer: assertion ‘size > 0’ failed
+-   qt: Fix description in meson build options
+-   qtdemux: Do not set channel-mask to zero
+-   rtspsrc: remove ‘deprecated’ flag from the ‘push-backchannel-sample’ signal
+-   rtspsrc: Consider 503 Service Not Available when handling broken control urls
+-   rtspsrc, rtponviftimestamp: ONVIF mode fixes
+-   rtspsrc: Don’t invoke close when stopping if we’ve started cleanup, fixing potential crash on shutdown
+-   rtpgstpay: Delay pushing of event packets until the next buffer
+
+gst-plugins-bad
+
+-   asio: Fix {input,output}-channels property handling
+-   cuda,d3d11,d3d12bufferpool: Disable preallocation
+-   d3d11device: Fix adapter LUID comparison in wrapped device mode
+-   d3d12device: Fix IDXGIFactory2 leak
+-   d3d12: Fix SDK debug layer activation
+-   dvbsubenc: Fix bottom field size calculation
+-   dvdspu: avoid null dereference
+-   GstPlay: Fix a critical warning in error callback
+-   v4l2codecs: decoders: Add DMA_DRM caps support
+-   vaav1enc: Init the output_frame_num when resetting gf group
+-   vah264enc, vah265enc, vaav1enc: fix potential crash on devices without rate control
+-   vah265enc: checking surface alignment
+-   videoparsers: Don’t verbosely warn about CEA_708_PROCESS_EM_DATA_FLAG not being set
+-   vtdec: Fix a deadlock during ProRes playback, handle non-linked gracefully
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+-   gtk4paintablesink: Fix scaling of texture position
+-   janusvrwebrtcsink: Handle 64 bit numerical room ids
+-   janusvrwebrtcsink: Don’t include deprecated audio/video fields in publish messages
+-   janusvrwebrtcsink: Handle various other messages to avoid printing errors
+-   livekitwebrtc: Fix shutdown behaviour
+-   rtpgccbwe: Don’t forward buffer lists with buffers from different SSRCs to avoid breaking assumptions in rtpsession
+-   sccparse: Ignore invalid timecodes during seeking
+-   webrtcsink: Don’t try parsing audio caps as video caps
+-   webrtc: Allow resolution and framerate changes
+-   webrtcsrc: Make producer-peer-id optional
+-   livekitwebrtcsrc: Add new LiveKit source element
+-   regex: Add support for configuring regex behaviour
+-   spotifyaudiosrc: Document how to use with non-Facebook accounts
+-   webrtcsrc: Add do-retransmission property
+
+gst-libav
+
+-   avcodecmap: Increase max AAC channels to 16
+-   avviddec: Fix how we get back the codec frame
+-   avviddec: Fix interlaced mode detection
+-   avviddec: Double check if AV_CODEC_FLAG_COPY_OPAQUE port is safe for our scenario
+
+gst-rtsp-server
+
+-   media: gst_rtsp_media_set_reusable() and gst_rtsp_media_set_shared() have become incompatible
+-   rtsp-stream: clear sockets when leaving bin
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   ges: Fix critical warning
+
+gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.24.1
+
+-   gstreamer: Enable ptp helper explicitly
+-   gst-plugins-bad: Package new insertbin plugin
+-   gst-plugins-rs: Adjust parallel architecture build blocks
+-   libnice: update to 0.1.22
+-   pixman: Bump to 0.43.4
+-   orc: disable JIT code generation on arm64 on iOS again, fixing crashes
+
+Contributors to 1.24.1
+
+Alexander Slobodeniuk, Antonio Larrosa, Edward Hervey, Elizabeth Figura, François Laignel, Guillaume Desmottes, He Junyan, Jan
+Schmidt, Jordan Yelloz, L. E. Segovia, Mark Nauwelaerts, Mathieu Duponchelle, Michael Tretter, Mikhail Rudenko, Nicolas
+Dufresne, Nirbheek Chauhan, Philippe Normand, Piotr Brzeziński, Robert Mader, Ruijing Dong, Sebastian Dröge, Seungha Yang,
+Thomas Goodwin, Thomas Klausner, Tim-Philipp Müller, Xi Ruoyao,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.1
+
+-   List of Merge Requests applied in 1.24.1
+-   List of Issues fixed in 1.24.1
+
+1.24.2
+
+The second 1.24 bug-fix release (1.24.2) was released on 9 April 2024.
+
+This release only contains bugfixes and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.2
+
+-   H.264 parsing regression fixes
+-   WavPack typefinding improvements
+-   Video4linux fixes and improvements
+-   Android build and runtime fixes
+-   macOS OpenGL memory leak and robustness fixes
+-   Qt/QML video sink fixes
+-   Package new analytics and mse libraries in binary packages
+-   Windows MSVC binary packages: fix libvpx avx/avx2/avx512 instruction set detection
+-   various bug fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   clock: Block futex_time64 usage on Android API level < 30
+-   basesrc: Clear submitted buffer lists consistently with buffers
+-   ptpclock: fix double free of domain data during deinit
+-   clocksync: Proxy allocation queries
+-   inputselector: fix possible clock leak on shutdown
+-   typefind: Handle WavPack block sizes > 131072
+
+gst-plugins-base
+
+-   glcolorconvert: Ensure glcolorconvert does not miss supported RGB formats
+-   gl/macos: a couple of race/reference count fixes
+-   pbutils: descriptions: Don’t warn on MPEG-1 audio caps without layer field
+-   encodebin: Add the parser before timestamper to tosync list
+-   videorate: Reset last_ts when a new segment is received
+
+gst-plugins-good
+
+-   qml6glsink: fix destruction of underlying texture
+-   qt/qt6: Fixup for dummy textures
+-   rtpjitterbuffer: Don’t use estimated_dts to do default skew adjustment
+-   rtpjitterbuffer: Use an extended RTP timestamp for the clock-base
+-   rtpmp4adepay: Set duration on outgoing buffers
+-   tests: rtpred: fix out-of-bound writes
+-   v4l2: allocator: Fix unref log/trace on memory release
+-   v4l2: Also set max_width/max_width if enum framesize fail
+-   v4l2: enforce a pixel aspect ratio of 1/1 if no data are available
+-   v4l2: fix error in calculating padding bottom for tile format
+-   v4l2src: need maintain the caps order in caps compare when fixate
+-   vpxenc: Include vpx error details in errors and warnings
+
+gst-plugins-bad
+
+-   h264parse: element hangs with some video streams (regression)
+-   h264parse: Revert “AU boundary detection changes”
+-   alphadecodebin: Explicitly pass 64 bit integers as such through varargs
+-   atdec: Set a channel mask for channel counts greater than 2
+-   ccconverter: Fix caps leak and remove unnecessary code
+-   d3d11videosink: disconnect signals before releasing the window
+-   d3d11: meson: Add support for MinGW DirectXMath package and update directxmath wrap to 3.1.9
+-   d3d11: meson: Disable library build if DirectXMath header was not found
+-   dwrite: Fix crash on device update
+-   GstPlay: Update video_snapshot to support playbin3
+-   jpegparse: avi1 tag can be progressive
+-   jpegparse: turn some bus warnings into object ones
+-   qsvdecoder: Release too old frames
+-   ristsrc: Only free caps if needed
+-   va: av1enc: Correct the reference number and improve the reference setting
+-   va: {vp9, av1}enc: Avoid reopen encoder or renegotiate
+-   videoparsers: Demote CC warning message
+-   vkbufferpool: correct usage flags type
+-   vkh26xdec: a couple decoding fixes
+-   vtdec: Fix caps criticals during negotiation
+-   wpe: avoid crash with G_DEBUG=fatal_criticals and static build
+-   Sink missing floating references
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+-   aws: use fixed BehaviorVersion
+-   aws: improve error message logs
+-   fmp4: Update to dash-mpd 0.16
+-   fmp4mux: Require gstreamer-pbutils 1.20 for the examples
+-   onvifmetadataparse: Reset state in PAUSED->READY after pad deactivation, fixing occasional deadlock on shutdown
+-   reqwest: Update to reqwest 0.12
+-   webrtcsink: set perfect-timestamp=true on audio encoders
+-   webrtcsink: improve panic message on unexpected caps during discovery
+-   webrtchttp: Update to reqwest 0.12
+-   webrtc: fix inconsistencies in documentation of object names
+-   Fix clippy warnings after upgrade to Rust 1.77
+
+gst-libav
+
+-   avviddec: Fix AVPacket leak
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   ges: frame-composition-meta: Stop using keyword ‘operator’ for field in C++
+
+gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   webrtc examples: set perfect-timestamp=true on opusenc for better Chrome interoperability
+
+Development build environment
+
+-   flac: Add subproject wrap and allow falling back to it in the flac plugin
+-   libnice: bump subproject wrap to v0.1.22 (needed for ICE consent freshness support in gstwebrtc)
+
+Cerbero build tool and packaging changes in 1.24.2
+
+-   glib: Block futex_time64 usage on Android API level < 30
+-   libvpx: Fix build with Python 3.8
+-   libvpx: Fix errors with avx* instruction set detection for x86* builds and MSVC
+-   openjpeg: Update to 2.5.2
+-   directxmath: Update to 3.1.9
+-   gst-plugins-rs: Fix superstripping for ELF breaking all plugins
+-   Rust-based plugin initialization hangs on Android with GStreamer 1.24.0
+
+Contributors to 1.24.2
+
+Alexander Slobodeniuk, Arnaud Vrac, Chao Guo, Chris Spencer, Daniel Morin, Edward Hervey, Elizabeth Figura, Elliot Chen, eri,
+François Laignel, Guillaume Desmottes, Haihua Hu, He Junyan, Hou Qi, Jan Schmidt, Jochen Henneberg, L. E. Segovia, Martin
+Nordholts, Matthew Waters, Nicolas Dufresne, Philippe Normand, Philipp Zabel, Piotr Brzeziński, Robert Guziolowski, Robert
+Mader, Ruben Gonzalez, Sebastian Dröge, Seungha Yang, Taruntej Kanakamalla, Thibault Saunier, Tim Blechmann, Tim-Philipp Müller,
+Víctor Manuel Jáquez Leal, Wojciech Kapsa, Xavier Claessens,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.2
+
+-   List of Merge Requests applied in 1.24.2
+-   List of Issues fixed in 1.24.2
+
+1.24.3
+
+The third 1.24 bug-fix release (1.24.3) was released on 30 April 2024.
+
+This release only contains bugfixes and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.3
+
+-   EXIF image tag parsing security fixes
+-   Subtitle handling improvements in parsebin
+-   Fix issues with HLS streams that contain VTT subtitles
+-   Qt6 QML sink re-render and re-sizing fixes
+-   unixfd ipc plugin timestamp and segment handling fixes
+-   vah264enc, vah265enc: Do not touch the PTS of the output frame
+-   vah264dec and vapostproc fixes and improvements
+-   v4l2: multiple fixes and improvements, incl. for mediatek JPEG decoder and v4l2 loopback
+-   v4l2: fix hang after seek with some v4l2 decoders
+-   Wayland sink fixes
+-   ximagesink: fix regression on RPi/aarch64
+-   fmp4mux, mp4mux gained FLAC audio support
+-   D3D11, D3D12: reliablity improvements and memory leak fixes
+-   Media Foundation device provider fixes
+-   GTK4 paintable sink improvements including support for directly importing dmabufs with GTK 4.14
+-   WebRTC sink/source fixes and improvements
+-   AWS s3sink, s3src, s3hlssink now support path-style addressing
+-   MPEG-TS demuxer fixes
+-   Python bindings fixes
+-   various bug fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   ptp: Silence Rust compiler warning about some unused trait methods
+
+gst-plugins-base
+
+-   EXIF image tag parsing security fixes
+-   glcolorconvert: remove some dead code
+-   parsebin: Ensure non-time subtitle streams get “parsed”
+-   playbin3: Handle combiner update in case of errors
+-   ximagesink: initialize mask for XISelectEvents
+
+gst-plugins-good
+
+-   adaptivedemux2: Playback hangs with VTT fragments
+-   adaptivedemux2: Avoid double usage of parsebin
+-   pulsedeviceprovider: Add compare_device_type_name function and missing lock
+-   qml6glsink: Notify that the returned QSGNode node has changes
+-   qml6glsink: video content resizes to new item size
+-   qtdemux: fix wrong full_range offset when parsing colr box
+-   soup: fix thread name
+-   v4l2: add multiplane y42b (yuv422m) support (for mediatek v4l2 jpeg decoder)
+-   v4l2: bufferpool: Drop writable check on output pool process
+-   v4l2: bufferpool: Ensure freshly created buffers are not marked as queued, fixing issues with v4l2sink on a v4l2loopback
+    device
+-   v4l2: bufferpool: queue back the buffer flagged LAST but empty, fixes hangs after seek with some decoders
+-   v4l2: silence valgrind warning
+-   vpx: Include vpx error details in errors and warnings
+
+gst-plugins-bad
+
+-   d3d11device: protect device_lock vs device_new
+-   d3d11decoder, d3d12decoder: Fix potential use after free
+-   d3d11videosink: Fix rendering on keyed mutex enabled handle
+-   d3d12decoder: Fix d3d12 resource copy
+-   d3d12encoder: Fix buffer pool leak
+-   d3d12videosink: HWND event handling related fixes
+-   d3d12vp9dec: Fix Intel GPU crash occurred when decoding VP9 SVC
+-   dvbsubenc: fixed some memory leaks and a crash
+-   GstPlay: fix read duration failure issue for some type rtsp streams which have valid duration
+-   mediafoundation: Fix device enumeration
+-   mediafoundation: Fix infinite loop in device provider
+-   tests: fix possible libscpp build failure in gst-plugins-bad
+-   tsdemux, tsparse: Fix Program equality check
+-   tsdemux: Disable smart program update
+-   unixfdsink: Take segment into account when converting timestamps
+-   va: videoformat: use video library to get DRM fourcc
+-   va: radeonsi: DRM RGB formats doesn’t look correctly mapped to VA formats
+-   vah264enc, vah265enc: Do not touch the PTS of output frame
+-   vaav1enc: Change the alignment of output to “tu”
+-   vaallocator: disable derived all together for Mesa <23.3
+-   waylandsink: free staged buffer when do gst_wl_window_finalize
+-   wlwindow: clear configure mutex and cond when finalize
+-   waylandsink: config buffer pool with query size when propose_allocation
+-   v4l2codecs: Don’t unref allocation query caps
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+Fixed:
+
+-   hrtfrender: Use a bitmask instead of an int in the caps for the channel-mask
+-   rtpgccbwe: Don’t log an error when pushing a buffer list fails while stopping
+-   webrtcsink: Don’t panic in bitrate handling with unsupported encoders
+-   webrtcsink: Don’t panic if unsupported input caps are used
+-   webrtcsrc: Allow a None producer-id in request-encoded-filter signal
+
+Added:
+
+-   aws: New property to support path-style addressing
+-   fmp4mux / mp4mux: Support FLAC inside (f)MP4
+-   gtk4: Support directly importing dmabufs with GTK 4.14
+-   gtk4: Add force-aspect-ratio property similar to other video sinks
+
+gst-libav
+
+-   libav: guard some recently dropped APIs
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   Fix Python library name fetching and library searching on Windows
+-   Don’t link to python for the gi overrides module
+
+gst-editing-services
+
+-   ges-launcher: Fix for forcing container profiles
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   debug-viewer: Fix plugin loading machinery
+-   validate/flvdemux: Stop spamming audio/video on test
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.24.3
+
+-   No changes
+
+Contributors to 1.24.3
+
+Alexander Slobodeniuk, Edward Hervey, Elliot Chen, F. Duncanh, François Laignel, Haihua Hu, He Junyan, Hou Qi, Jan Schmidt,
+Jimmy Ohn, Maksym Khomenko, Matthew Waters, Nicolas Dufresne, Nirbheek Chauhan, Philippe Normand, Philipp Zabel, Qian Hu (胡骞),
+Sanchayan Maity, Sebastian Dröge, Seungha Yang, Simonas Kazlauskas, Taruntej Kanakamalla, Tim Blechmann, Tim-Philipp Müller, U.
+Artie Eoff, Víctor Manuel Jáquez Leal, William Wedler, Xavier Claessens,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.3
+
+-   List of Merge Requests applied in 1.24.3
+-   List of Issues fixed in 1.24.3
+
+1.24.4
+
+The fourth 1.24 bug-fix release (1.24.4) was released on 29 May 2024.
+
+This release only contains bugfixes and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.4
+
+-   audioconvert: support more than 64 audio channels
+-   avvidec: fix dropped frames when doing multi-threaded decoding of I-frame codecs such as DV Video
+-   mpegtsmux: Correctly time out in live pipelines, esp. for sparse streams like KLV and DVB subtitles
+-   vtdec deadlock fixes on shutdown and format/resolution changes (as might happen with e.g. HLS/DASH)
+-   fmp4mux, isomp4mux: Add support for adding AV1 header OBUs into the MP4 headers, and add language from tags
+-   gtk4paintablesink improvements: fullscreen mode and gst-play-1.0 support
+-   webrtcsink: add support for insecure TLS and improve error handling and VP9 handling
+-   v4l2codecs: decoder: Reorder caps to prefer DMA_DRM ones, fixes issues with playbin3
+-   vah264enc, vah265enc: timestamp handling fixes; generate IDR frames on force-keyunit-requests, not I frames
+-   Visualizer plugins fixes
+-   Avoid using private APIs on iOS
+-   Various bug fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   clock: Fix 32 bit assertions in GST_TIME_TO_TIMEVAL and GST_TIME_TO_TIMESPEC
+-   systemclock: fix usage of __STDC_NO_ATOMICS__
+-   filesrc: Don’t abort on _get_osfhandle() on Windows
+-   tests: Avoid using “bool” for the variable name
+-   Various Solaris / Illumos fixes
+-   parse: Don’t assume that child proxy child objects are GstObjects
+
+gst-plugins-base
+
+-   audioconvert: Support converting >64 channels
+-   decodebin3: Fix caps and stream leaks
+-   playbin(3), streamsynchronizer: Fix deadlock when streams have been flushed before others start
+-   videotestsrc: fix race condition when clearing cached buffer
+-   Fix visualization plugins
+-   GstDiscoverer hangs when processing media file containing mebx on MacOS
+-   glmixer: Add GL_SYNC_META option to buffer pool
+-   typefinding: Fix ID_ODD_SIZE handling regression in WavPack typefinder
+
+gst-plugins-good
+
+-   osxaudio: Avoid using private APIs on iOS
+-   qtdemux: unit test fixes for 32-bit platforms
+
+gst-plugins-bad
+
+-   cudamemory: Fix offset of subsampled planar formats
+-   d3d11: Revert “d3d11device: protect device_lock vs device_new
+-   d3dshader: Fix gamma and primaries conversion pixel shader
+-   dtlsconnection: Fix overflow in timeout calculation on systems with 32 bit time_t
+-   GstPlay: Initialize debug category and error quark in class_init
+-   kmssink: Do not close the DRM prime handle twice
+-   mpegtsmux: Correctly time out and mux anyway in live pipelines
+-   nvcodec: Accept progressive-high profiles for h264
+-   nvencoder: Fix maximum QP value setting
+-   qsvh264dec, qsvh265dec: Fix nalu leaks
+-   v4l2codecs: decoder: Reorder caps to prefer DMA_DRM ones
+-   vah264enc, vah265enc: Let FORCE_KEYFRAME be IDR frame rather than just I frame
+-   vah264enc, vah265enc: Set DTS offset before PTS
+-   vkh26xdec: Fix stop memory leak
+-   vtdec: Fix deadlock when negotiating format change
+-   vtdec: Fix PAUSED->READY deadlock when output loop is running
+-   wayland: Use wl_display_create_queue_with_name
+-   webrtc: request-aux-sender, only sink floating refs
+-   webrtcbin: Allow session level setup attribute in SDP
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+-   fmp4mux, isomp4mux: Add support for adding AV1 header OBUs into the MP4 headers
+-   fmp4mux, isomp4mux: Add language from tags
+-   gtk4paintablesink: Also create own window for gst-play-1.0
+-   gtk4paintablesink: Add GST_GTK4_WINDOW_FULLSCREEN environment variable to fullscreen window for testing with
+    e.g. gst-launch-1.0
+-   gtk4: Fix plugin description and update python examples
+-   rtpgccbwe: Log effective bitrate in more places, and log delay and loss target bitrates separately
+-   webrtcsink: Improve error when no encoder was found or RTP plugins were missing
+-   webrtcsink: Add VP9 parser after the encoder for VP9 too
+-   webrtc: Add support for insecure TLS connections
+
+gst-libav
+
+-   avvidec: Fix dropping wrong “ghost” frames - fixing multi-threaded decoding of I-frame codecs such as DV Video
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   ges-pipeline: Configure encodebin before linking
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.24.4
+
+-   Add Fedora 40 support
+-   srt: bump version to 1.5.3
+-   pango: Fix leaks on Windows (textoverlay plugins)
+-   windows runtime installer has empty qt6 msm
+-   WiX: assorted fixes
+
+Contributors to 1.24.4
+
+Alexander Slobodeniuk, Bill Nottingham, Brad Reitmeyer, Chris Del Guercio, Daniel Stone, Edward Hervey, Emil Pettersson, He
+Junyan, Jordan Petridis, Joshua Breeden, L. E. Segovia, Martin Nordholts, Mathieu Duponchelle, Matthew Waters, Nirbheek Chauhan,
+Philippe Normand, Piotr Brzeziński, Rafael Carício, Robert Ayrapetyan, Robert Mader, Sebastian Dröge, Seungha Yang, Shengqi Yu,
+Stéphane Cerveau, Tim-Philipp Müller,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.4
+
+-   List of Merge Requests applied in 1.24.4
+-   List of Issues fixed in 1.24.4
+
+1.24.5
+
+The fifth 1.24 bug-fix release (1.24.5) was released on 20 June 2024.
+
+This release only contains bugfixes and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.5
+
+-   webrtcsink: Support for AV1 via nvav1enc, av1enc or rav1enc encoders
+-   AV1 RTP payloader/depayloader fixes to work correctly with Chrome and Pion WebRTC
+-   av1parse, av1dec error handling/robustness improvements
+-   av1enc: Handle force-keyunit events properly for WebRTC
+-   decodebin3: selection and collection handling improvements
+-   hlsdemux2: Various fixes for discontinuities, variant switching, playlist updates
+-   qml6glsink: fix RGB format support
+-   rtspsrc: more control URL handling fixes
+-   v4l2src: Interpret V4L2 report of sync loss as video signal loss
+-   d3d12 encoder, memory and videosink fixes
+-   vtdec: more robust error handling, fix regression
+-   ndi: support for NDI SDK v6
+-   Various bug fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   promise: Don’t use g_return_* for internal checks
+-   debug: Add missing gst_debug_log_id_literal() dummy with gst_debug=false
+-   ptp-helper: Add GNU/Hurd support
+
+gst-plugins-base
+
+-   uridecodebin3: Don’t hold PLAY_ITEMS lock when activating them
+-   decodebin3: Always ensure we end up with parsebin or identity
+-   decodebin3: Properly support changing input collections
+-   decodebin3: Avoid usage of parsebin even more
+-   decodebin3: Fix dealing with input without caps
+-   video-info: Don’t crash in gst_video_info_is_equal() if one videoinfo is zero-initialized
+
+gst-plugins-good
+
+-   flacparse: fix buffer overflow
+-   hlsdemux2: Various fixes for discontinuities, variant switching, playlist updates
+-   qml6glsink: fix RGB format support
+-   rtpdtmfdepay: fix caps negotiation with audioconvert
+-   rtpdtmfsrc: fix leak when shutting down mid-event
+-   rtspsrc: fix invalid seqnum assertions
+-   rtspsrc: Various control URL handling fixes
+-   v4l2src: Interpret V4L2 report of sync loss as video signal loss
+
+gst-plugins-bad
+
+-   av1parse: Do not return error when expectedFrameId mismatch
+-   av1dec: Don’t treat decoding errors as fatal and print more error details
+-   av1enc: Handle force-keyunit events properly by requesting keyframes
+-   codectimestamper: never set DTS to NONE
+-   d3d12encoder: Do not print error log for not-supported feature
+-   d3d12memory: Fix staging buffer alignment
+-   d3d12videosink: Disconnect window signal handler on dispose as intended
+-   dtlssrtpenc: Don’t crash if no pad name is provided when requesting a new pad
+-   glcolorconvert: update existing sync meta if outbuf has one
+-   pcapparse: Parsing code assumes unaligned memory accesses are OK
+-   pcapparse: Avoid unaligned memory access
+-   tsdemux: Fix maximum PCR/DTS values
+-   vtdec: Improve error handling in edge cases
+-   vtdec, qtdemux: regression in 1.24.3 - internal data stream error
+-   uvcgadget: Use g_path_get_basename instead of libc basename
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+-   gtk4: update flatpak integration code
+-   ndi: Add support for loading NDI SDK v6
+-   reqwesthttpsrc: Fix race condition when unlocking
+-   rtp: Don’t restrict payload types for payloaders
+-   rtp: av1pay: Correctly use N flag for marking keyframes
+-   rtp: av1depay: Parse internal size fields of OBUs and handle them
+-   webrtcsink: Refactor value retrieval to avoid lock poisoning
+-   webrtcsink: Add support for AV1
+-   webrtc: Update to async-tungstenite 0.26
+-   Fix various new clippy 1.79 warnings
+-   meson: Fix various issues in dependency management, feature detection, some regressions, and add logging
+
+gst-libav
+
+-   No changes
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   No changes
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.24.5
+
+-   osxrelocator: Fix RPATHs in deeply nested libraries
+
+Contributors to 1.24.5
+
+Angelo Verlain, Chris Del Guercio, Corentin Damman, Edward Hervey, Francisco Javier Velázquez-García, He Junyan, Jakub Adam,
+Jakub Vaněk, Khem Raj, L. E. Segovia, Martin Nordholts, Mathieu Duponchelle, Nirbheek Chauhan, Piotr Brzeziński, Samuel
+Thibault, Sebastian Dröge, Sergey Krivohatskiy, Seungha Yang, Tim-Philipp Müller, Zach van Rijn,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.5
+
+-   List of Merge Requests applied in 1.24.5
+-   List of Issues fixed in 1.24.5
+
+1.24.6
+
+The sixth 1.24 bug-fix release (1.24.6) was released on 29 July 2024.
+
+This release only contains bugfixes and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.6
+
+-   Fix compatibility with FFmpeg 7.0
+-   qmlglsink: Fix failure to display content on recent Android devices
+-   adaptivedemux: Fix handling of closed caption streams
+-   cuda: Fix runtime compiler loading with old CUDA tookit
+-   decodebin3 stream selection handling fixes
+-   d3d11compositor, d3d12compositor: Fix transparent background mode with YUV output
+-   d3d12converter: Make gamma remap work as intended
+-   h264decoder: Update output frame duration for interlaced video when second field frame is discarded
+-   macOS audio device provider now listens to audio devices being added/removed at runtime
+-   Rust plugins: audioloudnorm, s3hlssink, gtk4paintablesink, livesync and webrtcsink fixes
+-   videoaggregator: preserve features in non-alpha caps for subclasses with non-system memory sink caps
+-   vtenc: Fix redistribute latency spam
+-   v4l2: fixes for complex video formats
+-   va: Fix strides when importing DMABUFs, dmabuf handle leaks, and blocklist unmaintained Intel i965 driver for encoding
+-   waylandsink: Fix surface cropping for rotated streams
+-   webrtcdsp: Enable multi_channel processing to fix handling of stereo streams
+-   Various bug fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   downloadbuffer: fix push mode
+-   queue: queue2: multiqueue: Don’t work with segment.position if buffers have no timestamps
+-   gst-inspect-1.0: Fix leak of plugin/feature
+
+gst-plugins-base
+
+-   decodebin3: Fix detection of selection done
+-   glvideomixer: Fix critical when setting start-time-selection
+-   parsebin: accept-caps handling for elements with unusual sink pad names
+-   subparse: Don’t use jit for regular expressions when running in valgrind
+-   subparse: put valgrind header availability define into config.h for subparse
+-   videoaggregator: preserve features in non-alpha caps
+-   videoscale: correct classification error
+-   meson: Fix invalid include flag in uninstalled gl pc file
+-   Fix various memory leaks
+
+gst-plugins-good
+
+-   adaptivedemux: Fix handling closed caption streams
+-   qml/glsink: also support GLES2 needing shader ‘precision’ directives
+-   v4l2object: use v4l2 reported width for padded_width when complex video formats
+-   v4l2: meson: fix SIZEOF_OFF_T when cross-compiling with Meson >= 1.3.0
+
+gst-plugins-bad
+
+-   svtav1enc: Fix segfault when flushing
+-   avfdeviceprovider: Fix debug category initialization
+-   osxaudiodeviceprovider: Listen for audio devices being added/removed
+-   avtp: Fixed Linux/Alpine 3.20 build
+-   cuda: Fix runtime compiler loading with old CUDA tookit
+-   d3d11compositor, d3d12compositor: Fix transparent background mode with YUV output
+-   d3d11converter: Fix runtime compiled shader code
+-   d3d12converter: Make gamma remap work as intended
+-   h264decoder: Update output frame duration when second field frame is discarded
+-   isac: Work around upstream having no shared library support for MSVC
+-   lc3: remove bitstream comparison in the tests
+-   qroverlay: redraw overlay when caps changes
+-   qsv: Fix critical warnings
+-   rtmp2: guard against calling gst_amf_node_get_type() with NULL
+-   srtsrc: fix case fallthrough of authentication param
+-   va: Blocklist unmaintained i965 driver for encoding
+-   va: Fix strides when importing DMABUFs
+-   va: Fix dmabuf handle leaks
+-   vadisplay: fix minor version check
+-   vkh265dec: Fix H.264 ref in logs
+-   vulkan: fix wrong stages or access in barriers
+-   vtenc: Fix redistribute latency spam
+-   waylandsink: Fix surface cropping for rotated streams
+-   webrtcdsp: Enable multi_channel processing
+
+gst-plugins-ugly
+
+-   asfdemux: Be more lenient towards malformed header, fixes playback of files written by VLC
+
+GStreamer Rust plugins
+
+-   audioloudnorm: Fix limiter buffer index wraparound off-by-one for the last buffer
+-   aws: s3hlssink: Do not call abort before finishing uploads
+-   gtk4paintablesink: Support RGBx formats in SW paths
+-   gtk4paintablesink: default to force-aspect-ratio=false for Paintable
+-   livesync: Use the actual output buffer duration of gap filler buffers
+-   livesync: Allow queueing up to latency buffers, also sync on the first buffer and add sync property
+-   webrtcsink: fix property types for rav1enc AV1 encoder
+
+gst-libav
+
+-   Fix compatibility with ffmpeg 7
+-   avauddec: Fix crash on stop()
+-   avmux: Fix crash when muxer doesn’t get codecid
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   ges: Various leak fixes
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   validate: Remove G_REGEX_OPTIMIZE usage, helps avoid valgrind issues
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   libgudev wrap: add fallback uri
+-   liblc3 wrap: update to v1.1.1
+
+Cerbero build tool and packaging changes in 1.24.6
+
+-   meson: Backport fix for Glib including a GCC-only flag in the pkg-config file
+-   libsoup: Workaround build error with GCC 14
+-   libltc: Fix Windows build
+-   webrtc-audio-processing: Fix MinGW build
+-   libvpx: Also build a shared lib on macOS
+-   glib: Fix Windows build
+-   osxrelocator: Fix framework entrypoints being unable to load dylibs
+-   gobject-introspection, recipe: Fix more fallout from the Meson dylib ID fixes
+-   cargo-c.recipe: Ensure that we can change the id and rpath
+
+Contributors to 1.24.6
+
+Chris Spoelstra, Edward Hervey, François Laignel, Guillaume Desmottes, Jakub Adam, Jan Schmidt, Jordan Petridis, L. E. Segovia,
+Loïc Yhuel, Matthew Waters, Nirbheek Chauhan, Piotr Brzeziński, Robert Mader, Ruben Gonzalez, Sanchayan Maity, Sebastian Dröge,
+Sebastian Gross, Seungha Yang, Shengqi Yu, Taruntej Kanakamalla, Tim-Philipp Müller, tomaszmi, Víctor Manuel Jáquez Leal,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.6
+
+-   List of Merge Requests applied in 1.24.6
+-   List of Issues fixed in 1.24.6
+
+1.24.7
+
+The seventh 1.24 bug-fix release (1.24.7) was released on 21 August 2024.
+
+This release only contains bugfixes and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.7
+
+-   Fix APE and Musepack audio file and GIF playback with FFmpeg 7.0
+-   playbin3: Fix potential deadlock with multiple playbin3s with glimagesink used in parallel
+-   qt6: various qmlgl6src and qmlgl6sink fixes and improvements
+-   rtspsrc: expose property to force usage of non-compliant setup URLs for RTSP servers where the automatic fallback doesn’t
+    work
+-   urisourcebin: gapless playback and program switching fixes
+-   v4l2: various fixes
+-   va: Fix potential deadlock with multiple va elements used in parallel
+-   meson: option to disable gst-full for static-library build configurations that do not need this
+-   cerbero: libvpx updated to 1.14.1; map 2022Server to Windows11; disable rust variant on Linux if binutils is too old
+-   Various bug fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   bin: Don’t keep the object lock while setting a GstContext when handling NEED_CONTEXT
+-   core: Log pad name, not just the pointer
+
+gst-plugins-base
+
+-   pbutils: descriptions: use subsampling factor to get YUV subsampling
+-   rtspconnection: Handle invalid argument properly
+-   urisourcebin: Actually drop EOS on old-school pad switch
+-   urisourcebin: Don’t hold lock when emitting about-to-finish
+-   gst-launch deadlock with two playbin3s
+-   xvimagesink: Fix crash in pool on error
+
+gst-plugins-good
+
+-   qmlgl6src: Fix crash when use-default-fbo is not set
+-   qt6glwindow: Fallback to GL_RGB on CopyTexImage2D error, fixing usage with eglfs backend
+-   qt6glwindow: Only use GL_READ_FRAMEBUFFER when we do blits
+-   qt6: glwindow: Don’t leak previously rendered buffer
+-   rtspsrc: expose property for forcing usage of non-compliant URLs
+-   v4l2object: fix ARIB_STD_B67 colorimetry unmatch issue
+-   v4l2: Fix colorimetry mismatch for encoded format with RGB color-matrix
+
+gst-plugins-bad
+
+-   aom: av1enc: restrict allowed input width and height
+-   h264parse: bypass check for length_size_minus_one
+-   h265parse: Reject FD received before SPS
+-   msdk: replace strcmp with g_strcmp0
+-   msdkvc1dec crashes (segfault)
+-   rsvgoverlay: add debug category
+-   va: don’t use GST_ELEMENT_WARNING in set_context() vmethod to fix potential deadlock
+-   va: deadlock when playing two videos at once
+-   webrtc: Add missing G_BEGIN/END_DECLS in header for C++
+-   wpe: initialize threading.ready before reading it
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+-   gtk4: Move the dmabuf cfg to the correct bracket level
+
+gst-libav
+
+-   avdemux: Fix deadlock with FFmpeg 7.x when serialized events are received from upstream while opening, such as e.g. APE
+    files with tags
+-   libav: return EOF when stream is out of data
+-   avdemux: Never return 0 from read function, which would lead to infinite loops
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   vaapi: Fix sps_max_dec_pic_buffering_minus1 value in h265 decoder
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   nlecomposition: Don’t leak QoS events
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   validate: Fix copying of action name
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   Add a meson option to disable gst-full for static-library build configurations that do not need this
+
+Cerbero build tool and packaging changes in 1.24.7
+
+-   Disable rust variant on Linux if binutils is too old
+-   Added 2022Server to the Windows platform distro map as Windows11
+-   libvpx: Update to 1.14.1
+
+Contributors to 1.24.7
+
+David Rosca, Edward Hervey, Guillaume Desmottes, Hou Qi, Jan Schmidt, Jesper Jensen, Jordan Petridis, Jordan Yelloz, L. E.
+Segovia, Lyra McMillan, Mathieu Duponchelle, Max Romanov, Nicolas Dufresne, Nirbheek Chauhan, Qian Hu (胡骞), Sebastian Dröge,
+Tim-Philipp Müller, Víctor Manuel Jáquez Leal,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.7
+
+-   List of Merge Requests applied in 1.24.7
+-   List of Issues fixed in 1.24.7
+
+1.24.8
+
+The eigth 1.24 bug-fix release (1.24.8) was released on 19 September 2024.
+
+This release only contains bugfixes and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.8
+
+-   decodebin3: collection handling fixes
+-   encodebin: Fix pad removal (and smart rendering in gst-editing-services)
+-   glimagesink: Fix cannot resize viewport when video size changed in caps
+-   matroskamux, webmmux: fix firefox compatibility issue with Opus audio streams
+-   mpegtsmux: Wait for data on all pads before deciding on a best pad unless timing out
+-   splitmuxsink: Override LATENCY query to pretend to downstream that we’re not live
+-   video: QoS event handling improvements
+-   voamrwbenc: fix list of bitrates
+-   vtenc: Restart encoding session when certain errors are detected
+-   wayland: Fix ABI break in WL context type name
+-   webrtcbin: Prevent crash when attempting to set answer on invalid SDP
+-   cerbero: ship vp8/vp9 software encoders again, which went missing in 1.24.7; ship transcode plugin
+-   Various bug fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   clock: Fix unchecked overflows in linear regression code
+-   meta: Add missing include of gststructure.h
+-   pad: Check data NULL-ness when probes are stopped
+-   aggregator: Immediately return NONE from simple_get_next_time() on non-TIME segments
+
+gst-plugins-base
+
+-   decodebin3: Fix collection identity check
+-   encodebin: Fix pad removal
+-   glimagesink: Fix cannot resize viewport when video size changed in caps
+-   video: Don’t overshoot QoS earliest time by a factor of 2
+-   meson: gst-play: link to libm
+
+gst-plugins-good
+
+-   jackaudiosrc: actually use the queried ports from JACK
+-   matroskamux: Include end padding in the block duration for Opus streams, fixing firefox compatibility
+-   osxaudio: Avoid dangling pointer on shutdown
+-   splitmuxsink: Override LATENCY query to pretend to downstream that we’re not live
+-   v4l2bufferpool: actually queue back the empty buffer flagged LAST
+-   v4l2videoenc: unref buffer pool after usage properly
+-   v4l2: encoder: Add dynamic framerate support
+
+gst-plugins-bad
+
+-   GstPlay: Name the different bus
+-   GstPlay: check whether stream is seekable before seeking when state change
+-   GstPlayer: Check GstPlayerSignalDispatcher type
+-   mpegtsmux: Wait for data on all pads before deciding on a best pad unless timing out
+-   mpegtsmux: Fix refcounting issue when selecting the best pad
+-   uvcsink: fix caps event handling
+-   v4l2codecs: h265: Minimize memory allocation
+-   voamrwbenc: fix list of bitrates
+-   vtenc: Restart encoding session when certain errors are detected
+-   wayland: Fix ABI break in WL context type name
+-   webrtcbin: Prevent crash when attempting to set answer on invalid SDP
+-   wpe: fix gst-launch example
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+-   No changes
+
+gst-libav
+
+-   No changes
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   discoverer-manager: Fix race leading to assertion when stopping
+-   structured-interface: Fix memory leak of invalid fields GList
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   pad-monitor: Fix remaining pad function data handling
+-   pad-monitor: Fix pad function data properly
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   meson: Update openjpeg wrap to 2.5.2, fixes a warning
+
+Cerbero build tool and packaging changes in 1.24.8
+
+-   No vp8 / vp9 encoders packaged (regression)
+-   libvpx: Fix codec detection to fix vp8enc/vp9enc elements not being shipped
+-   gst-plugins-bad: Add missing transcode plugin
+
+Contributors to 1.24.8
+
+Andoni Morales Alastruey, Arun Raghavan, Benjamin Gaignard, Carlos Bentzen, Chao Guo, Edward Hervey, Francis Quiers, Guillaume
+Desmottes, Hou Qi, Jan Schmidt,, L. E. Segovia, Michael Tretter, Nicolas Dufresne, Nirbheek Chauhan, Peter Kjellerstedt,
+Philippe Normand, Piotr Brzeziński, Randy Li (ayaka), Sebastian Dröge, Thibault Saunier, Tim-Philipp Müller, Wim Taymans,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.8
+
+-   List of Merge Requests applied in 1.24.8
+-   List of Issues fixed in 1.24.8
+
+1.24.9
+
+The ninth 1.24 bug-fix release (1.24.9) was released on 30 October 2024.
+
+This release only contains bugfixes and a security fix and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.9
+
+-   gst-rtsp-server security fix
+-   GstAggregator start time selection and latency query fixes for force-live mode
+-   audioconvert: fix dynamic handling of mix matrix, and accept custom upstream event for setting one
+-   encodebin: fix parser selection for encoders that support multiple codecs
+-   flvmux improvments for pipelines where timestamps don’t start at 0
+-   glcontext: egl: Unrestrict the support base DRM formats
+-   kms: Add IMX-DCSS auto-detection in sink and fix stride with planar formats in allocator
+-   macOS main application event loop fixes
+-   mpegtsdemux: Handle PTS/DTS wraparound with ignore-pcr=true
+-   playbin3, decodebin3, parsebin, urisourcebin: fix races, and improve stability and stream-collection handling
+-   rtpmanager: fix early RTCP SR generation for sparse streams like metadata
+-   qml6glsrc: Reduce capture delay
+-   qtdemux: fix parsing of rotation matrix with 180 degree rotation
+-   rtpav1depay: added wait-for-keyframe and request-keyframe properties
+-   srt: make work with newer libsrt versions and don’t re-connect on authentication failure
+-   v4l2 fixes and improvement
+-   webrtcsink, webrtcbin and whepsrc fixes
+-   cerbero: fix Python 3.13 compatibility, g-i with newer setuptools, bootstrap on Arch Linux; iOS build fixes
+-   Ship qroverlay plugin in binary packages - Various bug fixes, memory leak fixes, and other stability and reliability
+    improvements
+-   Various bug fixes, build fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   aggregator: fix start time selection first with force-live
+-   aggregator: fix live query when force-live is TRUE
+-   parse-launch: Make sure children are bins before recursing in
+-   macos: Fix race conditions in cocoa/application main event loop
+-   multiqueue: Do not unref the query we get in pad->query
+
+gst-plugins-base
+
+-   audioconvert: fix dynamic handling of mix matrix, accept custom upstream event for setting one
+-   playback: Fix a variety of decodebin3/parsebin/urisourcebin races
+-   playbin3: prevent crashing trying to play a corrupted mp4 file (WARNING : HIGH PITCHED CORRUPTED SOUND)
+-   urisourcebin: Ensure all stream-start are handled
+-   urisourcebin: Allow more cases for posting stream-collection
+-   decodebin3: Make update/posting of collection messages atomic
+-   decodebin3: send selected stream message as long as not all the tracks can’t select decoders
+-   urisourcebin/parsebin: Improve collection creation and handling
+-   encodebasebin: Miscellaneous fixes
+-   allocators: drmdumb: Fix bpp value for P010
+-   gldownload: use gst_gl_sync_meta_wait_cpu()
+-   Revert “meson: Fix invalid include flag in uninstalled gl pc file”
+-   gl: Fix configure error when libdrm is a subproject
+-   glcontext: egl: Unrestrict the support base DRM formats
+-   exiftag: Check the result of gst_date_time_new_local_time(), fixes criticals with malformed EXIF tags
+
+gst-plugins-good
+
+-   flvmux: Use first running time on the initial header instead of 0
+-   rtpmanager: skip RTPSources which are not ready in the RTCP generation
+-   rtppassthroughpay: Fix reading clock-rate and payload type from caps
+-   qml6glsrc: Reduce capture delay
+-   qtdemux: fix parsing of matrix with 180 rotation
+-   qtdemux: Check fourcc of a second CEA608 atom instead of assuming it’s cdt2
+-   qtdemux: Skip zero-sized boxes instead of stopping to look at further boxes
+-   twcc: Handle wrapping of reference time
+-   v4l2object: append non colorimetry structure to probed caps
+-   v4l2: Various fixes and improvement
+
+gst-plugins-bad
+
+-   avfdeviceprovider: Fix leak from the GstCaps
+-   codecparsers: add debug categories to bitwriters
+-   codectimestamper: Fix gint wraparound in pts_compare_func
+-   dvxa: Explicitly use cpp_std=c++11
+-   GstPlay: message parsing and documentation improvements
+-   h26xbitwriter: false have_space if aligning fails on aud
+-   kmsallocator: fix stride with planar formats
+-   kmssink: Add IMX-DCSS auto-detection
+-   mpegtsdemux: Handle PTS/DTS wraparound with ignore-pcr=true
+-   rtmp2sink: Initialize base_ts / last_ts with the actual first observed timestamp
+-   scenechange: fix memory leak
+-   srtsink: Register SRT listen callback before binding socket
+-   srt: Don’t attempt to reconnect on authentication failures
+-   tests: va: fix vapostproc test for DMABuf
+-   tests: lc3: Allocate the same size for the buffer and the data
+-   va: Fix libdrm include, plus meson and wrap changes
+-   vaav1enc: Do not enable palette mode by default
+-   vp8decoder: Fix resolution change handling
+-   vtdec: add support for level 6 6.1 and 6.2
+-   wayland: Add NV15 support
+-   webrtcbin: Clean up bin elements when datachannel is removed
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+-   Build: turn lto off for dev profile for faster dev builds
+-   fmp4 hls_live example: Don’t set header-update-mode=update, no need to update the header in live mode
+-   gtk4paintablesink: Don’t check for a GL context when filtering dmabuf caps
+-   livesync: Log latency query results when handling latency query too
+-   onvifmetadatapay: Set output caps earlier, so upstream can send gap events earlier
+-   rtpav1depay: Add wait-for-keyframe and request-keyframe properties
+-   spotify: tweak dependencies
+-   transcriberbin: fix panic during gst-inspect-1.0 -u
+-   webrtcsink: fix segment format mismatch with remote offer
+-   webrtcsink: fix assertions when finalizing
+-   webrtcsink: Fix typo in “turn-servers” property description
+-   whepsrc: Fix incorrect default caps
+
+gst-libav
+
+-   avviddec: Unlock video decoder stream lock temporarily while finishing frames
+
+gst-rtsp-server
+
+-   rtsp-server: Remove pointless assertions that can happen if client provides invalid rates (security fix)
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   ges: Fix name of GESFrameCompositionMeta API type (which caused gobject-introspection failures at build time)
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   validate: Ignore flaky dash playbin3 issue
+-   validate: Blacklist more netsim tests
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.24.9
+
+-   Fix Python 3.13 compatibility
+-   gobject-introspection: Import patch to build against newer setuptools
+-   Switch from wget to curl on Fedora 40 and newer
+-   bootstrap: Add missing dependencies on Arch Linux
+-   harfbuzz: Add CXXFLAGS to fix broken build on iOS
+-   openssl.recipe: Stop using non-existent domain in primary tarball url
+-   gst-plugins-bad: ship qroverlay plugin
+
+Contributors to 1.24.9
+
+Andoni Morales Alastruey, Arun Raghavan, Benjamin Gaignard, Corentin Damman, Dave Lucia, Edward Hervey, Elliot Chen, eri,
+Francisco Javier Velázquez-García, Guillaume Desmottes, He Junyan, Hugues Fruchet, Jakub Adam, James Cowgill, Jan Alexander
+Steffens (heftig), Jan Schmidt, Johan Sternerup, Jordan Petridis, L. E. Segovia, Mathieu Duponchelle, Nick Steel, Nicolas
+Dufresne, Nirbheek Chauhan, Ognyan Tonchev, Olivier Crête, Peter Stensson, Philippe Normand, Piotr Brzeziński, Sanchayan Maity,
+Sebastian Dröge, Shengqi Yu, Stéphane Cerveau, Théo Maillart, Thibault Saunier, Tim-Philipp Müller, Víctor Manuel Jáquez Leal,
+Weijian Pan, Xavier Claessens,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.9
+
+-   List of Merge Requests applied in 1.24.9
+-   List of Issues fixed in 1.24.9
+
+1.24.10
+
+The tenth 1.24 bug-fix release (1.24.10) was released on 03 December 2024.
+
+This release only contains bugfixes and security fixes. It should be safe to update from 1.24.x and we would recommend you
+update at your earliest convenience.
+
+Highlighted bugfixes in 1.24.10
+
+-   More than 40 security fixes across a wide range of elements following an audit by the GitHub Security Lab, including the
+    MP4, Matroska, Ogg and WAV demuxers, subtitle parsers, image decoders, audio decoders and the id3v2 tag parser.
+-   avviddec: Fix regression that could trigger assertions about width/height mismatches
+-   appsink and appsrc fixes
+-   closed caption handling fixes
+-   decodebin3 and urisourcebin fixes
+-   glupload: dmabuf: Fix emulated tiled import
+-   level: fix LevelMeta values outside of the stated range
+-   mpegtsmux, flvmux: fix potential busy looping with high cpu usage in live mode
+-   pipeline dot file graph generation improvements
+-   qt(6): fix criticals with multiple qml(6)gl{src,sink}
+-   rtspsrc: Optionally timestamp RTP packets with their receive times in TCP/HTTP mode to enable clock drift handling
+-   splitmuxsrc: reduce number of file descriptors used
+-   systemclock: locking order fixes
+-   v4l2: fix possible v4l2videodec deadlock on shutdown; 8-bit bayer format fixes
+-   x265: Fix build with libx265 version >= 4.1 after masteringDisplayColorVolume API change
+-   macOS: fix rendering artifacts in retina displays, plus ptp clock fixes
+-   cargo: Default to thin lto for the release profile (for faster builds with lower memory requirements)
+-   Various bug fixes, build fixes, memory leak fixes, and other stability and reliability improvements
+-   Translation updates
+
+gstreamer
+
+-   allocator: Avoid integer overflow when allocating sysmem and avoid integer overflow in qtdemux theora extension parsing
+-   deviceprovider: fix leaking hidden providers
+-   gstreamer: prefix debug dot node names to prevent splitting
+-   pad: Never push sticky events in response to a FLUSH_STOP
+-   systemclock: Fix lock order violation and some cleanup
+-   utils: improve gst_util_ceil_log2()
+-   ptp: use ip_mreq instead of ip_mreqn for macos
+-   tracers: unlock leaks tracer if already tracking
+
+gst-plugins-base
+
+-   appsink: fix timeout logic for gst_app_sink_try_pull_sample()
+-   appsrc: Fix use-after-free when making buffer / buffer-lists writable
+-   audiostreamalign: Don’t report disconts for every buffer if alignment-threshold is too small
+-   decodebin3: Unify collection switching checks
+-   discoverer: Don’t print channel layout for more than 64 channels
+-   discoverer: Make sure the missing elements details array is NULL-terminated in a thread-safe way
+-   discoverer: fix segfault in race condition adding a new uri
+-   id3v2: Don’t try parsing extended header if not enough data is available
+-   glupload: dmabuf: Fix emulated tiled import
+-   gl: cocoa: fix rendering artifacts in retina displays
+-   gl: meson: Don’t use libdrm_dep in cc.has_header()
+-   oggstream: fix invalid ogg_packet->packet accesses, address invalid writes CVE
+-   opusdec: Set at most 64 channels to NONE position
+-   playbin: Fix caps leak in get_n_common_capsfeatures()
+-   playbin3: ERROR when setting new HLS URI with instant-uri=true
+-   sdp: Add debug categories for message and mikey modules
+-   ssaparse: Search for closing brace after opening brace
+-   splitmuxsrc: Convert part reader to a bin with a non-async bus
+-   subparse: Check for NULL return of strchr() when parsing LRC subtitles
+-   streamsynchronizer: Only send GAP events out of source pads
+-   urisourcebin: Also use event probe for HLS use-cases
+-   video-converter: Set TIME segment format on appsrc
+-   vorbisdec: Set at most 64 channels to NONE position
+-   Translation for gst-plugins-base 1.24.0 not sync-ed with Translation Project
+-   Update translations
+
+gst-plugins-good
+
+-   avisubtitle: Fix size checks and avoid overflows when checking sizes
+-   flvmux: Don’t time out in live mode if no timestamped next buffer is available
+-   gdkpixbufdec: Check if initializing the video info actually succeeded
+-   jpegdec: Directly error out on negotiation failures
+-   level: Fix integer overflow when filling LevelMeta
+-   level: produces level value outside of Stated Range
+-   matroskademux: header parsing fixes
+-   qtdemux: header and sample table parsing fixes
+-   qtdemux: avoid integer overflow in theora extension parsing
+-   qt(6)/material: ensure that we always update the context in setBuffer()
+-   rtspsrc: Optionally timestamp RTP packets with their receive times in TCP/HTTP mode
+-   rtp: Fix precision loss in gst_rtcp_ntp_to_unix()
+-   rtpfunnel: Ensure segment events are forwarded after flushs
+-   rtpmanager: don’t map READWRITE in twcc header ext
+-   rtph264depay, rtph265depay: Fix various OOB reads / NULL pointer dereferences in parameter-set string handling
+-   shout2send: Unref event at the end of the event function
+-   udpsrc: protect cancellable from unlock/unlock_stop race
+-   v4l2object: Fixed incorrect maximum value for int range
+-   v4l2object: Remove little endian marker on 8 bit bayer format names
+-   v4l2videodec: fix freeze race condition
+-   wavparse: Fix various (missing) size checks and other parsing problems
+
+gst-plugins-bad
+
+-   ccconverter: Don’t override in_fps_entry when trying to take output
+-   ccutils fixes
+-   kmssink: Add mediatek auto-detection
+-   mpegtsmux: Don’t time out in live mode if no timestamped next buffer is available (fixes busy loop with high cpu usage)
+-   mpegvideoparse: do not set delta unit flag on unknown frame type
+-   mxfmux: Fix off-by-one in the month when generating a timestamp for now
+-   timecodestamper: Don’t fail the latency query in LTC mode if we have no framerate
+-   webrtc: don’t crash on invalid bundle id
+-   x265: Allow building with x265-4.1 (after masteringDisplayColorVolume API change)
+-   meson: Don’t unconditionally invoke the libsoup subproject for tests
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+-   cargo: Default to thin lto for the release profile (for faster builds with lower memory requirements)
+
+gst-libav
+
+-   avcodecmap: Use avcodec_get_supported_config() instead of struct fields
+-   libav: viddec: provide details if meta has the wrong resolution
+-   avviddec: Unlock video decoder stream lock temporarily while finishing frames
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   No changes
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   validate: Fix leaks in ssim components
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   meson: Fix failing libva wrap file build
+
+Cerbero build tool and packaging changes in 1.24.10
+
+-   shell: fix TemporaryDirectory error with the with statement when ZSH
+-   ci: update macos CI to 15 Sequoia
+
+Contributors to 1.24.10
+
+Albert Sjolund, Alicia Boya García, Andoni Morales Alastruey, Antonio Morales, Edward Hervey, Guillaume Desmottes, Jan Alexander
+Steffens (heftig), Jan Schmidt, Jonas Rebmann, Jordan Petridis, Mathieu Duponchelle, Matthew Waters, Nicolas Dufresne, Nirbheek
+Chauhan, Pablo Sun, Philippe Normand, Robert Rosengren, Ruben Gonzalez, Sebastian Dröge, Seungmin Kim, Stefan Riedmüller,
+Stéphane Cerveau, Taruntej Kanakamalla, Théo Maillart, Thibault Saunier, Tim-Philipp Müller, Tomáš Polomský, Wilhelm Bartel, Xi
+Ruoyao,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.10
+
+-   List of Merge Requests applied in 1.24.10
+-   List of Issues fixed in 1.24.10
+
+1.24.11
+
+The eleventh 1.24 bug-fix release (1.24.11) was released on 06 January 2025.
+
+This release only contains bugfixes and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.11
+
+-   playback: Fix SSA/ASS subtitles with embedded fonts
+-   decklink: add missing video modes and fix 8K video modes
+-   matroskamux: spec compliance fixes for audio-only files
+-   onnx: disable onnxruntime telemetry
+-   qtdemux: Fix base offset update when doing segment seeks
+-   srtpdec: Fix a use-after-free issue
+-   (uri)decodebin3: Fix stream change scenarios, possible deadlock on shutdown
+-   video: fix missing alpha flag in AV12 format description
+-   avcodecmap: Add some more channel position mappings
+-   cerbero bootstrap fixes for Windows 11
+-   Various bug fixes, build fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   No changes
+
+gst-plugins-base
+
+-   appsrc: Decrease log level for item drop
+-   gl: raise WARNING instead of ERROR when no connector is connected
+-   decodebin3: Free main input even if it is not part of the list of inputs
+-   urisourcebin: Avoid deadlock on shutdown
+-   urisourcebin: Only rewrite stream-start event once
+-   urisourcebin/(uri)decodebin3: Fix stream change scenarios
+-   urisourcebin: Reference counting leak
+-   playbin3: leak detected with A/V playback and window closed
+-   videodecoder: Gracefully handle missing data without prior input segment
+-   videodecoder: set decode only flag by decode only buffer
+-   video: fix AV12 format lacking the GST_VIDEO_FORMAT_FLAG_ALPHA flag.
+-   Fix SSA/ASS subtitles with embedded fonts
+
+gst-plugins-good
+
+-   matroskamux: Fix audio-only stream conditions and consider audio buffers as keyframes when writing out simpleblocks
+-   qtdemux: fix accumulated base offset in segment seeks
+-   rtppassthroughpay: ensure buffer is writable before mapping writable
+-   rtpsession: Fix twcc stats structure leak
+-   v4l2: object: Add P010 format
+-   v4l2videodec: release decode only frame in input list
+
+gst-plugins-bad
+
+-   decklink: add missing video modes, fix 8K video modes
+-   onnx: disable onnxruntime telemetry
+-   srtpdec: fix build when libsrtp1 is being used
+-   srtpdec: Fix a use-after-free buffer issue
+-   va: display: Optimize out some property indirection
+-   vp9parse/av1parse: Add video codec tag to the tag list
+-   webrtc: Simplify fmtp handling in codec stats
+-   webrtcbin: Fix potential deadlock on bin elements cleanup
+-   zxing: Replace deprecated DecodeHints with ReaderOptions
+-   meson: Also disable drm on GNU/Hurd
+
+gst-plugins-ugly
+
+-   No changes
+
+GStreamer Rust plugins
+
+-   No changes
+
+gst-libav
+
+-   avcodecmap: Add some more channel position mappings
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   meson: Re-added required: lines accidentally removed
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   ges: Fix some reference counting and error handling
+-   ges-meta-container: Fix the GET_INTERFACE macro
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.24.11
+
+-   Fix bootstrap on Windows 11: Install WMIC when missing
+
+Contributors to 1.24.11
+
+Armin Begovic, Benjamin Gräf, Cheung Yik Pang, Christian Meissl, Daniel Morin, Dean Zhang (张安迪), Edward Hervey, Emil
+Ljungdahl, Francisco Javier Velázquez-García, Guillaume Desmottes, Jan Alexander Steffens (heftig), L. E. Segovia, Matthew
+Waters, Max Romanov, Nicolas Dufresne, Philippe Normand, Robert Mader, Samuel Thibault, Sebastian Dröge, Stéphane Cerveau,
+Thibault Saunier, Tim-Philipp Müller,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.11
+
+-   List of Merge Requests applied in 1.24.11
+-   List of Issues fixed in 1.24.11
+
+1.24.12
+
+The twelfth 1.24 bug-fix release (1.24.12) was released on 29 January 2025.
+
+This release only contains bugfixes and it should be safe to update from 1.24.x.
+
+Highlighted bugfixes in 1.24.12
+
+-   d3d12: Fix shaders failing to compile with newer dxc versions
+-   decklinkvideosink: Fix handling of caps framerate in auto mode; also a decklinkaudiosink fix
+-   devicemonitor: Fix potential crash macOS when a device is unplugged
+-   gst-libav: Fix crash in audio encoders like avenc_ac3 if input data has insufficient alignment
+-   gst-libav: Fix build against FFmpeg 4.2 as in Ubuntu 20.04
+-   gst-editing-services: Fix Python library name fetching on Windows
+-   netclientclock: Don’t store failed internal clocks in the cache, so applications can re-try later
+-   oggdemux: Seeking and duration handling fixes
+-   osxaudiosrc: Fixes for failing init/no output on recent iOS versions
+-   qtdemux: Use mvhd transform matrix and support for flipping
+-   rtpvp9pay: Fix profile parsing
+-   splitmuxsrc: Fix use with decodebin3 which would occasionally fail with an assertion when seeking
+-   tsdemux: Fix backwards PTS wraparound detection with ignore-pcr=true
+-   video-overlay-composition: Declare the video/size/orientation tags for the meta and implement scale transformations
+-   vtdec: Fix seeks occasionally hanging on macOS due to a race condition when draining
+-   webrtc: Fix duplicate payload types with RTX and multiple video codecs
+-   win32-pluginloader: Make sure not to create any windows when inspecting plugins
+-   wpe: Various fixes for re-negotiation, latency reporting, progress messages on startup
+-   x264enc: Add missing data to AvcDecoderConfigurationRecord in codec_data for high profile variants
+-   cerbero: Support using ccache with cmake if enabled
+-   Various bug fixes, build fixes, memory leak fixes, and other stability and reliability improvements
+
+gstreamer
+
+-   device: Fix racy nullptr deref on macOS when a device is unplugged
+-   iterator: Added error handling to filtered iterators
+-   netclientclock: Don’t ever store failed internal clocks in the cache
+-   netclock-replay: use gst_c_args when building, fixing build failure on Solaris
+-   pluginloader-win32: create no window
+-   pluginloader-win32: fix use after free in find_helper_bin_location
+-   sparsefile: ensure error is set when read_buffer() returns 0
+-   basetransform: fix incorrect logging inside gst_base_transform_query_caps
+
+gst-plugins-base
+
+-   oggdemux: fixes seeking in some cases by not overwriting a valid duration with CLOCK_TIME_NONE
+-   video-overlay-composition: Declare the video/size/orientation tags for the meta & implement scale transformation
+-   Various fixes found from adding extra warning flags
+
+gst-plugins-good
+
+-   osxaudiosrc: Fixes for failing init/no output on recent iOS versions
+-   qtdemux: Use mvhd transform matrix and support for flipping
+-   qtmux: fix critical warnings on negotiation error
+-   rtpvp9pay: fix profile parsing
+-   splitmuxsrc: Ensure only a single stream-start event is pushed
+-   splitmuxsrc: decodebin3 Fails with assertion in mq_slot_handle_stream_start when seeking
+-   Various fixes found from adding extra warning flags
+
+gst-plugins-bad
+
+-   decklinkvideosink: Fix handling of caps framerate in auto mode
+-   decklinkaudiosink: Don’t crash if started without corresponding video sink
+-   d3d12: Fix shaders failing to compile with newer dxc versions
+-   tsdemux: Fix backwards PTS wraparound detection with ignore-pcr=true
+-   vtdec: fix seeks hangs due to a race condition draining
+-   vtdec: seeks freeze the pipeline
+-   wayland: Print table split when DMABuf format changes
+-   webrtc: fix duplicate payload types with RTX and multiple video codecs
+-   wpevideosrc: Clear cached SHM buffers after caps re-negotiation
+-   wpe: Report latency and start-up progress messages
+-   wpe: remove glFlush() when filling buffer
+-   Fix build with gtk3 but not wayland
+-   Various fixes found from adding extra warning flags
+
+gst-plugins-ugly
+
+-   x264enc: add missing data to AvcDecoderConfigurationRecord, and switch to GstByteWriter
+
+GStreamer Rust plugins
+
+-   No changes
+
+gst-libav
+
+-   avaudenc: fix crash in avenc_ac3 if input buffers are insufficiently aligned
+-   avcodecmap: Only use new channel positions when compiling against new enough ffmpeg
+-   gst-libav: 1.24.11: Fails to build with minimum supported ffmpeg version
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   ges: Fix Python library name fetching on Windows
+
+gst-devtools, gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.24.12
+
+-   cmake: Support using ccache if enabled
+
+Contributors to 1.24.12
+
+Adrian Perez de Castro, Alan Coopersmith, Alexander Slobodeniuk, Andoni Morales Alastruey, Andrew Yooeun Chun, Brad Hards,
+Carlos Bentzen, Colin Kinloch, Edward Hervey, François Laignel, Guillaume Desmottes, Jochen Henneberg, Jordan Yelloz, L. E.
+Segovia, Monty C, Nirbheek Chauhan, Philippe Normand, Piotr Brzeziński, Rares Branici, Samuel Thibault, Sebastian Dröge, Silvio
+Lazzeretti, Tim-Philipp Müller, Tomas Granath, Will Miller,
+
+… and many others who have contributed bug reports, translations, sent suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.24.12
+
+-   List of Merge Requests applied in 1.24.12
+-   List of Issues fixed in 1.24.12
+
+Schedule for 1.26
+
+Our next major feature release will be 1.26, and 1.25 will be the unstable development version leading up to the stable 1.26
+release. The development of 1.25/1.25 will happen in the git main branch of the GStreamer mono repository.
+
+The schedule for 1.26 is yet to be decided.
+
+1.26 will be backwards-compatible to the stable 1.24, 1.22, 1.20, 1.18, 1.16, 1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0
+release series.
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+These release notes have been prepared by Tim-Philipp Müller with contributions from Edward Hervey, Matthew Waters, Nicolas
+Dufresne, Nirbheek Chauhan, Olivier Crête, Sebastian Dröge, Seungha Yang, Thibault Saunier, and Víctor Manuel Jáquez Leal.
 
 License: CC BY-SA 4.0
diff --git a/README.md b/README.md
index 79e1942..eb6c080 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-GStreamer 1.20.x stable series
+GStreamer 1.24.x stable series
 
 WHAT IT IS
 ----------
@@ -16,17 +16,17 @@ Our documentation, including tutorials, API reference and FAQ can be found at
 
   https://gstreamer.freedesktop.org/documentation/
 
-You can subscribe to our mailing lists:
+You can ask questions on the GStreamer Discourse at
 
-  https://lists.freedesktop.org/mailman/listinfo/gstreamer-announce
-
-  https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
+  https://discourse.gstreamer.org/
 
 We track bugs, feature requests and merge requests (patches) in GitLab at
 
   https://gitlab.freedesktop.org/gstreamer/
 
-You can join us on IRC - #gstreamer on irc.oftc.net
+You can join us on our Matrix room at
+
+  https://matrix.to/#/#gstreamer:gstreamer.org
 
 GStreamer 1.0 series
 --------------------
diff --git a/RELEASE b/RELEASE
index dd68d14..f08efd3 100644
--- a/RELEASE
+++ b/RELEASE
@@ -1,17 +1,17 @@
-This is GStreamer core 1.22.0.
+This is GStreamer core 1.24.12.
 
 The GStreamer team is thrilled to announce a new major feature release
 of your favourite cross-platform multimedia framework!
 
 As always, this release is again packed with new features, bug fixes and
 other improvements.
-
-The 1.22 release series adds new features on top of the 1.20 series and is
+ 
+The 1.24 release series adds new features on top of the 1.22 series and is
 part of the API and ABI-stable 1.x release series.
 
 Full release notes can be found at:
 
-  https://gstreamer.freedesktop.org/releases/1.22/
+  https://gstreamer.freedesktop.org/releases/1.24/
 
 Binaries for Android, iOS, Mac OS X and Windows will usually be provided
 shortly after the release.
@@ -44,10 +44,7 @@ with other GStreamer modules for a complete multimedia experience.
 
  - gstreamer-vaapi: hardware-accelerated video decoding and encoding using
                     VA-API on Linux. Primarily for Intel graphics hardware.
-
- - gst-omx: hardware-accelerated video decoding and encoding, primarily for
-                    embedded Linux systems that provide an OpenMax
-                    implementation layer such as the Raspberry Pi.
+                    (Deprecated, use the new "va" plugin instead)
 
  - gst-rtsp-server: library to serve files or streaming pipelines via RTSP
 
@@ -80,14 +77,18 @@ Please submit patches via GitLab as well, in form of Merge Requests. See
 
 for more details.
 
-For help and support, please subscribe to and send questions to the
-gstreamer-devel mailing list (see below for details).
+For help and support, please head over to our Discourse forum at
 
-There is also a #gstreamer IRC channel on the OFTC IRC network, which is
-also bridged into the Matrix network.
+  https://discourse.gstreamer.org/
 
-Please do not submit support requests in GitLab, we only use it
-for bug tracking and merge requests review.
+or pop into one of our Matrix chat rooms, see
+
+  https://discourse.gstreamer.org/t/new-gstreamer-matrix-chat-space/675
+
+for more details.
+
+Please do not submit support requests in GitLab, we only use it for
+bug tracking and merge requests review. Use the Discourse forum instead.
 
 ==== Developers ====
 
@@ -99,6 +100,9 @@ and can also be cloned from there and this is also where you can submit
 Merge Requests or file issues for bugs or feature requests.
 
 Interested developers of the core library, plugins, and applications should
-subscribe to the gstreamer-devel list:
+join us on Matrix for chat and the Discourse forum for announcements, help
+and discussions.
+
+There is also a gstreamer-devel mailing list, but Discourse is preferred:
 
   https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
diff --git a/docs/gst-hotdoc-plugins-scanner.c b/docs/gst-hotdoc-plugins-scanner.c
index ffcdd3c..ebe8c9d 100644
--- a/docs/gst-hotdoc-plugins-scanner.c
+++ b/docs/gst-hotdoc-plugins-scanner.c
@@ -177,7 +177,7 @@ _serialize_enum (GString * json, GType gtype, GstPluginAPIFlags api_flags)
       "\"kind\": \"enum\"", json->len ? "," : "", g_type_name (gtype));
 
   if (api_flags & GST_PLUGIN_API_FLAG_IGNORE_ENUM_MEMBERS) {
-    g_string_append (json, ",\"ignore-enum-members\": true}");
+    g_string_append (json, ",\"ignore-enum-members\": true, \"values\": []}");
   } else {
     g_string_append (json, ",\"values\": [");
 
@@ -349,7 +349,7 @@ _add_properties (GString * json, GString * other_types,
       continue;
 
     g_value_init (&value, spec->value_type);
-    if (object && ! !(spec->flags & G_PARAM_READABLE) &&
+    if (object && !!(spec->flags & G_PARAM_READABLE) &&
         !(spec->flags & GST_PARAM_DOC_SHOW_DEFAULT)) {
       g_object_get_property (G_OBJECT (object), spec->name, &value);
     } else {
diff --git a/docs/gst-plugins-doc-cache-generator.py b/docs/gst-plugins-doc-cache-generator.py
index c1283e7..e947fb1 100755
--- a/docs/gst-plugins-doc-cache-generator.py
+++ b/docs/gst-plugins-doc-cache-generator.py
@@ -23,6 +23,8 @@ import sys
 import re
 import subprocess
 import tempfile
+from pathlib import Path as P
+from argparse import ArgumentParser
 
 from collections import OrderedDict
 try:
@@ -31,6 +33,53 @@ except ImportError:  # python <3.3
     from collections import Mapping
 
 
+class GstPluginsHotdocConfGen:
+    def __init__(self):
+
+        parser = ArgumentParser()
+        parser.add_argument('--builddir', type=P)
+        parser.add_argument('--gst_cache_file', type=P)
+        parser.add_argument('--sitemap', type=P)
+        parser.add_argument('--index', type=P)
+        parser.add_argument('--c_flags')
+        parser.add_argument('--gst_index', type=P)
+        parser.add_argument('--gst_c_sources', nargs='*', default=[])
+        parser.add_argument('--project_version')
+        parser.add_argument('--include_paths', nargs='*', default=[])
+        parser.add_argument('--gst_c_source_filters', nargs='*', default=[])
+
+        parser.parse_args(namespace=self, args=sys.argv[2:])
+
+    def generate_plugins_configs(self):
+        plugin_files = []
+        with self.gst_cache_file.open() as fd:
+            all_plugins = json.load(fd)
+
+            for plugin_name in all_plugins.keys():
+                conf = self.builddir / f'plugin-{plugin_name}.json'
+                plugin_files.append(str(conf))
+                with conf.open('w') as f:
+                    json.dump({
+                        'sitemap': str(self.sitemap),
+                        'index': str(self.index),
+                        'gst_index': str(self.index),
+                        'output': f'plugin-{plugin_name}',
+                        'conf': str(conf),
+                        'project_name': plugin_name,
+                        'project_version': self.project_version,
+                        'gst_cache_file': str(self.gst_cache_file),
+                        'gst_plugin_name': plugin_name,
+                        'c_flags': self.c_flags,
+                        'gst_smart_index': True,
+                        'gst_c_sources': self.gst_c_sources,
+                        'gst_c_source_filters': [str(s) for s in self.gst_c_source_filters],
+                        'include_paths': self.include_paths,
+                        'gst_order_generated_subpages': True,
+                    }, f, indent=4)
+
+        return plugin_files
+
+
 # Marks values in the json file as "unstable" so that they are
 # not updated automatically, this aims at making the cache file
 # stable and handle corner cases were we can't automatically
@@ -78,6 +127,11 @@ def test_unstable_values():
     assert (current_cache == { "v1": "no", "v2": "yay", "unstable-values": "v2" })
 
 if __name__ == "__main__":
+    if sys.argv[1] == "hotdoc-config":
+        fs = GstPluginsHotdocConfGen().generate_plugins_configs()
+        print(os.pathsep.join(fs))
+        sys.exit(0)
+
     cache_filename = sys.argv[1]
     output_filename = sys.argv[2]
     build_root = os.environ.get('MESON_BUILD_ROOT', '')
@@ -115,7 +169,7 @@ if __name__ == "__main__":
         except subprocess.CalledProcessError as e:
             log.flush()
             with open(stderrlogfile, 'r', encoding='utf8') as f:
-                print(f.read(), file=sys.stderr)
+                print(f.read(), file=sys.stderr, end='')
             raise
 
     with open(out, 'r', newline='\n', encoding='utf8') as jfile:
diff --git a/docs/gst/running.md b/docs/gst/running.md
index 65f5e6f..8285cd2 100644
--- a/docs/gst/running.md
+++ b/docs/gst/running.md
@@ -268,7 +268,8 @@ Use `all` to enable all tracing flags.
 
 Set this variable to a file path to redirect all GStreamer debug
 messages to this file. If left unset, debug messages with be output unto
-the standard error.
+the standard error. The %p pattern is replaced with the PID and the %r
+with a random number.
 
 **`ORC_CODE`.**
 
@@ -314,7 +315,7 @@ the encoding does not look like UTF-8.
 **`GST_GL_WINDOW`.**
 
 Influences the window system to use by the GStreamer OpenGL library.
-Common values are 'x11', 'wayland', 'win32' or 'cocoa'.
+Common values are 'x11', 'wayland', 'surfaceless', 'win32' or 'cocoa'.
 
 **`GST_GL_PLATFORM`.**
 
@@ -342,3 +343,10 @@ Example: `GST_PLUGIN_FEATURE_RANK=foo:PRIMARY,bar:primary,foobar:128`
 As a result of the above example,
 the `foo` and` bar` plugin feature rank values are `PRIMARY`(256)
 and `SECONDARY`(128) rank value will be assigned to `foobar`.
+
+**`GST_XINITTHREADS`.**
+
+Set this variable when using components that rely on X11, such as ximagesrc, 
+from gst-launch-1.0 or other command line applications. However, applications 
+should not depend on this variable and should make their own `XInitThreads()`
+call as early as possible.
diff --git a/docs/index.md b/docs/index.md
index 4237705..72bf530 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -277,7 +277,9 @@ Use `all` to enable all tracing flags.
 
 Set this variable to a file path to redirect all GStreamer debug
 messages to this file. If left unset, debug messages with be output unto
-the standard error.
+the standard error. The %p pattern is replaced with the PID and the
+%r with a random number.
+
 
 **ORC_CODE.**
 
@@ -323,7 +325,7 @@ the encoding does not look like UTF-8.
 **GST_GL_WINDOW.**
 
 Influences the window system to use by the GStreamer OpenGL library.
-Common values are 'x11', 'wayland', 'win32' or 'cocoa'.
+Common values are 'x11', 'wayland', 'surfaceless', 'win32' or 'cocoa'.
 
 **GST_GL_PLATFORM.**
 
diff --git a/docs/meson.build b/docs/meson.build
index 4dad0d3..a93e957 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -113,6 +113,7 @@ foreach h: ['gettext.h', 'glib-compat-private.h', 'glib-compat.h',
             '../libs/gst/base/gstindex.h',
             '../libs/gst/base/gstindex.c',
             '../libs/gst/check/internal-check.h',
+            '../libs/gst/check/gstharnesslink.h',
             'parser/grammar.tab.pre.h', 'parse/parse_lex.h', 'types.h',
             'gst-printf.h', 'printf-args.h', 'printf-extension.h',
             'printf-parse.h', 'vasnprintf.h', 'gstregistrybinary.c',
@@ -163,28 +164,23 @@ foreach lib: libs
   )]
 endforeach
 
-plugins_doc = [
-    hotdoc.generate_doc('coreelements',
-        project_version: apiversion,
-        sitemap: 'plugins/sitemap.txt',
-        index: 'plugins/index.md',
-        gst_index: 'plugins/index.md',
-        gst_smart_index: true,
-        gst_c_sources: ['../plugins/elements/*.c', '../plugins/elements/*.h'],
-        dependencies: [gst_plugins_doc_dep],
-        gst_cache_file: plugins_cache,
-        gst_plugin_name: 'coreelements',
-    ),
-    hotdoc.generate_doc('coretracers',
-        project_version: apiversion,
-        sitemap: 'plugins/coretracers/sitemap.txt',
-        index: 'plugins/coretracers/index.md',
-        gst_index: 'plugins/coretracers/index.md',
-        gst_smart_index: true,
-        gst_c_sources: ['../plugins/tracers/*.c', '../plugins/tracers/*.h'],
-        dependencies: [gst_plugins_doc_dep],
-        gst_cache_file: plugins_cache,
-        gst_plugin_name: 'coretracers',
-    )
-
-]
+cdir = meson.current_source_dir()
+if host_machine.system() == 'windows'
+  pathsep = ';'
+else
+  pathsep = ':'
+endif
+gst_plugins_doc = run_command(
+    plugins_cache_generator,
+    'hotdoc-config',
+    '--builddir', meson.current_build_dir(),
+    '--project_version', apiversion,
+    '--sitemap', cdir / 'plugins/sitemap.txt',
+    '--index', cdir / 'plugins/index.md',
+    '--gst_index', cdir / 'plugins/index.md',
+    '--gst_c_sources',
+        cdir / '../plugins/*/*.c',
+        cdir / '../plugins/*/*.h',
+    '--gst_cache_file', plugins_cache,
+    check: true,
+).stdout().split(pathsep)
diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json
index cbe32ab..33f8baa 100644
--- a/docs/plugins/gst_plugins_cache.json
+++ b/docs/plugins/gst_plugins_cache.json
@@ -80,6 +80,18 @@
                     }
                 },
                 "properties": {
+                    "qos": {
+                        "blurb": "Generate Quality-of-Service events upstream",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
                     "sync": {
                         "blurb": "Synchronize to pipeline clock",
                         "conditionally-available": false,
@@ -906,6 +918,18 @@
                         "type": "guint",
                         "writable": true
                     },
+                    "file-mode": {
+                        "blurb": "Specify file mode used to open file",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "truncate (1)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstFileSinkFileMode",
+                        "writable": true
+                    },
                     "location": {
                         "blurb": "Location of the file to write",
                         "conditionally-available": false,
@@ -2646,6 +2670,26 @@
                     }
                 ]
             },
+            "GstFileSinkFileMode": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Truncate file (mode wb)",
+                        "name": "truncate",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Append file (mode ab)",
+                        "name": "output",
+                        "value": "2"
+                    },
+                    {
+                        "desc": "Overwrite file without truncating (mode rb+)",
+                        "name": "overwrite",
+                        "value": "3"
+                    }
+                ]
+            },
             "GstInputSelectorSyncMode": {
                 "kind": "enum",
                 "values": [
diff --git a/gst/gst.c b/gst/gst.c
index 5d8788f..d766d16 100644
--- a/gst/gst.c
+++ b/gst/gst.c
@@ -119,6 +119,10 @@
 #endif
 #endif
 
+#ifdef GST_FULL_STATIC_COMPILATION
+void gst_init_static_plugins ();
+#endif
+
 #include <glib/gi18n-lib.h>
 #include <locale.h>             /* for LC_ALL */
 
@@ -180,7 +184,6 @@ enum
   ARG_DEBUG_COLOR_MODE,
   ARG_DEBUG_HELP,
 #endif
-  ARG_PLUGIN_SPEW,
   ARG_PLUGIN_PATH,
   ARG_PLUGIN_LOAD,
   ARG_SEGTRAP_DISABLE,
@@ -194,24 +197,21 @@ enum
  * val ::= [0-5]
  */
 
-#ifdef G_OS_WIN32
+#if defined(G_OS_WIN32) && !defined(GST_STATIC_COMPILATION)
 /* Note: DllMain is only called when DLLs are loaded or unloaded, so this will
  * never be called if libgstreamer-1.0 is linked statically. Do not add any code
  * here to, say, initialize variables or set things up since that will only
  * happen for dynamically-built GStreamer.
- *
- * Also, ideally this should not be defined when GStreamer is built statically.
- * i.e., it should be conditional on #ifdef DLL_EXPORT. It will be ignored, but
- * if other libraries make the same mistake of defining it when building
- * statically, there will be a symbol collision during linking. Fixing this
- * requires one to build two object files: one for static linking and another
- * for dynamic linking. */
+ */
 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
 BOOL WINAPI
 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 {
-  if (fdwReason == DLL_PROCESS_ATTACH)
+  if (fdwReason == DLL_PROCESS_ATTACH) {
     _priv_gst_dll_handle = (HMODULE) hinstDLL;
+    priv_gst_clock_init ();
+  }
+
   return TRUE;
 }
 
@@ -271,10 +271,6 @@ gst_init_get_option_group (void)
     {"gst-debug-disable", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
         (gpointer) parse_goption_arg, N_("Disable debugging"), NULL},
 #endif
-    {"gst-plugin-spew", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
-          (gpointer) parse_goption_arg,
-          N_("Enable verbose plugin loading diagnostics"),
-        NULL},
     {"gst-plugin-path", 0, 0, G_OPTION_ARG_CALLBACK,
           (gpointer) parse_goption_arg,
         N_("Colon-separated paths containing plugins"), N_("PATHS")},
@@ -539,6 +535,8 @@ init_pre (GOptionContext * context, GOptionGroup * group, gpointer data,
     return TRUE;
   }
 
+  priv_gst_clock_init ();
+
   find_executable_path ();
 
   _priv_gst_start_time = gst_util_get_timestamp ();
@@ -624,6 +622,9 @@ gst_register_core_elements (GstPlugin * plugin)
 static void
 init_static_plugins (void)
 {
+#ifdef GST_FULL_STATIC_COMPILATION
+  gst_init_static_plugins ();
+#else
   GModule *module;
 
   /* Call gst_init_static_plugins() defined in libgstreamer-full-1.0 in the case
@@ -637,6 +638,7 @@ init_static_plugins (void)
     }
     g_module_close (module);
   }
+#endif
 }
 
 /*
@@ -812,7 +814,7 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
    * environment variable */
   _priv_gst_plugin_feature_rank_initialize ();
 
-#ifndef GST_DISABLE_GST_DEBUG
+#ifndef GST_DISABLE_GST_TRACER_HOOKS
   _priv_gst_tracing_init ();
 #endif
 
@@ -987,8 +989,6 @@ parse_one_option (gint opt, const gchar * arg, GError ** err)
       gst_debug_help ();
       exit (0);
 #endif
-    case ARG_PLUGIN_SPEW:
-      break;
     case ARG_PLUGIN_PATH:
 #ifndef GST_DISABLE_REGISTRY
       if (!_priv_gst_disable_registry)
@@ -1042,7 +1042,6 @@ parse_goption_arg (const gchar * opt,
     "--gst-debug-help", ARG_DEBUG_HELP},
 #endif
     {
-    "--gst-plugin-spew", ARG_PLUGIN_SPEW}, {
     "--gst-plugin-path", ARG_PLUGIN_PATH}, {
     "--gst-plugin-load", ARG_PLUGIN_LOAD}, {
     "--gst-disable-segtrap", ARG_SEGTRAP_DISABLE}, {
diff --git a/gst/gst.h b/gst/gst.h
index 7bd59cd..25010b3 100644
--- a/gst/gst.h
+++ b/gst/gst.h
@@ -36,6 +36,7 @@
 #include <gst/gstbuffer.h>
 #include <gst/gstbufferlist.h>
 #include <gst/gstbufferpool.h>
+#include <gst/gstbytearrayinterface.h>
 #include <gst/gstcaps.h>
 #include <gst/gstcapsfeatures.h>
 #include <gst/gstchildproxy.h>
diff --git a/gst/gst_private.h b/gst/gst_private.h
index 0841836..8166a45 100644
--- a/gst/gst_private.h
+++ b/gst/gst_private.h
@@ -84,7 +84,8 @@ typedef struct {
 } GstPluginDep;
 
 struct _GstPluginPrivate {
-  GList *deps;    /* list of GstPluginDep structures */
+  GList *deps;                 /* list of GstPluginDep structures */
+  GstStructure *status_info;
   GstStructure *cache_data;
 };
 
@@ -154,7 +155,7 @@ gboolean _priv_gst_registry_remove_cache_plugins (GstRegistry *registry);
 G_GNUC_INTERNAL  void _priv_gst_registry_cleanup (void);
 
 GST_API
-gboolean _gst_plugin_loader_client_run (void);
+gboolean _gst_plugin_loader_client_run (const gchar * pipe_name);
 
 G_GNUC_INTERNAL  GstPlugin * _priv_gst_plugin_load_file_for_registry (const gchar *filename,
                                                                       GstRegistry * registry,
@@ -520,6 +521,11 @@ struct _GstClockEntryImpl
 };
 
 char * priv_gst_get_relocated_libgstreamer (void);
+gint   priv_gst_count_directories (const char *filepath);
+
+void priv_gst_clock_init (void);
+GstClockTime priv_gst_get_monotonic_time (void);
+GstClockTime priv_gst_get_real_time (void);
 
 G_END_DECLS
 #endif /* __GST_PRIVATE_H__ */
diff --git a/gst/gstallocator.c b/gst/gstallocator.c
index f3cd20e..198cfe9 100644
--- a/gst/gstallocator.c
+++ b/gst/gstallocator.c
@@ -46,6 +46,7 @@
 #endif
 
 #include "gst_private.h"
+#include "glib-compat-private.h"
 #include "gstmemory.h"
 
 GST_DEBUG_CATEGORY_STATIC (gst_allocator_debug);
@@ -103,13 +104,14 @@ _fallback_mem_copy (GstMemory * mem, gssize offset, gssize size)
 
   /* use the same allocator as the memory we copy  */
   allocator = mem->allocator;
-  if (GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC))
+  if (GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC) ||
+      GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_NO_COPY))
     allocator = NULL;
   copy = gst_allocator_alloc (allocator, size, &params);
 
   if (!gst_memory_map (copy, &dinfo, GST_MAP_WRITE)) {
     GST_CAT_WARNING (GST_CAT_MEMORY, "could not write map memory %p", copy);
-    gst_allocator_free (mem->allocator, copy);
+    gst_allocator_free (copy->allocator, copy);
     gst_memory_unmap (mem, &sinfo);
     return NULL;
   }
@@ -162,7 +164,7 @@ gst_allocation_params_new (void)
 {
   /* Call new() and then init(), rather than calling new0(), in case
    * init() ever changes to something other than a memset(). */
-  GstAllocationParams *result = g_slice_new (GstAllocationParams);
+  GstAllocationParams *result = g_new (GstAllocationParams, 1);
   gst_allocation_params_init (result);
   return result;
 }
@@ -196,8 +198,8 @@ gst_allocation_params_copy (const GstAllocationParams * params)
 
   if (params) {
     result =
-        (GstAllocationParams *) g_slice_copy (sizeof (GstAllocationParams),
-        params);
+        (GstAllocationParams *) g_memdup2 (params,
+        sizeof (GstAllocationParams));
   }
   return result;
 }
@@ -211,7 +213,7 @@ gst_allocation_params_copy (const GstAllocationParams * params)
 void
 gst_allocation_params_free (GstAllocationParams * params)
 {
-  g_slice_free (GstAllocationParams, params);
+  g_free (params);
 }
 
 /**
@@ -364,7 +366,6 @@ typedef struct
 {
   GstMemory mem;
 
-  gsize slice_size;
   guint8 *data;
 
   gpointer user_data;
@@ -387,14 +388,13 @@ G_DEFINE_TYPE (GstAllocatorSysmem, gst_allocator_sysmem, GST_TYPE_ALLOCATOR);
 /* initialize the fields */
 static inline void
 _sysmem_init (GstMemorySystem * mem, GstMemoryFlags flags,
-    GstMemory * parent, gsize slice_size,
+    GstMemory * parent,
     gpointer data, gsize maxsize, gsize align, gsize offset, gsize size,
     gpointer user_data, GDestroyNotify notify)
 {
   gst_memory_init (GST_MEMORY_CAST (mem),
       flags, _sysmem_allocator, parent, maxsize, align, offset, size);
 
-  mem->slice_size = slice_size;
   mem->data = data;
   mem->user_data = user_data;
   mem->notify = notify;
@@ -407,12 +407,9 @@ _sysmem_new (GstMemoryFlags flags,
     gsize size, gpointer user_data, GDestroyNotify notify)
 {
   GstMemorySystem *mem;
-  gsize slice_size;
 
-  slice_size = sizeof (GstMemorySystem);
-
-  mem = g_slice_alloc (slice_size);
-  _sysmem_init (mem, flags, parent, slice_size,
+  mem = g_new (GstMemorySystem, 1);
+  _sysmem_init (mem, flags, parent,
       data, maxsize, align, offset, size, user_data, notify);
 
   return mem;
@@ -430,11 +427,23 @@ _sysmem_new_block (GstMemoryFlags flags,
   /* ensure configured alignment */
   align |= gst_memory_alignment;
   /* allocate more to compensate for alignment */
+  if (align > G_MAXSIZE || maxsize > G_MAXSIZE - align) {
+    GST_CAT_WARNING (GST_CAT_MEMORY,
+        "Allocating %" G_GSIZE_FORMAT " bytes with alignment %" G_GSIZE_FORMAT
+        "x overflows", maxsize, align);
+    return NULL;
+  }
   maxsize += align;
   /* alloc header and data in one block */
+  if (maxsize > G_MAXSIZE - sizeof (GstMemorySystem)) {
+    GST_CAT_WARNING (GST_CAT_MEMORY,
+        "Allocating %" G_GSIZE_FORMAT " bytes with alignment %" G_GSIZE_FORMAT
+        "x overflows", maxsize, align);
+    return NULL;
+  }
   slice_size = sizeof (GstMemorySystem) + maxsize;
 
-  mem = g_slice_alloc (slice_size);
+  mem = g_malloc (slice_size);
   if (mem == NULL)
     return NULL;
 
@@ -454,7 +463,7 @@ _sysmem_new_block (GstMemoryFlags flags,
   if (padding && (flags & GST_MEMORY_FLAG_ZERO_PADDED))
     memset (data + offset + size, 0, padding);
 
-  _sysmem_init (mem, flags, NULL, slice_size, data, maxsize,
+  _sysmem_init (mem, flags, NULL, data, maxsize,
       align, offset, size, NULL, NULL);
 
   return mem;
@@ -481,6 +490,8 @@ _sysmem_copy (GstMemorySystem * mem, gssize offset, gsize size)
     size = mem->mem.size > offset ? mem->mem.size - offset : 0;
 
   copy = _sysmem_new_block (0, size, mem->mem.align, 0, size);
+  if (!copy)
+    return NULL;
   GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
       "memcpy %" G_GSIZE_FORMAT " memory %p -> %p", size, mem, copy);
   memcpy (copy->data, mem->data + mem->mem.offset + offset, size);
@@ -541,19 +552,16 @@ static void
 default_free (GstAllocator * allocator, GstMemory * mem)
 {
   GstMemorySystem *dmem = (GstMemorySystem *) mem;
-  gsize slice_size;
 
   if (dmem->notify)
     dmem->notify (dmem->user_data);
 
-  slice_size = dmem->slice_size;
-
 #ifdef USE_POISONING
   /* just poison the structs, not all the data */
   memset (mem, 0xff, sizeof (GstMemorySystem));
 #endif
 
-  g_slice_free1 (slice_size, mem);
+  g_free (mem);
 }
 
 static void
diff --git a/gst/gstallocator.h b/gst/gstallocator.h
index 0989dd8..74c3870 100644
--- a/gst/gstallocator.h
+++ b/gst/gstallocator.h
@@ -84,12 +84,30 @@ struct _GstAllocationParams {
 /**
  * GstAllocatorFlags:
  * @GST_ALLOCATOR_FLAG_CUSTOM_ALLOC: The allocator has a custom alloc function.
+ *    Only elements designed to work with this allocator should be using it,
+ *    other elements should ignore it from allocation propositions.
+ *    This implies %GST_ALLOCATOR_FLAG_NO_COPY.
+ * @GST_ALLOCATOR_FLAG_NO_COPY: When copying a #GstMemory allocated with this
+ *    allocator, the copy will instead be allocated using the default allocator.
+ *    Use this when allocating a new memory is an heavy opperation that should
+ *    only be done with a #GstBufferPool for example. (Since: 1.24)
  * @GST_ALLOCATOR_FLAG_LAST: first flag that can be used for custom purposes
  *
  * Flags for allocators.
  */
+/**
+ * GST_ALLOCATOR_FLAG_NO_COPY:
+ *
+ * When copying a #GstMemory allocated with this allocator, the copy will
+ * instead be allocated using the default allocator. Use this when allocating a
+ * new memory is an heavy opperation that should only be done with a
+ * #GstBufferPool for example.
+ *
+ * Since: 1.24
+ */
 typedef enum {
   GST_ALLOCATOR_FLAG_CUSTOM_ALLOC  = (GST_OBJECT_FLAG_LAST << 0),
+  GST_ALLOCATOR_FLAG_NO_COPY       = (GST_OBJECT_FLAG_LAST << 1),
 
   GST_ALLOCATOR_FLAG_LAST          = (GST_OBJECT_FLAG_LAST << 16)
 } GstAllocatorFlags;
diff --git a/gst/gstandroid.c b/gst/gstandroid.c
index 4212a54..dfb3def 100644
--- a/gst/gstandroid.c
+++ b/gst/gstandroid.c
@@ -56,7 +56,7 @@ load_real_signal (gpointer data)
 }
 
 __sighandler_t bsd_signal (int signum, __sighandler_t handler)
-    __attribute__ ((weak));
+    __attribute__((weak));
 __sighandler_t
 bsd_signal (int signum, __sighandler_t handler)
 {
diff --git a/gst/gstbin.c b/gst/gstbin.c
index 19b0fa6..86a6fb5 100644
--- a/gst/gstbin.c
+++ b/gst/gstbin.c
@@ -124,7 +124,7 @@
  *   sink is in the bin, the query fails.
  *
  * A #GstBin will by default forward any event sent to it to all sink
- * ( %GST_EVENT_TYPE_DOWNSTREAM ) or source ( %GST_EVENT_TYPE_UPSTREAM ) elements
+ * ( %GST_EVENT_TYPE_UPSTREAM ) or source ( %GST_EVENT_TYPE_DOWNSTREAM ) elements
  * depending on the event type.
  *
  * If all the elements return %TRUE, the bin will also return %TRUE, else %FALSE
@@ -1567,8 +1567,10 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
   GST_OBJECT_LOCK (element);
   elem_name = g_strdup (GST_ELEMENT_NAME (element));
 
-  if (GST_OBJECT_PARENT (element) != GST_OBJECT_CAST (bin))
+  if (GST_OBJECT_PARENT (element) != GST_OBJECT_CAST (bin)) {
+    GST_OBJECT_UNLOCK (element);
     goto not_in_bin;
+  }
 
   /* remove the parent ref */
   GST_OBJECT_PARENT (element) = NULL;
@@ -1819,7 +1821,6 @@ no_state_recalc:
   /* ERROR handling */
 not_in_bin:
   {
-    GST_OBJECT_UNLOCK (element);
     GST_OBJECT_UNLOCK (bin);
     GST_WARNING_OBJECT (bin, "Element '%s' is not in bin", elem_name);
     g_free (elem_name);
@@ -2875,10 +2876,13 @@ gst_bin_change_state_func (GstElement * element, GstStateChange transition)
       GST_DEBUG_OBJECT (element, "clearing all cached messages");
       bin_remove_messages (bin, NULL, GST_MESSAGE_ANY);
       GST_OBJECT_UNLOCK (bin);
-      /* We might not have reached PAUSED yet due to async errors,
-       * make sure to always deactivate the pads nonetheless */
-      if (!(gst_bin_src_pads_activate (bin, FALSE)))
-        goto activate_failure;
+      /* Pads can be activated in PULL mode before in NULL state */
+      if (current != GST_STATE_NULL) {
+        /* We might not have reached PAUSED yet due to async errors,
+         * make sure to always deactivate the pads nonetheless */
+        if (!gst_bin_src_pads_activate (bin, FALSE))
+          goto activate_failure;
+      }
       break;
     case GST_STATE_NULL:
       /* Clear message list on next NULL */
@@ -3266,7 +3270,7 @@ bin_bus_handler (GstBus * bus, GstMessage * message, GstBin * bin)
 static void
 free_bin_continue_data (BinContinueData * data)
 {
-  g_slice_free (BinContinueData, data);
+  g_free (data);
 }
 
 static void
@@ -3436,7 +3440,7 @@ bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
         "continue state change, pending %s",
         gst_element_state_get_name (pending));
 
-    cont = g_slice_new (BinContinueData);
+    cont = g_new (BinContinueData, 1);
 
     /* cookie to detect concurrent state change */
     cont->cookie = GST_ELEMENT_CAST (bin)->state_cookie;
@@ -3492,6 +3496,13 @@ was_busy:
 nothing_pending:
   {
     GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin, "nothing pending");
+
+    amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin), running_time);
+
+    GST_OBJECT_UNLOCK (bin);
+    gst_element_post_message (GST_ELEMENT_CAST (bin), amessage);
+    GST_OBJECT_LOCK (bin);
+
     return;
   }
 }
@@ -3974,13 +3985,17 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
     }
     case GST_MESSAGE_NEED_CONTEXT:{
       const gchar *context_type;
-      GList *l, *contexts;
 
       gst_message_parse_context_type (message, &context_type);
 
       if (src) {
+        GList *l, *contexts;
+
         GST_OBJECT_LOCK (bin);
-        contexts = GST_ELEMENT_CAST (bin)->contexts;
+        contexts =
+            g_list_copy_deep (GST_ELEMENT_CAST (bin)->contexts,
+            (GCopyFunc) gst_mini_object_ref, NULL);
+        GST_OBJECT_UNLOCK (bin);
         GST_LOG_OBJECT (bin, "got need-context message type: %s", context_type);
         for (l = contexts; l; l = l->next) {
           GstContext *tmp = l->data;
@@ -3991,7 +4006,8 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
             break;
           }
         }
-        GST_OBJECT_UNLOCK (bin);
+
+        g_list_free_full (contexts, (GDestroyNotify) gst_mini_object_unref);
 
         /* Forward if we couldn't answer the message */
         if (l == NULL) {
diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c
index fb2c787..52ce8e5 100644
--- a/gst/gstbuffer.c
+++ b/gst/gstbuffer.c
@@ -35,7 +35,7 @@
  * The following example creates a buffer that can hold a given video frame
  * with a given width, height and bits per plane.
  *
- * ``` C 
+ * ``` C
  *   GstBuffer *buffer;
  *   GstMemory *memory;
  *   gint size, width, height, bpp;
@@ -145,7 +145,6 @@ GType _gst_buffer_type = 0;
 
 #define GST_BUFFER_MEM_MAX         16
 
-#define GST_BUFFER_SLICE_SIZE(b)   (((GstBufferImpl *)(b))->slice_size)
 #define GST_BUFFER_MEM_LEN(b)      (((GstBufferImpl *)(b))->len)
 #define GST_BUFFER_MEM_ARRAY(b)    (((GstBufferImpl *)(b))->mem)
 #define GST_BUFFER_MEM_PTR(b,i)    (((GstBufferImpl *)(b))->mem[i])
@@ -157,8 +156,6 @@ typedef struct
 {
   GstBuffer buffer;
 
-  gsize slice_size;
-
   /* the memory blocks */
   guint len;
   GstMemory *mem[GST_BUFFER_MEM_MAX];
@@ -546,6 +543,7 @@ gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
   GstMetaItem *walk;
   gsize bufsize;
   gboolean region = FALSE;
+  gboolean sharing_mem = FALSE;
 
   g_return_val_if_fail (dest != NULL, FALSE);
   g_return_val_if_fail (src != NULL, FALSE);
@@ -649,6 +647,9 @@ gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
           return FALSE;
         }
 
+        /* Indicates if dest references any of src memories. */
+        sharing_mem |= (newmem == mem);
+
         _memory_add (dest, -1, newmem);
         left -= tocopy;
       }
@@ -662,6 +663,10 @@ gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
         gst_buffer_remove_memory_range (dest, dest_len, -1);
         return FALSE;
       }
+
+      /* If we were sharing memory and the merge is no-op, we are still sharing. */
+      sharing_mem &= (mem == GST_BUFFER_MEM_PTR (dest, 0));
+
       _replace_memory (dest, len, 0, len, mem);
     }
   }
@@ -691,7 +696,8 @@ gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
       } else if (deep && gst_meta_api_type_has_tag (info->api,
               _gst_meta_tag_memory_reference)) {
         GST_CAT_DEBUG (GST_CAT_BUFFER,
-            "don't copy meta with memory references %" GST_PTR_FORMAT, meta);
+            "don't copy memory reference meta %p of API type %s", meta,
+            g_type_name (info->api));
       } else if (info->transform_func) {
         GstMetaTransformCopy copy_data;
 
@@ -709,6 +715,14 @@ gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
     }
   }
 
+  if (sharing_mem && src->pool != NULL) {
+    /* The new buffer references some of src's memories. We have to ensure that
+     * src buffer does not return to its buffer pool as long as its memories are
+     * used by other buffers. That would cause the buffer to be discarted by the
+     * pool because its memories are not writable. */
+    gst_buffer_add_parent_buffer_meta (dest, src);
+  }
+
   return TRUE;
 }
 
@@ -782,12 +796,20 @@ _gst_buffer_free (GstBuffer * buffer)
 {
   GstMetaItem *walk, *next;
   guint i, len;
-  gsize msize;
 
   g_return_if_fail (buffer != NULL);
 
   GST_CAT_LOG (GST_CAT_BUFFER, "finalize %p", buffer);
 
+  /* free our memory */
+  len = GST_BUFFER_MEM_LEN (buffer);
+  for (i = 0; i < len; i++) {
+    gst_memory_unlock (GST_BUFFER_MEM_PTR (buffer, i), GST_LOCK_FLAG_EXCLUSIVE);
+    gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (GST_BUFFER_MEM_PTR
+            (buffer, i)), GST_MINI_OBJECT_CAST (buffer));
+    gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
+  }
+
   /* free metadata */
   for (walk = GST_BUFFER_META (buffer); walk; walk = next) {
     GstMeta *meta = &walk->meta;
@@ -799,43 +821,23 @@ _gst_buffer_free (GstBuffer * buffer)
 
     next = walk->next;
     /* and free the slice */
-    g_slice_free1 (ITEM_SIZE (info), walk);
+    g_free (walk);
   }
 
-  /* get the size, when unreffing the memory, we could also unref the buffer
-   * itself */
-  msize = GST_BUFFER_SLICE_SIZE (buffer);
-
-  /* free our memory */
-  len = GST_BUFFER_MEM_LEN (buffer);
-  for (i = 0; i < len; i++) {
-    gst_memory_unlock (GST_BUFFER_MEM_PTR (buffer, i), GST_LOCK_FLAG_EXCLUSIVE);
-    gst_mini_object_remove_parent (GST_MINI_OBJECT_CAST (GST_BUFFER_MEM_PTR
-            (buffer, i)), GST_MINI_OBJECT_CAST (buffer));
-    gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
-  }
-
-  /* we set msize to 0 when the buffer is part of the memory block */
-  if (msize) {
 #ifdef USE_POISONING
-    memset (buffer, 0xff, msize);
+  memset (buffer, 0xff, sizeof (GstBufferImpl));
 #endif
-    g_slice_free1 (msize, buffer);
-  } else {
-    gst_memory_unref (GST_BUFFER_BUFMEM (buffer));
-  }
+  g_free (buffer);
 }
 
 static void
-gst_buffer_init (GstBufferImpl * buffer, gsize size)
+gst_buffer_init (GstBufferImpl * buffer)
 {
   gst_mini_object_init (GST_MINI_OBJECT_CAST (buffer), 0, _gst_buffer_type,
       (GstMiniObjectCopyFunction) _gst_buffer_copy,
       (GstMiniObjectDisposeFunction) _gst_buffer_dispose,
       (GstMiniObjectFreeFunction) _gst_buffer_free);
 
-  GST_BUFFER_SLICE_SIZE (buffer) = size;
-
   GST_BUFFER (buffer)->pool = NULL;
   GST_BUFFER_PTS (buffer) = GST_CLOCK_TIME_NONE;
   GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
@@ -859,10 +861,10 @@ gst_buffer_new (void)
 {
   GstBufferImpl *newbuf;
 
-  newbuf = g_slice_new (GstBufferImpl);
+  newbuf = g_new (GstBufferImpl, 1);
   GST_CAT_LOG (GST_CAT_BUFFER, "new %p", newbuf);
 
-  gst_buffer_init (newbuf, sizeof (GstBufferImpl));
+  gst_buffer_init (newbuf);
 
   return GST_BUFFER_CAST (newbuf);
 }
@@ -918,7 +920,7 @@ gst_buffer_new_allocate (GstAllocator * allocator, gsize size,
 
 #if 0
   asize = sizeof (GstBufferImpl) + size;
-  data = g_slice_alloc (asize);
+  data = g_malloc (asize);
   if (G_UNLIKELY (data == NULL))
     goto no_memory;
 
@@ -2311,9 +2313,9 @@ gst_buffer_add_meta (GstBuffer * buffer, const GstMetaInfo * info,
    * uninitialized memory
    */
   if (!info->init_func)
-    item = g_slice_alloc0 (size);
+    item = g_malloc0 (size);
   else
-    item = g_slice_alloc (size);
+    item = g_malloc (size);
   result = &item->meta;
   result->info = info;
   result->flags = GST_META_FLAG_NONE;
@@ -2341,7 +2343,7 @@ gst_buffer_add_meta (GstBuffer * buffer, const GstMetaInfo * info,
 
 init_failed:
   {
-    g_slice_free1 (size, item);
+    g_free (item);
     return NULL;
   }
 }
@@ -2392,7 +2394,7 @@ gst_buffer_remove_meta (GstBuffer * buffer, GstMeta * meta)
         info->free_func (m, buffer);
 
       /* and free the slice */
-      g_slice_free1 (ITEM_SIZE (info), walk);
+      g_free (walk);
       break;
     }
     prev = walk;
@@ -2540,7 +2542,7 @@ gst_buffer_foreach_meta (GstBuffer * buffer, GstBufferForeachMetaFunc func,
         info->free_func (m, buffer);
 
       /* and free the slice */
-      g_slice_free1 (ITEM_SIZE (info), walk);
+      g_free (walk);
     } else {
       prev = walk;
     }
@@ -2858,6 +2860,49 @@ gst_reference_timestamp_meta_api_get_type (void)
   return type;
 }
 
+static gboolean
+timestamp_meta_serialize (const GstMeta * meta, GstByteArrayInterface * data,
+    guint8 * version)
+{
+  const GstReferenceTimestampMeta *rtmeta =
+      (const GstReferenceTimestampMeta *) meta;
+  gchar *caps_str = gst_caps_to_string (rtmeta->reference);
+  gsize caps_str_len = strlen (caps_str);
+
+  gsize size = 16 + caps_str_len + 1;
+  guint8 *ptr = gst_byte_array_interface_append (data, size);
+  if (ptr == NULL) {
+    g_free (caps_str);
+    return FALSE;
+  }
+
+  GST_WRITE_UINT64_LE (ptr, rtmeta->timestamp);
+  GST_WRITE_UINT64_LE (ptr + 8, rtmeta->duration);
+  memcpy (ptr + 16, caps_str, caps_str_len + 1);
+  g_free (caps_str);
+
+  return TRUE;
+}
+
+static GstMeta *
+timestamp_meta_deserialize (const GstMetaInfo * info, GstBuffer * buffer,
+    const guint8 * data, gsize size, guint8 version)
+{
+  /* Sanity check: caps_str must be 0-terminated. */
+  if (version != 0 || size < 2 * sizeof (guint64) + 1 || data[size - 1] != '\0')
+    return NULL;
+
+  guint64 timestamp = GST_READ_UINT64_LE (data);
+  guint64 duration = GST_READ_UINT64_LE (data + 8);
+  const gchar *caps_str = (const gchar *) data + 16;
+  GstCaps *reference = gst_caps_from_string (caps_str);
+  GstMeta *meta = (GstMeta *) gst_buffer_add_reference_timestamp_meta (buffer,
+      reference, timestamp, duration);
+  gst_caps_unref (reference);
+
+  return meta;
+}
+
 /**
  * gst_reference_timestamp_meta_get_info:
  *
@@ -2873,13 +2918,17 @@ gst_reference_timestamp_meta_get_info (void)
   static const GstMetaInfo *meta_info = NULL;
 
   if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {
-    const GstMetaInfo *meta =
-        gst_meta_register (gst_reference_timestamp_meta_api_get_type (),
+    const GstMetaInfo *meta = NULL;
+    GstMetaInfo *info =
+        gst_meta_info_new (gst_reference_timestamp_meta_api_get_type (),
         "GstReferenceTimestampMeta",
-        sizeof (GstReferenceTimestampMeta),
-        (GstMetaInitFunction) _gst_reference_timestamp_meta_init,
-        (GstMetaFreeFunction) _gst_reference_timestamp_meta_free,
-        _gst_reference_timestamp_meta_transform);
+        sizeof (GstReferenceTimestampMeta));
+    info->init_func = (GstMetaInitFunction) _gst_reference_timestamp_meta_init;
+    info->free_func = (GstMetaFreeFunction) _gst_reference_timestamp_meta_free;
+    info->transform_func = _gst_reference_timestamp_meta_transform;
+    info->serialize_func = timestamp_meta_serialize;
+    info->deserialize_func = timestamp_meta_deserialize;
+    meta = gst_meta_info_register (info);
     g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) meta);
   }
 
diff --git a/gst/gstbuffer.h b/gst/gstbuffer.h
index 6a8b84f..a1896fe 100644
--- a/gst/gstbuffer.h
+++ b/gst/gstbuffer.h
@@ -763,6 +763,9 @@ typedef struct _GstReferenceTimestampMeta GstReferenceTimestampMeta;
  *  * `timestamp/x-unix`: for timestamps based on the UNIX epoch according to
  *    the local clock.
  *
+ * Since 1.24 it can be serialized using gst_meta_serialize() and
+ * gst_meta_deserialize().
+ *
  * Since: 1.14
  */
 struct _GstReferenceTimestampMeta
diff --git a/gst/gstbufferlist.c b/gst/gstbufferlist.c
index dca4335..140c9cf 100644
--- a/gst/gstbufferlist.c
+++ b/gst/gstbufferlist.c
@@ -61,8 +61,6 @@ struct _GstBufferList
   guint n_buffers;
   guint n_allocated;
 
-  gsize slice_size;
-
   /* one-item array, in reality more items are pre-allocated
    * as part of the GstBufferList structure, and that
    * pre-allocated array extends beyond the declared struct */
@@ -104,7 +102,6 @@ static void
 _gst_buffer_list_free (GstBufferList * list)
 {
   guint i, len;
-  gsize slice_size;
 
   GST_LOG ("free %p", list);
 
@@ -119,17 +116,15 @@ _gst_buffer_list_free (GstBufferList * list)
   if (GST_BUFFER_LIST_IS_USING_DYNAMIC_ARRAY (list))
     g_free (list->buffers);
 
-  slice_size = list->slice_size;
-
 #ifdef USE_POISONING
-  memset (list, 0xff, slice_size);
+  memset (list, 0xff, sizeof (GstBufferList));
 #endif
 
-  g_slice_free1 (slice_size, list);
+  g_free (list);
 }
 
 static void
-gst_buffer_list_init (GstBufferList * list, guint n_allocated, gsize slice_size)
+gst_buffer_list_init (GstBufferList * list, guint n_allocated)
 {
   gst_mini_object_init (GST_MINI_OBJECT_CAST (list), 0, _gst_buffer_list_type,
       (GstMiniObjectCopyFunction) _gst_buffer_list_copy, NULL,
@@ -138,7 +133,6 @@ gst_buffer_list_init (GstBufferList * list, guint n_allocated, gsize slice_size)
   list->buffers = &list->arr[0];
   list->n_buffers = 0;
   list->n_allocated = n_allocated;
-  list->slice_size = slice_size;
 
   GST_LOG ("init %p", list);
 }
@@ -166,11 +160,11 @@ gst_buffer_list_new_sized (guint size)
 
   slice_size = sizeof (GstBufferList) + (n_allocated - 1) * sizeof (gpointer);
 
-  list = g_slice_alloc0 (slice_size);
+  list = g_malloc0 (slice_size);
 
   GST_LOG ("new %p", list);
 
-  gst_buffer_list_init (list, n_allocated, slice_size);
+  gst_buffer_list_init (list, n_allocated);
 
   return list;
 }
diff --git a/gst/gstbufferpool.c b/gst/gstbufferpool.c
index a1bfd3c..d7da0cd 100644
--- a/gst/gstbufferpool.c
+++ b/gst/gstbufferpool.c
@@ -1217,6 +1217,12 @@ remove_meta_unpooled (GstBuffer * buffer, GstMeta ** meta, gpointer user_data)
   if (!GST_META_FLAG_IS_SET (*meta, GST_META_FLAG_POOLED)) {
     GST_META_FLAG_UNSET (*meta, GST_META_FLAG_LOCKED);
     *meta = NULL;
+  } else {
+    const GstMetaInfo *info = (*meta)->info;
+
+    /* If we can clear it, don't free it */
+    if (info->clear_func)
+      info->clear_func (buffer, *meta);
   }
   return TRUE;
 }
diff --git a/gst/gstbus.c b/gst/gstbus.c
index 15cf16b..3f6eb23 100644
--- a/gst/gstbus.c
+++ b/gst/gstbus.c
@@ -97,6 +97,7 @@ enum
 };
 
 #define DEFAULT_ENABLE_ASYNC (TRUE)
+#define WARN_QUEUE_SIZE 1024
 
 enum
 {
@@ -365,10 +366,13 @@ gst_bus_post (GstBus * bus, GstMessage * message)
 
   g_clear_pointer (&sync_handler, sync_handler_unref);
 
-  /* If this is a bus without async message delivery
-   * always drop the message */
-  if (!bus->priv->poll)
+  /* If this is a bus without async message delivery always drop the message.
+   * If the sync handler returned GST_BUS_DROP it is responsible of unreffing
+   * the message, otherwise do it ourself. */
+  if (!bus->priv->poll && reply != GST_BUS_DROP) {
     reply = GST_BUS_DROP;
+    gst_message_unref (message);
+  }
 
   /* now see what we should do with the message */
   switch (reply) {
@@ -376,7 +380,14 @@ gst_bus_post (GstBus * bus, GstMessage * message)
       /* drop the message */
       GST_DEBUG_OBJECT (bus, "[msg %p] dropped", message);
       break;
-    case GST_BUS_PASS:
+    case GST_BUS_PASS:{
+      guint length = gst_atomic_queue_length (bus->priv->queue);
+      if (G_UNLIKELY (length > 0 && length % WARN_QUEUE_SIZE == 0)) {
+        GST_WARNING_OBJECT (bus, "queue overflows with %d messages. "
+            "Application is too slow or is not handling messages. "
+            "Please add a message handler, otherwise the queue will grow "
+            "infinitely.", length);
+      }
       /* pass the message to the async queue, refcount passed in the queue */
       GST_DEBUG_OBJECT (bus, "[msg %p] pushing on async queue", message);
       gst_atomic_queue_push (bus->priv->queue, message);
@@ -384,6 +395,7 @@ gst_bus_post (GstBus * bus, GstMessage * message)
       GST_DEBUG_OBJECT (bus, "[msg %p] pushed on async queue", message);
 
       break;
+    }
     case GST_BUS_ASYNC:
     {
       /* async delivery, we need a mutex and a cond to block
@@ -424,6 +436,7 @@ gst_bus_post (GstBus * bus, GstMessage * message)
     }
     default:
       g_warning ("invalid return from bus sync handler");
+      gst_message_unref (message);
       break;
   }
   return TRUE;
@@ -834,7 +847,6 @@ no_handler:
   }
 }
 
-#if GLIB_CHECK_VERSION(2,63,3)
 static void
 gst_bus_source_dispose (GSource * source)
 {
@@ -850,22 +862,11 @@ gst_bus_source_dispose (GSource * source)
     bus->priv->gsource = NULL;
   GST_OBJECT_UNLOCK (bus);
 }
-#endif
 
 static void
 gst_bus_source_finalize (GSource * source)
 {
   GstBusSource *bsource = (GstBusSource *) source;
-#if !GLIB_CHECK_VERSION(2,63,3)
-  GstBus *bus = bsource->bus;
-
-  GST_DEBUG_OBJECT (bus, "finalize source %p", source);
-
-  GST_OBJECT_LOCK (bus);
-  if (bus->priv->gsource == source)
-    bus->priv->gsource = NULL;
-  GST_OBJECT_UNLOCK (bus);
-#endif
 
   gst_clear_object (&bsource->bus);
 }
@@ -894,9 +895,7 @@ gst_bus_create_watch_unlocked (GstBus * bus)
   source = (GstBusSource *) bus->priv->gsource;
 
   g_source_set_name ((GSource *) source, "GStreamer message bus watch");
-#if GLIB_CHECK_VERSION(2,63,3)
   g_source_set_dispose_function ((GSource *) source, gst_bus_source_dispose);
-#endif
 
   source->bus = gst_object_ref (bus);
   g_source_add_poll ((GSource *) source, &bus->priv->pollfd);
@@ -1149,7 +1148,7 @@ poll_destroy (GstBusPollData * poll_data, gpointer unused)
   poll_data->source_running = FALSE;
   if (!poll_data->timeout_id) {
     g_main_loop_unref (poll_data->loop);
-    g_slice_free (GstBusPollData, poll_data);
+    g_free (poll_data);
   }
 }
 
@@ -1159,7 +1158,7 @@ poll_destroy_timeout (GstBusPollData * poll_data)
   poll_data->timeout_id = 0;
   if (!poll_data->source_running) {
     g_main_loop_unref (poll_data->loop);
-    g_slice_free (GstBusPollData, poll_data);
+    g_free (poll_data);
   }
 }
 
@@ -1217,7 +1216,7 @@ gst_bus_poll (GstBus * bus, GstMessageType events, GstClockTime timeout)
 
   g_return_val_if_fail (GST_IS_BUS (bus), NULL);
 
-  poll_data = g_slice_new (GstBusPollData);
+  poll_data = g_new (GstBusPollData, 1);
   poll_data->source_running = TRUE;
   poll_data->loop = g_main_loop_new (NULL, FALSE);
   poll_data->events = events;
diff --git a/gst/gstbytearrayinterface.h b/gst/gstbytearrayinterface.h
new file mode 100644
index 0000000..0ffc8ed
--- /dev/null
+++ b/gst/gstbytearrayinterface.h
@@ -0,0 +1,129 @@
+/* Copyright (C) 2023 Netflix Inc.
+ *  Author: Xavier Claessens <xavier.claessens@collabora.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include <glib.h>
+#include <gst/gstconfig.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstByteArrayInterface:
+ * @data: A pointer to an array of bytes.
+ * @len: Number of bytes in @data.
+ * @resize: Reallocate @data.
+ *
+ * Interface for an array of bytes. It is expected to be subclassed to implement
+ * @resize virtual method using language native array implementation, such as
+ * GLib's #GByteArray, C++'s `std::vector<uint8_t>` or Rust's `Vec<u8>`.
+ *
+ * @resize implementation could allocate more than requested to avoid repeated
+ * reallocations. It can return %FALSE, or be set to %NULL, in the case the
+ * array cannot grow.
+ *
+ * Since: 1.24
+ */
+typedef struct _GstByteArrayInterface GstByteArrayInterface;
+struct _GstByteArrayInterface
+{
+  guint8 *data;
+  gsize len;
+  gboolean (*resize) (GstByteArrayInterface *self, gsize length);
+
+  /* < private > */
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+/**
+ * gst_byte_array_interface_init:
+ * @self: A #GstByteArrayInterface.
+ * @length: New size.
+ *
+ * Initialize #GstByteArrayInterface structure.
+ *
+ * Since: 1.24
+ */
+static inline void
+gst_byte_array_interface_init (GstByteArrayInterface *self)
+{
+  memset (self, 0, sizeof (GstByteArrayInterface));
+}
+
+/**
+ * gst_byte_array_interface_set_size:
+ * @self: A #GstByteArrayInterface.
+ * @length: New size.
+ *
+ * Reallocate data pointer to fit at least @length bytes. @self->len is updated
+ * to @length.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ * Since: 1.24
+ */
+static inline gboolean
+gst_byte_array_interface_set_size (GstByteArrayInterface *self, gsize length)
+{
+  if (self->resize == NULL || !self->resize (self, length))
+    return FALSE;
+  self->len = length;
+  return TRUE;
+}
+
+/**
+ * gst_byte_array_interface_append:
+ * @self: A #GstByteArrayInterface.
+ * @size: Number of bytes to append to the array.
+ *
+ * Grow the array by @size bytes and return a pointer to the newly added memory.
+ *
+ * Returns: Pointer to added memory, or %NULL if reallocation failed.
+ * Since: 1.24
+ */
+static inline guint8 *
+gst_byte_array_interface_append (GstByteArrayInterface *self, gsize size)
+{
+  gsize orig = self->len;
+  if (!gst_byte_array_interface_set_size (self, self->len + size))
+    return NULL;
+  return self->data + orig;
+}
+
+/**
+ * gst_byte_array_interface_append_data:
+ * @self: A #GstByteArrayInterface.
+ * @data: Source data.
+ * @size: Size of @data.
+ *
+ * Append @size bytes from @data, reallocating @self->data pointer if necessary.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ * Since: 1.24
+ */
+static inline gboolean
+gst_byte_array_interface_append_data (GstByteArrayInterface *self, const guint8 *data, gsize size)
+{
+  guint8 *ptr = gst_byte_array_interface_append (self, size);
+  if (ptr == NULL)
+    return FALSE;
+  memcpy (ptr, data, size);
+  return TRUE;
+}
+
+G_END_DECLS
diff --git a/gst/gstcaps.c b/gst/gstcaps.c
index 28a7dfe..373e2b4 100644
--- a/gst/gstcaps.c
+++ b/gst/gstcaps.c
@@ -222,7 +222,7 @@ _gst_caps_free (GstCaps * caps)
   memset (caps, 0xff, sizeof (GstCapsImpl));
 #endif
 
-  g_slice_free1 (sizeof (GstCapsImpl), caps);
+  g_free (caps);
 }
 
 static void
@@ -255,7 +255,7 @@ gst_caps_new_empty (void)
 {
   GstCaps *caps;
 
-  caps = (GstCaps *) g_slice_new (GstCapsImpl);
+  caps = (GstCaps *) g_new (GstCapsImpl, 1);
 
   gst_caps_init (caps);
 
@@ -2646,10 +2646,9 @@ gst_caps_map_in_place (GstCaps * caps, GstCapsMapFunc func, gpointer user_data)
  *
  * Calls the provided function once for each structure and caps feature in the
  * #GstCaps. In contrast to gst_caps_foreach(), the function may modify the
- * structure and features. In contrast to gst_caps_filter_and_map_in_place(),
- * the structure and features are removed from the caps if %FALSE is returned
- * from the function.
- * The caps must be mutable.
+ * structure and features. In contrast to gst_caps_map_in_place(), the structure
+ * and features are removed from the caps if %FALSE is returned from the
+ * function. The caps must be mutable.
  *
  * Since: 1.6
  */
diff --git a/gst/gstcapsfeatures.c b/gst/gstcapsfeatures.c
index 243837f..d81169c 100644
--- a/gst/gstcapsfeatures.c
+++ b/gst/gstcapsfeatures.c
@@ -180,7 +180,7 @@ gst_caps_features_new_empty (void)
 {
   GstCapsFeatures *features;
 
-  features = g_slice_new (GstCapsFeatures);
+  features = g_new (GstCapsFeatures, 1);
   features->type = _gst_caps_features_type;
   features->parent_refcount = NULL;
   features->array = g_array_new (FALSE, FALSE, sizeof (GQuark));
@@ -431,7 +431,7 @@ gst_caps_features_free (GstCapsFeatures * features)
 #endif
   GST_TRACE ("free caps features %p", features);
 
-  g_slice_free (GstCapsFeatures, features);
+  g_free (features);
 }
 
 /**
diff --git a/gst/gstclock.c b/gst/gstclock.c
index 365a0e1..ab8a4b0 100644
--- a/gst/gstclock.c
+++ b/gst/gstclock.c
@@ -247,7 +247,7 @@ gst_clock_entry_new (GstClock * clock, GstClockTime time,
 {
   GstClockEntry *entry;
 
-  entry = (GstClockEntry *) g_slice_new0 (GstClockEntryImpl);
+  entry = (GstClockEntry *) g_new0 (GstClockEntryImpl, 1);
 
   /* FIXME: add tracer hook for struct allocations such as clock entries */
 
@@ -382,7 +382,7 @@ _gst_clock_id_free (GstClockID id)
 
   /* FIXME: add tracer hook for struct allocations such as clock entries */
 
-  g_slice_free (GstClockEntryImpl, (GstClockEntryImpl *) id);
+  g_free (id);
 }
 
 /**
@@ -1758,11 +1758,11 @@ gst_clock_set_synced (GstClock * clock, gboolean synced)
           GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC));
 
   GST_OBJECT_LOCK (clock);
-  if (clock->priv->synced != ! !synced) {
-    clock->priv->synced = ! !synced;
+  if (clock->priv->synced != !!synced) {
+    clock->priv->synced = !!synced;
     g_cond_signal (&clock->priv->sync_cond);
     GST_OBJECT_UNLOCK (clock);
-    g_signal_emit (clock, gst_clock_signals[SIGNAL_SYNCED], 0, ! !synced);
+    g_signal_emit (clock, gst_clock_signals[SIGNAL_SYNCED], 0, !!synced);
   } else {
     GST_OBJECT_UNLOCK (clock);
   }
diff --git a/gst/gstclock.h b/gst/gstclock.h
index 46419c9..0649f14 100644
--- a/gst/gstclock.h
+++ b/gst/gstclock.h
@@ -175,18 +175,22 @@ typedef gpointer GstClockID;
  *
  * Converts a #GstClockTime to a GTimeVal
  *
- * > on 32-bit systems, a timeval has a range of only 2^32 - 1 seconds,
- * > which is about 68 years.  Expect trouble if you want to schedule stuff
- * > in your pipeline for 2038.
- */
-#define GST_TIME_TO_TIMEVAL(t,tv)                               \
-G_STMT_START {                                                  \
-  g_assert ("Value of time " #t " is out of timeval's range" && \
-      ((t) / GST_SECOND) < G_MAXLONG);                          \
-  (tv).tv_sec  = (glong) (((GstClockTime) (t)) / GST_SECOND);   \
-  (tv).tv_usec = (glong) ((((GstClockTime) (t)) -               \
-                  ((GstClockTime) (tv).tv_sec) * GST_SECOND)    \
-                 / GST_USECOND);                                \
+ * > on many 32-bit systems, a timeval has a range of only 2^32 - 1 seconds,
+ * > which is about 68 years. Expect trouble if you want to schedule stuff
+ * > in your pipeline for 2038. This macro asserts that this case does not
+ * > happen.
+ */
+#define GST_TIME_TO_TIMEVAL(t,tv)                                           \
+G_STMT_START {                                                              \
+  G_STATIC_ASSERT (sizeof ((tv).tv_sec) == 4 || sizeof ((tv).tv_sec) == 8); \
+  if (sizeof ((tv).tv_sec) == 4) {                                          \
+    g_assert ("Value of time " #t " is out of timeval's range" &&           \
+        ((t) / GST_SECOND) < G_MAXINT32);                                   \
+  }                                                                         \
+  (tv).tv_sec  = (((GstClockTime) (t)) / GST_SECOND);                       \
+  (tv).tv_usec = ((((GstClockTime) (t)) -                                   \
+                  ((GstClockTime) (tv).tv_sec) * GST_SECOND)                \
+                 / GST_USECOND);                                            \
 } G_STMT_END
 
 /**
@@ -203,12 +207,15 @@ G_STMT_START {                                                  \
  *
  * Converts a #GstClockTime to a struct timespec (see `man pselect`)
  */
-#define GST_TIME_TO_TIMESPEC(t,ts)                                \
-G_STMT_START {                                                    \
-  g_assert ("Value of time " #t " is out of timespec's range" &&  \
-      ((t) / GST_SECOND) < G_MAXLONG);                            \
-  (ts).tv_sec  =  (glong) ((t) / GST_SECOND);                     \
-  (ts).tv_nsec = (glong) (((t) - (ts).tv_sec * GST_SECOND) / GST_NSECOND);        \
+#define GST_TIME_TO_TIMESPEC(t,ts)                                          \
+G_STMT_START {                                                              \
+  G_STATIC_ASSERT (sizeof ((ts).tv_sec) == 4 || sizeof ((ts).tv_sec) == 8); \
+  if (sizeof ((ts).tv_sec) == 4) {                                          \
+    g_assert ("Value of time " #t " is out of timespec's range" &&          \
+        ((t) / GST_SECOND) < G_MAXINT32);                                   \
+  }                                                                         \
+  (ts).tv_sec  =  ((t) / GST_SECOND);                                       \
+  (ts).tv_nsec = (((t) - (ts).tv_sec * GST_SECOND) / GST_NSECOND);          \
 } G_STMT_END
 
 /* timestamp debugging macros */
diff --git a/gst/gstcontext.c b/gst/gstcontext.c
index 8d71c00..a1b90be 100644
--- a/gst/gstcontext.c
+++ b/gst/gstcontext.c
@@ -114,7 +114,7 @@ _gst_context_free (GstContext * context)
   memset (context, 0xff, sizeof (GstContext));
 #endif
 
-  g_slice_free1 (sizeof (GstContext), context);
+  g_free (context);
 }
 
 static void gst_context_init (GstContext * context);
@@ -128,7 +128,7 @@ _gst_context_copy (GstContext * context)
   GST_CAT_LOG (GST_CAT_CONTEXT, "copy context %p: %" GST_PTR_FORMAT, context,
       GST_CONTEXT_STRUCTURE (context));
 
-  copy = g_slice_new0 (GstContext);
+  copy = g_new0 (GstContext, 1);
 
   gst_context_init (copy);
 
@@ -171,7 +171,7 @@ gst_context_new (const gchar * context_type, gboolean persistent)
 
   g_return_val_if_fail (context_type != NULL, NULL);
 
-  context = g_slice_new0 (GstContext);
+  context = g_new0 (GstContext, 1);
 
   GST_CAT_LOG (GST_CAT_CONTEXT, "creating new context %p", context);
 
@@ -316,6 +316,25 @@ gst_context_unref (GstContext * context)
   gst_mini_object_unref (GST_MINI_OBJECT_CAST (context));
 }
 
+/**
+ * gst_clear_context: (skip)
+ * @context_ptr: a pointer to a #GstContext reference
+ *
+ * Clears a reference to a #GstContext.
+ *
+ * @context_ptr must not be `NULL`.
+ *
+ * If the reference is `NULL` then this function does nothing. Otherwise, the
+ * reference count of the context is decreased and the pointer is set to `NULL`.
+ *
+ * Since: 1.24
+ */
+void
+gst_clear_context (GstContext ** context_ptr)
+{
+  gst_clear_mini_object ((GstMiniObject **) context_ptr);
+}
+
 /**
  * gst_context_copy:
  * @context: the context to copy
diff --git a/gst/gstcontext.h b/gst/gstcontext.h
index 92d8502..42a7d47 100644
--- a/gst/gstcontext.h
+++ b/gst/gstcontext.h
@@ -59,6 +59,12 @@ gst_context_unref (GstContext * context)
   gst_mini_object_unref (GST_MINI_OBJECT_CAST (context));
 }
 
+static inline void
+gst_clear_context (GstContext ** context_ptr)
+{
+  gst_clear_mini_object ((GstMiniObject **) context_ptr);
+}
+
 /* copy context */
 static inline GstContext *
 gst_context_copy (const GstContext * context)
@@ -72,6 +78,9 @@ GstContext * gst_context_ref    (GstContext * context);
 GST_API
 void         gst_context_unref  (GstContext * context);
 
+GST_API
+void         gst_clear_context  (GstContext ** context_ptr);
+
 GST_API
 GstContext * gst_context_copy   (const GstContext * context);
 #endif /* GST_DISABLE_MINIOBJECT_INLINE_FUNCTIONS */
diff --git a/gst/gstcontrolbinding.c b/gst/gstcontrolbinding.c
index 42c32f1..9715aa2 100644
--- a/gst/gstcontrolbinding.c
+++ b/gst/gstcontrolbinding.c
@@ -491,5 +491,5 @@ gboolean
 gst_control_binding_is_disabled (GstControlBinding * binding)
 {
   g_return_val_if_fail (GST_IS_CONTROL_BINDING (binding), TRUE);
-  return ! !binding->disabled;
+  return !!binding->disabled;
 }
diff --git a/gst/gstdatetime.c b/gst/gstdatetime.c
index 10e73e2..79af88f 100644
--- a/gst/gstdatetime.c
+++ b/gst/gstdatetime.c
@@ -87,7 +87,7 @@ gst_date_time_new_from_g_date_time (GDateTime * dt)
   if (!dt)
     return NULL;
 
-  gst_dt = g_slice_new (GstDateTime);
+  gst_dt = g_new (GstDateTime, 1);
 
   gst_mini_object_init (GST_MINI_OBJECT_CAST (gst_dt), 0, GST_TYPE_DATE_TIME,
       NULL, NULL, (GstMiniObjectFreeFunction) gst_date_time_free);
@@ -334,7 +334,7 @@ gst_date_time_get_microsecond (const GstDateTime * datetime)
  * values, timezones before (to the west) of UTC have negative values.
  * If @datetime represents UTC time, then the offset is zero.
  *
- * Return value: the offset from UTC in hours, or %G_MAXDOUBLE if none is set.
+ * Return value: the offset from UTC in hours, or %G_MAXFLOAT if none is set.
  */
 gfloat
 gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
@@ -342,7 +342,7 @@ gst_date_time_get_time_zone_offset (const GstDateTime * datetime)
   g_return_val_if_fail (datetime != NULL, 0.0);
 
   if (!gst_date_time_has_time (datetime))
-    return G_MAXDOUBLE;
+    return G_MAXFLOAT;
 
   return (g_date_time_get_utc_offset (datetime->datetime) /
       G_USEC_PER_SEC) / 3600.0;
@@ -1047,7 +1047,7 @@ gst_date_time_free (GstDateTime * datetime)
   memset (datetime, 0xff, sizeof (GstDateTime));
 #endif
 
-  g_slice_free (GstDateTime, datetime);
+  g_free (datetime);
 }
 
 /**
diff --git a/gst/gstdebugutils.c b/gst/gstdebugutils.c
index 8ca334a..482b357 100644
--- a/gst/gstdebugutils.c
+++ b/gst/gstdebugutils.c
@@ -82,7 +82,8 @@ static const gchar spaces[] = {
 static gchar *
 debug_dump_make_object_name (GstObject * obj)
 {
-  return g_strcanon (g_strdup_printf ("%s_%p", GST_OBJECT_NAME (obj), obj),
+  /* must start with a letter to prevent dot from splitting names starting with [0-9] */
+  return g_strcanon (g_strdup_printf ("node_%s_%p", GST_OBJECT_NAME (obj), obj),
       G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "_", '_');
 }
 
@@ -922,6 +923,13 @@ gst_debug_bin_to_dot_file_with_ts (GstBin * bin,
 }
 #else /* !GST_DISABLE_GST_DEBUG */
 #ifndef GST_REMOVE_DISABLED
+
+gchar *
+gst_debug_bin_to_dot_data (GstBin * bin, GstDebugGraphDetails details)
+{
+  return g_strdup ("");
+}
+
 void
 gst_debug_bin_to_dot_file (GstBin * bin, GstDebugGraphDetails details,
     const gchar * file_name)
diff --git a/gst/gstdevicemonitor.c b/gst/gstdevicemonitor.c
index c542cad..6eef865 100644
--- a/gst/gstdevicemonitor.c
+++ b/gst/gstdevicemonitor.c
@@ -151,7 +151,7 @@ struct DeviceFilter
 static struct DeviceFilter *
 device_filter_copy (struct DeviceFilter *filter)
 {
-  struct DeviceFilter *copy = g_slice_new0 (struct DeviceFilter);
+  struct DeviceFilter *copy = g_new0 (struct DeviceFilter, 1);
 
   copy->classesv = g_strdupv (filter->classesv);
   copy->caps = filter->caps ? gst_caps_ref (filter->caps) : NULL;
@@ -167,7 +167,7 @@ device_filter_free (struct DeviceFilter *filter)
   if (filter->caps)
     gst_caps_unref (filter->caps);
 
-  g_slice_free (struct DeviceFilter, filter);
+  g_free (filter);
 }
 
 static void
@@ -277,9 +277,9 @@ bus_sync_message (GstBus * bus, GstMessage * message,
       gst_message_parse_device_changed (message, &device, NULL);
 
     GST_OBJECT_LOCK (monitor);
-    provider =
-        GST_DEVICE_PROVIDER (gst_object_get_parent (GST_OBJECT (device)));
-    if (is_provider_hidden (monitor, monitor->priv->hidden, provider)) {
+    provider = GST_DEVICE_PROVIDER (GST_MESSAGE_SRC (message));
+    if (provider &&
+        is_provider_hidden (monitor, monitor->priv->hidden, provider)) {
       matches = FALSE;
     } else {
       guint i;
@@ -299,7 +299,6 @@ bus_sync_message (GstBus * bus, GstMessage * message,
     }
     GST_OBJECT_UNLOCK (monitor);
 
-    gst_object_unref (provider);
     gst_object_unref (device);
 
     if (matches)
@@ -665,7 +664,7 @@ gst_device_monitor_add_filter_unlocked (GstDeviceMonitor * monitor,
   guint id = 0;
   gboolean matched = FALSE;
 
-  filter = g_slice_new0 (struct DeviceFilter);
+  filter = g_new0 (struct DeviceFilter, 1);
   filter->id = monitor->priv->last_id++;
   if (caps)
     filter->caps = gst_caps_ref (caps);
diff --git a/gst/gstdeviceprovider.c b/gst/gstdeviceprovider.c
index f073ede..896721b 100644
--- a/gst/gstdeviceprovider.c
+++ b/gst/gstdeviceprovider.c
@@ -180,8 +180,8 @@ gst_device_provider_dispose (GObject * object)
   gst_object_replace ((GstObject **) & provider->priv->bus, NULL);
 
   GST_OBJECT_LOCK (provider);
-  g_list_free_full (provider->devices, (GDestroyNotify) gst_object_unparent);
-  provider->devices = NULL;
+  g_clear_list (&provider->devices, (GDestroyNotify) gst_object_unparent);
+  g_clear_list (&provider->priv->hidden_providers, (GDestroyNotify) g_free);
   GST_OBJECT_UNLOCK (provider);
 
   G_OBJECT_CLASS (gst_device_provider_parent_class)->dispose (object);
@@ -535,8 +535,8 @@ gst_device_provider_stop (GstDeviceProvider * provider)
     if (klass->stop)
       klass->stop (provider);
     GST_OBJECT_LOCK (provider);
-    g_list_free_full (provider->devices, (GDestroyNotify) gst_object_unparent);
-    provider->devices = NULL;
+    g_clear_list (&provider->devices, (GDestroyNotify) gst_object_unparent);
+    g_clear_list (&provider->priv->hidden_providers, (GDestroyNotify) g_free);
     GST_OBJECT_UNLOCK (provider);
   } else if (provider->priv->started_count < 1) {
     g_critical
diff --git a/gst/gstelement.c b/gst/gstelement.c
index 154b612..10ce62b 100644
--- a/gst/gstelement.c
+++ b/gst/gstelement.c
@@ -2500,72 +2500,80 @@ gst_element_get_state_func (GstElement * element,
 {
   GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
   GstState old_pending;
+  gint64 end_time;
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "getting state, timeout %"
       GST_TIME_FORMAT, GST_TIME_ARGS (timeout));
 
   GST_OBJECT_LOCK (element);
-  ret = GST_STATE_RETURN (element);
-  GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s",
-      gst_element_state_change_return_get_name (ret));
 
-  /* we got an error, report immediately */
-  if (ret == GST_STATE_CHANGE_FAILURE)
-    goto done;
+  if (timeout != GST_CLOCK_TIME_NONE) {
+    /* make timeout absolute */
+    end_time = g_get_monotonic_time () + (timeout / 1000);
+  }
 
-  /* we got no_preroll, report immediately */
-  if (ret == GST_STATE_CHANGE_NO_PREROLL)
-    goto done;
+  do {
+    ret = GST_STATE_RETURN (element);
+    GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s",
+        gst_element_state_change_return_get_name (ret));
 
-  /* no need to wait async if we are not async */
-  if (ret != GST_STATE_CHANGE_ASYNC)
-    goto done;
+    /* we got an error, report immediately */
+    if (ret == GST_STATE_CHANGE_FAILURE)
+      goto done;
 
-  old_pending = GST_STATE_PENDING (element);
-  if (old_pending != GST_STATE_VOID_PENDING) {
-    gboolean signaled;
-    guint32 cookie;
+    /* we got no_preroll, report immediately */
+    if (ret == GST_STATE_CHANGE_NO_PREROLL)
+      goto done;
 
-    /* get cookie to detect state changes during waiting */
-    cookie = element->state_cookie;
+    /* no need to wait async if we are not async */
+    if (ret != GST_STATE_CHANGE_ASYNC)
+      goto done;
 
-    GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
-        "waiting for element to commit state");
-
-    /* we have a pending state change, wait for it to complete */
-    if (timeout != GST_CLOCK_TIME_NONE) {
-      gint64 end_time;
-      /* make timeout absolute */
-      end_time = g_get_monotonic_time () + (timeout / 1000);
-      signaled = GST_STATE_WAIT_UNTIL (element, end_time);
-    } else {
-      GST_STATE_WAIT (element);
-      signaled = TRUE;
-    }
+    old_pending = GST_STATE_PENDING (element);
+    if (old_pending != GST_STATE_VOID_PENDING) {
+      gboolean signaled = TRUE;
+      guint32 cookie;
 
-    if (!signaled) {
-      GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "timed out");
-      /* timeout triggered */
-      ret = GST_STATE_CHANGE_ASYNC;
-    } else {
-      if (cookie != element->state_cookie)
-        goto interrupted;
+      /* get cookie to detect state changes during waiting */
+      cookie = element->state_cookie;
 
-      /* could be success or failure */
-      if (old_pending == GST_STATE (element)) {
-        GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "got success");
-        ret = GST_STATE_CHANGE_SUCCESS;
+      GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
+          "waiting for element to commit state");
+
+      /* we have a pending state change, wait for it to complete or for
+         an interruption */
+      if (timeout != GST_CLOCK_TIME_NONE) {
+        signaled = GST_STATE_WAIT_UNTIL (element, end_time);
       } else {
-        GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "got failure");
-        ret = GST_STATE_CHANGE_FAILURE;
+        GST_STATE_WAIT (element);
+        signaled = TRUE;
+      }
+
+      if (!signaled) {
+        GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "timed out");
+        /* timeout triggered */
+        ret = GST_STATE_CHANGE_ASYNC;
+        goto done;
+      } else {
+        if (cookie != element->state_cookie)
+          goto interrupted;
+
+        /* could be success or failure */
+        if (old_pending == GST_STATE (element)) {
+          GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "got success");
+          ret = GST_STATE_CHANGE_SUCCESS;
+        } else {
+          GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "got failure");
+          ret = GST_STATE_CHANGE_FAILURE;
+        }
+      }
+      /* if nothing is pending anymore we can return SUCCESS */
+      if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING) {
+        GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "nothing pending");
+        ret = GST_STATE_CHANGE_SUCCESS;
       }
     }
-    /* if nothing is pending anymore we can return SUCCESS */
-    if (GST_STATE_PENDING (element) == GST_STATE_VOID_PENDING) {
-      GST_CAT_LOG_OBJECT (GST_CAT_STATES, element, "nothing pending");
-      ret = GST_STATE_CHANGE_SUCCESS;
-    }
-  }
+  } while (old_pending != GST_STATE (element));
 
 done:
   if (state)
diff --git a/gst/gstelementfactory.c b/gst/gstelementfactory.c
index ea3427a..2bbe943 100644
--- a/gst/gstelementfactory.c
+++ b/gst/gstelementfactory.c
@@ -163,7 +163,7 @@ gst_element_factory_cleanup (GstElementFactory * factory)
     GstStaticPadTemplate *templ = item->data;
 
     gst_static_caps_cleanup (&templ->static_caps);
-    g_slice_free (GstStaticPadTemplate, templ);
+    g_free (templ);
   }
   g_list_free (factory->staticpadtemplates);
   factory->staticpadtemplates = NULL;
@@ -257,7 +257,7 @@ gst_element_register (GstPlugin * plugin, const gchar * name, guint rank,
     GstStaticPadTemplate *newt;
     gchar *caps_string = gst_caps_to_string (templ->caps);
 
-    newt = g_slice_new (GstStaticPadTemplate);
+    newt = g_new (GstStaticPadTemplate, 1);
     newt->name_template = g_intern_string (templ->name_template);
     newt->direction = templ->direction;
     newt->presence = templ->presence;
@@ -1084,6 +1084,10 @@ gst_element_factory_list_is_type (GstElementFactory * factory,
     res = ((strstr (klass, "Parser") != NULL)
         && (strstr (klass, "Codec") != NULL));
 
+  if (!res && (type & GST_ELEMENT_FACTORY_TYPE_TIMESTAMPER))
+    res = ((strstr (klass, "Timestamper") != NULL)
+        && (strstr (klass, "Codec") != NULL));
+
   if (!res && (type & GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER))
     res = (strstr (klass, "Depayloader") != NULL);
 
diff --git a/gst/gstelementfactory.h b/gst/gstelementfactory.h
index 07f3f81..b3749a6 100644
--- a/gst/gstelementfactory.h
+++ b/gst/gstelementfactory.h
@@ -165,6 +165,14 @@ typedef guint64 GstElementFactoryListType;
 #define  GST_ELEMENT_FACTORY_TYPE_DECRYPTOR      ((GstElementFactoryListType)(G_GUINT64_CONSTANT (1) << 10))
 #define  GST_ELEMENT_FACTORY_TYPE_ENCRYPTOR      ((GstElementFactoryListType)(G_GUINT64_CONSTANT (1) << 11))
 #define  GST_ELEMENT_FACTORY_TYPE_HARDWARE      ((GstElementFactoryListType)(G_GUINT64_CONSTANT (1) << 12))
+/**
+ * GST_ELEMENT_FACTORY_TYPE_TIMESTAMPER:
+ *
+ * Timestamp correcting elements
+ *
+ * Since: 1.24
+ */
+#define  GST_ELEMENT_FACTORY_TYPE_TIMESTAMPER    ((GstElementFactoryListType)(G_GUINT64_CONSTANT (1) << 13))
 
 #define  GST_ELEMENT_FACTORY_TYPE_MAX_ELEMENTS   ((GstElementFactoryListType)(G_GUINT64_CONSTANT (1) << 48))
 
diff --git a/gst/gstevent.c b/gst/gstevent.c
index 0bd4ac0..5032f1c 100644
--- a/gst/gstevent.c
+++ b/gst/gstevent.c
@@ -261,7 +261,7 @@ _gst_event_free (GstEvent * event)
   memset (event, 0xff, sizeof (GstEventImpl));
 #endif
 
-  g_slice_free1 (sizeof (GstEventImpl), event);
+  g_free (event);
 }
 
 static void gst_event_init (GstEventImpl * event, GstEventType type);
@@ -272,7 +272,7 @@ _gst_event_copy (GstEvent * event)
   GstEventImpl *copy;
   GstStructure *s;
 
-  copy = g_slice_new0 (GstEventImpl);
+  copy = g_new0 (GstEventImpl, 1);
 
   gst_event_init (copy, GST_EVENT_TYPE (event));
 
@@ -332,7 +332,7 @@ gst_event_new_custom (GstEventType type, GstStructure * structure)
 {
   GstEventImpl *event;
 
-  event = g_slice_new0 (GstEventImpl);
+  event = g_new0 (GstEventImpl, 1);
 
   GST_CAT_DEBUG (GST_CAT_EVENT, "creating new event %p %s %d", event,
       gst_event_type_get_name (type), type);
@@ -353,7 +353,7 @@ gst_event_new_custom (GstEventType type, GstStructure * structure)
   /* ERRORS */
 had_parent:
   {
-    g_slice_free1 (sizeof (GstEventImpl), event);
+    g_free (event);
     g_warning ("structure is already owned by another object");
     return NULL;
   }
diff --git a/gst/gstformat.c b/gst/gstformat.c
index 130fc77..b9f2560 100644
--- a/gst/gstformat.c
+++ b/gst/gstformat.c
@@ -153,7 +153,7 @@ gst_format_register (const gchar * nick, const gchar * description)
     return query;
 
   g_mutex_lock (&mutex);
-  format = g_slice_new (GstFormatDefinition);
+  format = g_new (GstFormatDefinition, 1);
   format->value = (GstFormat) _n_values;
   format->nick = g_strdup (nick);
   format->description = g_strdup (description);
diff --git a/gst/gstinfo.c b/gst/gstinfo.c
index e5efe8f..4e61dcd 100644
--- a/gst/gstinfo.c
+++ b/gst/gstinfo.c
@@ -106,9 +106,6 @@
 #include "gstvalue.h"
 #include "gstcapsfeatures.h"
 
-#ifdef HAVE_VALGRIND_VALGRIND_H
-#  include <valgrind/valgrind.h>
-#endif
 #endif /* GST_DISABLE_GST_DEBUG */
 
 #include <glib/gprintf.h>       /* g_sprintf */
@@ -1722,7 +1719,7 @@ gst_debug_add_log_function (GstLogFunction func, gpointer user_data,
   if (func == NULL)
     func = gst_debug_log_default;
 
-  entry = g_slice_new (LogFuncEntry);
+  entry = g_new (LogFuncEntry, 1);
   entry->func = func;
   entry->user_data = user_data;
   entry->notify = notify;
@@ -1789,7 +1786,7 @@ gst_debug_remove_with_compare_func (GCompareFunc func, gpointer data)
     if (entry->notify)
       entry->notify (entry->user_data);
 
-    g_slice_free (LogFuncEntry, entry);
+    g_free (entry);
     cleanup = g_slist_delete_link (cleanup, cleanup);
   }
   return removals;
@@ -2074,7 +2071,7 @@ gst_debug_set_threshold_for_name (const gchar * name, GstDebugLevel level)
   g_return_if_fail (name != NULL);
 
   pat = g_pattern_spec_new (name);
-  entry = g_slice_new (LevelNameEntry);
+  entry = g_new (LevelNameEntry, 1);
   entry->pat = pat;
   entry->level = level;
   g_mutex_lock (&__level_name_mutex);
@@ -2109,7 +2106,7 @@ gst_debug_unset_threshold_for_name (const gchar * name)
     if (g_pattern_spec_equal (entry->pat, pat)) {
       __level_name = g_slist_remove_link (__level_name, walk);
       g_pattern_spec_free (entry->pat);
-      g_slice_free (LevelNameEntry, entry);
+      g_free (entry);
       g_slist_free_1 (walk);
       walk = __level_name;
     } else {
@@ -2129,7 +2126,7 @@ _gst_debug_category_new (const gchar * name, guint color,
 
   g_return_val_if_fail (name != NULL, NULL);
 
-  cat = g_slice_new (GstDebugCategory);
+  cat = g_new (GstDebugCategory, 1);
   cat->name = g_strdup (name);
   cat->color = color;
   if (description != NULL) {
@@ -2146,7 +2143,7 @@ _gst_debug_category_new (const gchar * name, guint color,
   if (catfound) {
     g_free ((gpointer) cat->name);
     g_free ((gpointer) cat->description);
-    g_slice_free (GstDebugCategory, cat);
+    g_free (cat);
     cat = catfound;
   } else {
     __categories = g_slist_prepend (__categories, cat);
@@ -2387,8 +2384,8 @@ parse_debug_level (gchar * str, GstDebugLevel * level)
  * %FALSE if adding the threshold described by @list to the one already set.
  *
  * Sets the debug logging wanted in the same form as with the GST_DEBUG
- * environment variable. You can use wildcards such as '*', but note that
- * the order matters when you use wild cards, e.g. "foosrc:6,*src:3,*:2" sets
+ * environment variable. You can use wildcards such as `*`, but note that
+ * the order matters when you use wild cards, e.g. `foosrc:6,*src:3,*:2` sets
  * everything to log level 2.
  *
  * Since: 1.2
@@ -2511,7 +2508,7 @@ clear_level_names (void)
   while (__level_name) {
     LevelNameEntry *level_name_entry = __level_name->data;
     g_pattern_spec_free (level_name_entry->pat);
-    g_slice_free (LevelNameEntry, level_name_entry);
+    g_free (level_name_entry);
     __level_name = g_slist_delete_link (__level_name, __level_name);
   }
   g_mutex_unlock (&__level_name_mutex);
@@ -2534,7 +2531,7 @@ _priv_gst_debug_cleanup (void)
     GstDebugCategory *cat = __categories->data;
     g_free ((gpointer) cat->name);
     g_free ((gpointer) cat->description);
-    g_slice_free (GstDebugCategory, cat);
+    g_free (cat);
     __categories = g_slist_delete_link (__categories, __categories);
   }
   g_mutex_unlock (&__cat_mutex);
@@ -2546,7 +2543,7 @@ _priv_gst_debug_cleanup (void)
     LogFuncEntry *log_func_entry = __log_functions->data;
     if (log_func_entry->notify)
       log_func_entry->notify (log_func_entry->user_data);
-    g_slice_free (LogFuncEntry, log_func_entry);
+    g_free (log_func_entry);
     __log_functions = g_slist_delete_link (__log_functions, __log_functions);
   }
   g_mutex_unlock (&__log_func_mutex);
@@ -2687,6 +2684,13 @@ gst_debug_log_literal (GstDebugCategory * category, GstDebugLevel level,
 {
 }
 
+void
+gst_debug_log_id_literal (GstDebugCategory * category, GstDebugLevel level,
+    const gchar * file, const gchar * function, gint line,
+    const gchar * id, const gchar * message_string)
+{
+}
+
 const gchar *
 gst_debug_message_get (GstDebugMessage * message)
 {
diff --git a/gst/gstiterator.c b/gst/gstiterator.c
index af8d2b1..6d469d7 100644
--- a/gst/gstiterator.c
+++ b/gst/gstiterator.c
@@ -68,6 +68,7 @@
  */
 
 #include "gst_private.h"
+#include "glib-compat-private.h"
 #include <gst/gstiterator.h>
 
 /**
@@ -83,7 +84,7 @@ gst_iterator_copy (const GstIterator * it)
 {
   GstIterator *copy;
 
-  copy = g_slice_copy (it->size, it);
+  copy = g_memdup2 (it, it->size);
   if (it->copy)
     it->copy (it, copy);
 
@@ -159,7 +160,7 @@ gst_iterator_new (guint size,
   g_return_val_if_fail (resync != NULL, NULL);
   g_return_val_if_fail (free != NULL, NULL);
 
-  result = g_slice_alloc0 (size);
+  result = g_malloc0 (size);
   gst_iterator_init (result, size, type, lock, master_cookie, copy, next, item,
       resync, free);
 
@@ -422,7 +423,7 @@ gst_iterator_free (GstIterator * it)
 
   it->free (it);
 
-  g_slice_free1 (it->size, it);
+  g_free (it);
 }
 
 /**
@@ -485,6 +486,7 @@ filter_next (GstIteratorFilter * it, GValue * elem)
         break;
       case GST_ITERATOR_RESYNC:
       case GST_ITERATOR_DONE:
+      case GST_ITERATOR_ERROR:
         done = TRUE;
         break;
       default:
diff --git a/gst/gstmacos.m b/gst/gstmacos.m
index e0cd09b..bb943ac 100644
--- a/gst/gstmacos.m
+++ b/gst/gstmacos.m
@@ -9,11 +9,40 @@ struct _ThreadArgs {
   char **argv;
   gpointer user_data;
   gboolean is_simple;
+  GMutex nsapp_mutex;
+  GCond nsapp_cond;
+  gboolean nsapp_running;
 };
 
+@interface GstCocoaApplicationDelegate : NSObject <NSApplicationDelegate>
+@property (assign) GMutex *nsapp_mutex;
+@property (assign) GCond *nsapp_cond;
+@property (assign) gboolean *nsapp_running;
+@end
+
+@implementation GstCocoaApplicationDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification *)notification
+{
+  g_mutex_lock (self.nsapp_mutex);
+  *self.nsapp_running = TRUE;
+  g_cond_signal (self.nsapp_cond);
+  g_mutex_unlock (self.nsapp_mutex);
+}
+
+@end
+
 int
 gst_thread_func (ThreadArgs *args)
 {
+  /* Only proceed once NSApp is running, otherwise we could
+   * attempt to call [NSApp: stop] before it's even started. */
+  g_mutex_lock (&args->nsapp_mutex);
+  while (!args->nsapp_running) {
+    g_cond_wait (&args->nsapp_cond, &args->nsapp_mutex);
+  }
+  g_mutex_unlock (&args->nsapp_mutex);
+
   int ret;
   if (args->is_simple) {
     ret = ((GstMainFuncSimple) args->main_func) (args->user_data);
@@ -21,7 +50,20 @@ gst_thread_func (ThreadArgs *args)
     ret = ((GstMainFunc) args->main_func) (args->argc, args->argv, args->user_data);
   }
 
-  [NSApp terminate: nil];
+  /* Post a message so we'll break out of the message loop */
+  NSEvent *event = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
+                       location: NSZeroPoint
+                  modifierFlags: 0
+                      timestamp: 0
+                   windowNumber: 0
+                        context: nil
+                        subtype: NSEventSubtypeApplicationActivated
+                          data1: 0
+                          data2: 0];
+
+  [NSApp stop:nil];
+  [NSApp postEvent:event atStart:YES];
+
   return ret;
 }
 
@@ -29,12 +71,33 @@ int
 run_main_with_nsapp (ThreadArgs args)
 {
   GThread *gst_thread;
+  GstCocoaApplicationDelegate* delegate;
+  int result;
+
+  g_mutex_init (&args.nsapp_mutex);
+  g_cond_init (&args.nsapp_cond);
+  args.nsapp_running = FALSE;
+
+  [NSApplication sharedApplication];
+  delegate = [[GstCocoaApplicationDelegate alloc] init];
+  delegate.nsapp_mutex = &args.nsapp_mutex;
+  delegate.nsapp_cond = &args.nsapp_cond;
+  delegate.nsapp_running = &args.nsapp_running;
+  [NSApp setDelegate:delegate];
+
+  /* This lets us show an icon in the dock and correctly focus opened windows */
+  if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
+    [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
+  }
 
-  [NSApplication sharedApplication]; 
   gst_thread = g_thread_new ("macos-gst-thread", (GThreadFunc) gst_thread_func, &args);
   [NSApp run];
+  result = GPOINTER_TO_INT (g_thread_join (gst_thread));
+
+  g_mutex_clear (&args.nsapp_mutex);
+  g_cond_clear (&args.nsapp_cond);
 
-  return GPOINTER_TO_INT (g_thread_join (gst_thread));
+  return result;
 }
 
 /**
@@ -44,11 +107,11 @@ run_main_with_nsapp (ThreadArgs args)
  * @argv: (array length=argc): an array of arguments to be passed to the main function
  * @user_data: (nullable): user data to be passed to the main function
  *
- * Starts an NSApplication on the main thread before calling 
- * the provided main() function on a secondary thread. 
- * 
- * This ensures that GStreamer can correctly perform actions 
- * such as creating a GL window, which require a Cocoa main loop 
+ * Starts an NSApplication on the main thread before calling
+ * the provided main() function on a secondary thread.
+ *
+ * This ensures that GStreamer can correctly perform actions
+ * such as creating a GL window, which require a Cocoa main loop
  * to be running on the main thread.
  *
  * Do not call this function more than once - especially while
@@ -86,7 +149,7 @@ gst_macos_main (GstMainFunc main_func, int argc, char **argv, gpointer user_data
  *
  * Since: 1.22
  */
-int 
+int
 gst_macos_main_simple (GstMainFuncSimple main_func, gpointer user_data)
 {
   ThreadArgs args;
diff --git a/gst/gstmessage.c b/gst/gstmessage.c
index f6ecbe3..f2dd883 100644
--- a/gst/gstmessage.c
+++ b/gst/gstmessage.c
@@ -223,7 +223,7 @@ _gst_message_free (GstMessage * message)
   memset (message, 0xff, sizeof (GstMessageImpl));
 #endif
 
-  g_slice_free1 (sizeof (GstMessageImpl), message);
+  g_free (message);
 }
 
 static void
@@ -240,7 +240,7 @@ _gst_message_copy (GstMessage * message)
       GST_MESSAGE_TYPE_NAME (message),
       GST_OBJECT_NAME (GST_MESSAGE_SRC (message)));
 
-  copy = g_slice_new0 (GstMessageImpl);
+  copy = g_new0 (GstMessageImpl, 1);
 
   gst_message_init (copy, GST_MESSAGE_TYPE (message),
       GST_MESSAGE_SRC (message));
@@ -299,7 +299,7 @@ gst_message_new_custom (GstMessageType type, GstObject * src,
 {
   GstMessageImpl *message;
 
-  message = g_slice_new0 (GstMessageImpl);
+  message = g_new0 (GstMessageImpl, 1);
 
   GST_CAT_LOG (GST_CAT_MESSAGE, "source %s: creating new message %p %s",
       (src ? GST_OBJECT_NAME (src) : "NULL"), message,
@@ -320,7 +320,7 @@ gst_message_new_custom (GstMessageType type, GstObject * src,
   /* ERRORS */
 had_parent:
   {
-    g_slice_free1 (sizeof (GstMessageImpl), message);
+    g_free (message);
     g_warning ("structure is already owned by another object");
     return NULL;
   }
diff --git a/gst/gstmeta.c b/gst/gstmeta.c
index 9fc6198..6667aff 100644
--- a/gst/gstmeta.c
+++ b/gst/gstmeta.c
@@ -59,13 +59,6 @@ GQuark _gst_meta_transform_copy;
 GQuark _gst_meta_tag_memory;
 GQuark _gst_meta_tag_memory_reference;
 
-typedef struct
-{
-  GstCustomMeta meta;
-
-  GstStructure *structure;
-} GstCustomMetaImpl;
-
 typedef struct
 {
   GstMetaInfo info;
@@ -78,7 +71,7 @@ typedef struct
 static void
 free_info (gpointer data)
 {
-  g_slice_free (GstMetaInfoImpl, data);
+  g_free (data);
 }
 
 void
@@ -154,7 +147,7 @@ gst_meta_api_type_register (const gchar * api, const gchar ** tags)
 static gboolean
 custom_init_func (GstMeta * meta, gpointer params, GstBuffer * buffer)
 {
-  GstCustomMetaImpl *cmeta = (GstCustomMetaImpl *) meta;
+  GstCustomMeta *cmeta = (GstCustomMeta *) meta;
 
   cmeta->structure = gst_structure_new_empty (g_type_name (meta->info->type));
 
@@ -167,7 +160,7 @@ custom_init_func (GstMeta * meta, gpointer params, GstBuffer * buffer)
 static void
 custom_free_func (GstMeta * meta, GstBuffer * buffer)
 {
-  GstCustomMetaImpl *cmeta = (GstCustomMetaImpl *) meta;
+  GstCustomMeta *cmeta = (GstCustomMeta *) meta;
 
   gst_structure_set_parent_refcount (cmeta->structure, NULL);
   gst_structure_free (cmeta->structure);
@@ -177,16 +170,15 @@ static gboolean
 custom_transform_func (GstBuffer * transbuf, GstMeta * meta,
     GstBuffer * buffer, GQuark type, gpointer data)
 {
-  GstCustomMetaImpl *custom, *cmeta = (GstCustomMetaImpl *) meta;
+  GstCustomMeta *custom, *cmeta = (GstCustomMeta *) meta;
   GstMetaInfoImpl *info = (GstMetaInfoImpl *) meta->info;
 
   if (info->custom_transform_func)
-    return info->custom_transform_func (transbuf, (GstCustomMeta *) meta,
+    return info->custom_transform_func (transbuf, cmeta,
         buffer, type, data, info->custom_transform_user_data);
 
   if (GST_META_TRANSFORM_IS_COPY (type)) {
-    custom =
-        (GstCustomMetaImpl *) gst_buffer_add_meta (transbuf, meta->info, NULL);
+    custom = (GstCustomMeta *) gst_buffer_add_meta (transbuf, meta->info, NULL);
     gst_structure_set_parent_refcount (custom->structure, NULL);
     gst_structure_take (&custom->structure,
         gst_structure_copy (cmeta->structure));
@@ -199,6 +191,46 @@ custom_transform_func (GstBuffer * transbuf, GstMeta * meta,
   return TRUE;
 }
 
+static gboolean
+custom_serialize_func (const GstMeta * meta, GstByteArrayInterface * data,
+    guint8 * version)
+{
+  const GstCustomMeta *cmeta = (const GstCustomMeta *) meta;
+  gchar *str = gst_structure_serialize_full (cmeta->structure,
+      GST_SERIALIZE_FLAG_STRICT);
+  if (str == NULL)
+    return FALSE;
+
+  gboolean ret = gst_byte_array_interface_append_data (data, (guint8 *) str,
+      strlen (str) + 1);
+  g_free (str);
+
+  return ret;
+}
+
+static GstMeta *
+custom_deserialize_func (const GstMetaInfo * info, GstBuffer * buffer,
+    const guint8 * data, gsize size, guint8 version)
+{
+  if (version != 0 || size < 1 || data[size - 1] != '\0')
+    return NULL;
+
+  GstStructure *structure =
+      gst_structure_new_from_string ((const gchar *) data);
+  if (structure == NULL)
+    return NULL;
+
+  GstMeta *meta = gst_buffer_add_meta (buffer, info, NULL);
+  GstCustomMeta *cmeta = (GstCustomMeta *) meta;
+
+  gst_structure_set_parent_refcount (cmeta->structure, NULL);
+  gst_structure_take (&cmeta->structure, structure);
+  gst_structure_set_parent_refcount (cmeta->structure,
+      &GST_MINI_OBJECT_REFCOUNT (buffer));
+
+  return meta;
+}
+
 /**
  * gst_custom_meta_get_structure:
  *
@@ -215,7 +247,7 @@ gst_custom_meta_get_structure (GstCustomMeta * meta)
   g_return_val_if_fail (gst_meta_info_is_custom (((GstMeta *) meta)->info),
       NULL);
 
-  return ((GstCustomMetaImpl *) meta)->structure;
+  return meta->structure;
 }
 
 /**
@@ -233,7 +265,7 @@ gst_custom_meta_has_name (GstCustomMeta * meta, const gchar * name)
   g_return_val_if_fail (gst_meta_info_is_custom (((GstMeta *) meta)->info),
       FALSE);
 
-  return gst_structure_has_name (((GstCustomMetaImpl *) meta)->structure, name);
+  return gst_structure_has_name (meta->structure, name);
 }
 
 /**
@@ -269,8 +301,9 @@ gst_meta_register_custom (const gchar * name, const gchar ** tags,
 {
   gchar *api_name = g_strdup_printf ("%s-api", name);
   GType api;
-  GstMetaInfoImpl *info;
-  GstMetaInfo *ret = NULL;
+  GstMetaInfo *info;
+  GstMetaInfoImpl *impl;
+  const GstMetaInfo *ret = NULL;
 
   g_return_val_if_fail (tags != NULL, NULL);
   g_return_val_if_fail (name != NULL, NULL);
@@ -280,24 +313,46 @@ gst_meta_register_custom (const gchar * name, const gchar ** tags,
   if (api == G_TYPE_INVALID)
     goto done;
 
-  info = (GstMetaInfoImpl *) gst_meta_register (api, name,
-      sizeof (GstCustomMetaImpl),
-      custom_init_func, custom_free_func, custom_transform_func);
-
-  if (!info)
+  info = gst_meta_info_new (api, name, sizeof (GstCustomMeta));
+  if (info == NULL)
     goto done;
 
-  info->is_custom = TRUE;
-  info->custom_transform_func = transform_func;
-  info->custom_transform_user_data = user_data;
-  info->custom_transform_destroy_notify = destroy_data;
+  impl = (GstMetaInfoImpl *) info;
+
+  info->init_func = custom_init_func;
+  info->free_func = custom_free_func;
+  info->transform_func = custom_transform_func;
+  info->serialize_func = custom_serialize_func;
+  info->deserialize_func = custom_deserialize_func;
 
-  ret = (GstMetaInfo *) info;
+  impl->is_custom = TRUE;
+  impl->custom_transform_func = transform_func;
+  impl->custom_transform_user_data = user_data;
+  impl->custom_transform_destroy_notify = destroy_data;
+
+  ret = gst_meta_info_register (info);
 
 done:
   return ret;
 }
 
+/**
+ * gst_meta_register_custom_simple:
+ * @name: the name of the #GstMeta implementation
+ *
+ * Simplified version of gst_meta_register_custom(), with no tags and no
+ * transform function.
+ *
+ * Returns: (transfer none): a #GstMetaInfo that can be used to access metadata.
+ * Since: 1.24
+ */
+const GstMetaInfo *
+gst_meta_register_custom_simple (const gchar * name)
+{
+  const gchar *tags[] = { NULL };
+  return gst_meta_register_custom (name, tags, NULL, NULL, NULL);
+}
+
 /**
  * gst_meta_info_is_custom:
  *
@@ -353,14 +408,40 @@ gst_meta_api_type_get_tags (GType api)
   return (const gchar * const *) tags;
 }
 
+static const GstMetaInfo *
+gst_meta_register_internal (GType api, const gchar * impl, gsize size,
+    GstMetaInitFunction init_func, GstMetaFreeFunction free_func,
+    GstMetaTransformFunction transform_func,
+    GstMetaSerializeFunction serialize_func,
+    GstMetaDeserializeFunction deserialize_func)
+{
+  GstMetaInfo *info;
+  if (init_func == NULL)
+    g_critical ("Registering meta implementation '%s' without init function",
+        impl);
+
+  info = gst_meta_info_new (api, impl, size);
+  if (info == NULL)
+    return NULL;
+
+  info->init_func = init_func;
+  info->free_func = free_func;
+  info->transform_func = transform_func;
+  info->serialize_func = serialize_func;
+  info->deserialize_func = deserialize_func;
+  ((GstMetaInfoImpl *) info)->is_custom = FALSE;
+
+  return gst_meta_info_register (info);
+}
+
 /**
- * gst_meta_register:
+ * gst_meta_register: (skip):
  * @api: the type of the #GstMeta API
  * @impl: the name of the #GstMeta implementation
  * @size: the size of the #GstMeta structure
- * @init_func: (scope async): a #GstMetaInitFunction
- * @free_func: (scope async): a #GstMetaFreeFunction
- * @transform_func: (scope async): a #GstMetaTransformFunction
+ * @init_func: a #GstMetaInitFunction
+ * @free_func: a #GstMetaFreeFunction
+ * @transform_func: a #GstMetaTransformFunction
  *
  * Register a new #GstMeta implementation.
  *
@@ -370,46 +451,110 @@ gst_meta_api_type_get_tags (GType api)
  * Returns: (transfer none): a #GstMetaInfo that can be used to
  * access metadata.
  */
-
 const GstMetaInfo *
 gst_meta_register (GType api, const gchar * impl, gsize size,
     GstMetaInitFunction init_func, GstMetaFreeFunction free_func,
     GstMetaTransformFunction transform_func)
 {
-  GstMetaInfo *info;
+  return gst_meta_register_internal (api, impl, size, init_func, free_func,
+      transform_func, NULL, NULL);
+}
+
+/**
+ * gst_meta_info_new: (skip):
+ * @api:  the type of the #GstMeta API
+ * @impl: the name of the #GstMeta implementation
+ * @size: the size of the #GstMeta structure
+ *
+ * Creates a new structure that needs to be filled before being
+ * registered.  This structure should filled and then registered with
+ * gst_meta_info_register().
+ *
+ * Example:
+ * ```c
+ * const GstMetaInfo *
+ * gst_my_meta_get_info (void)
+ * {
+ *   static const GstMetaInfo *meta_info = NULL;
+ *
+ *   if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {
+ *     GstMetaInfo *info = gst_meta_info_new (
+ *       gst_my_meta_api_get_type (),
+ *         "GstMyMeta",
+ *        sizeof (GstMyMeta));
+ *     const GstMetaInfo *meta = NULL;
+ *
+ *     info->init_func = my_meta_init;
+ *     info->free_func = my_meta_free;
+ *     info->transform_func = my_meta_transform;
+ *     info->serialize_func = my_meta_serialize;
+ *     info->deserialize_func = my_meta_deserialize;
+ *     meta = gst_meta_info_register (info);
+ *     g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) meta);
+ *   }
+ *
+ *   return meta_info;
+ * }
+ * ```
+ *
+ * Returns: a new #GstMetaInfo that needs to be filled
+ *
+ * Since: 1.24
+ */
+
+GstMetaInfo *
+gst_meta_info_new (GType api, const gchar * impl, gsize size)
+{
   GType type;
+  GstMetaInfo *info;
 
   g_return_val_if_fail (api != 0, NULL);
   g_return_val_if_fail (impl != NULL, NULL);
   g_return_val_if_fail (size != 0, NULL);
 
-  if (init_func == NULL)
-    g_critical ("Registering meta implementation '%s' without init function",
-        impl);
-
   /* first try to register the implementation name. It's possible
    * that this fails because it was already registered. Don't warn,
    * glib did this for us already. */
   type = g_pointer_type_register_static (impl);
-  if (type == G_TYPE_INVALID)
-    return NULL;
 
-  info = (GstMetaInfo *) g_slice_new (GstMetaInfoImpl);
+  info = (GstMetaInfo *) g_new0 (GstMetaInfoImpl, 1);
   info->api = api;
   info->type = type;
   info->size = size;
-  info->init_func = init_func;
-  info->free_func = free_func;
-  info->transform_func = transform_func;
-  ((GstMetaInfoImpl *) info)->is_custom = FALSE;
+
+  return info;
+}
+
+/**
+ * gst_meta_info_register:
+ * @info: (transfer full): a new #GstMetaInfo created by gst_meta_info_new()
+ *
+ * Registers a new meta.
+ *
+ * Use the structure returned by gst_meta_info_new(), it consumes it and the
+ * structure shouldnt be used after. The one returned by the function can be
+ * kept.
+ *
+ * Returns: (transfer none): the registered meta
+ *
+ * Since: 1.24
+ */
+
+const GstMetaInfo *
+gst_meta_info_register (GstMetaInfo * info)
+{
+  if (info->type == G_TYPE_INVALID) {
+    g_free (info);
+    return NULL;
+  }
 
   GST_CAT_DEBUG (GST_CAT_META,
-      "register \"%s\" implementing \"%s\" of size %" G_GSIZE_FORMAT, impl,
-      g_type_name (api), size);
+      "register \"%s\" implementing \"%s\" of size %" G_GSIZE_FORMAT,
+      g_type_name (info->type), g_type_name (info->api), info->size);
 
   g_rw_lock_writer_lock (&lock);
-  g_hash_table_insert (metainfo, (gpointer) g_intern_string (impl),
-      (gpointer) info);
+  g_hash_table_insert (metainfo,
+      (gpointer) g_intern_string (g_type_name (info->type)), (gpointer) info);
   g_rw_lock_writer_unlock (&lock);
 
   return info;
@@ -486,3 +631,180 @@ gst_meta_compare_seqnum (const GstMeta * meta1, const GstMeta * meta2)
 
   return (seqnum1 < seqnum2) ? -1 : 1;
 }
+
+/**
+ * gst_meta_serialize:
+ * @meta: a #GstMeta
+ * @data: #GstByteArrayInterface to append serialization data
+ *
+ * Serialize @meta into a format that can be stored or transmitted and later
+ * deserialized by gst_meta_deserialize().
+ *
+ * This is only supported for meta that implements #GstMetaInfo.serialize_func,
+ * %FALSE is returned otherwise.
+ *
+ * Upon failure, @data->data pointer could have been reallocated, but @data->len
+ * won't be modified. This is intended to be able to append multiple metas
+ * into the same #GByteArray.
+ *
+ * Since serialization size is often the same for every buffer, caller may want
+ * to remember the size of previous data to preallocate the next.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * Since: 1.24
+ */
+gboolean
+gst_meta_serialize (const GstMeta * meta, GstByteArrayInterface * data)
+{
+  g_return_val_if_fail (meta != NULL, FALSE);
+  g_return_val_if_fail (data != NULL, FALSE);
+
+  if (meta->info->serialize_func != NULL) {
+    const gchar *name = g_type_name (meta->info->type);
+    guint32 name_len = strlen (name);
+    guint32 orig_len = data->len;
+    guint8 version = 0;
+
+    /* Format: [total size][name_len][name][\0][version][payload]
+     * Preallocate space for header but only write it on success because we
+     * don't have every info yet.
+     */
+    guint8 header_size = 2 * sizeof (guint32) + name_len + 2;
+    if (!gst_byte_array_interface_set_size (data, data->len + header_size))
+      return FALSE;
+    if (meta->info->serialize_func (meta, data, &version)) {
+      guint8 *header = data->data + orig_len;
+      GST_WRITE_UINT32_LE (header + 0, data->len - orig_len);
+      GST_WRITE_UINT32_LE (header + 4, name_len);
+      memcpy (header + 8, name, name_len + 1);
+      header[header_size - 1] = version;
+      return TRUE;
+    }
+    // Serialization failed, rollback.
+    gst_byte_array_interface_set_size (data, orig_len);
+  }
+
+  return FALSE;
+}
+
+typedef struct
+{
+  GstByteArrayInterface parent;
+  GByteArray *data;
+} ByteArrayImpl;
+
+static gboolean
+byte_array_impl_resize (GstByteArrayInterface * parent, gsize length)
+{
+  ByteArrayImpl *self = (ByteArrayImpl *) parent;
+
+  g_byte_array_set_size (self->data, length);
+  parent->data = self->data->data;
+  return TRUE;
+}
+
+/**
+ * gst_meta_serialize_simple:
+ * @meta: a #GstMeta
+ * @data: #GByteArray to append serialization data
+ *
+ * Same as gst_meta_serialize() but with a #GByteArray instead of
+ * #GstByteArrayInterface.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * Since: 1.24
+ */
+gboolean
+gst_meta_serialize_simple (const GstMeta * meta, GByteArray * data)
+{
+  ByteArrayImpl impl;
+
+  gst_byte_array_interface_init (&impl.parent);
+  impl.parent.data = data->data;
+  impl.parent.len = data->len;
+  impl.parent.resize = byte_array_impl_resize;
+  impl.data = data;
+  return gst_meta_serialize (meta, (GstByteArrayInterface *) & impl);
+}
+
+/**
+ * gst_meta_deserialize:
+ * @buffer: a #GstBuffer
+ * @data: serialization data obtained from gst_meta_serialize()
+ * @size: size of @data
+ * @consumed: (out): total size used by this meta, could be less than @size
+ *
+ * Recreate a #GstMeta from serialized data returned by
+ * gst_meta_serialize() and add it to @buffer.
+ *
+ * Note that the meta must have been previously registered by calling one of
+ * `gst_*_meta_get_info ()` functions.
+ *
+ * @consumed is set to the number of bytes that can be skipped from @data to
+ * find the next meta serialization, if any. In case of parsing error that does
+ * not allow to determine that size, @consumed is set to 0.
+ *
+ * Returns: (transfer none) (nullable): the metadata owned by @buffer, or %NULL.
+ *
+ * Since: 1.24
+ */
+GstMeta *
+gst_meta_deserialize (GstBuffer * buffer, const guint8 * data, gsize size,
+    guint32 * consumed)
+{
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
+  g_return_val_if_fail (data != NULL, NULL);
+  g_return_val_if_fail (consumed != NULL, NULL);
+
+  *consumed = 0;
+
+  /* Format: [total size][name_len][name][\0][version][payload] */
+  if (size < 2 * sizeof (guint32))
+    goto bad_header;
+
+  guint32 total_size = GST_READ_UINT32_LE (data + 0);
+  guint32 name_len = GST_READ_UINT32_LE (data + 4);
+  guint32 header_size = 2 * sizeof (guint32) + name_len + 2;
+  if (size < total_size || total_size < header_size)
+    goto bad_header;
+
+  guint8 version = data[header_size - 1];
+  const gchar *name = (const gchar *) (data + 2 * sizeof (guint32));
+  if (name[name_len] != '\0')
+    goto bad_header;
+
+  *consumed = total_size;
+
+  const GstMetaInfo *info = gst_meta_get_info (name);
+  if (info == NULL) {
+    GST_CAT_WARNING (GST_CAT_META,
+        "%s does not correspond to a registered meta", name);
+    return NULL;
+  }
+
+  if (info->deserialize_func == NULL) {
+    GST_CAT_WARNING (GST_CAT_META, "Meta %s does not support deserialization",
+        name);
+    return NULL;
+  }
+
+  const guint8 *payload = data + header_size;
+  guint32 payload_size = total_size - header_size;
+  GstMeta *meta =
+      info->deserialize_func (info, buffer, payload, payload_size, version);
+  if (meta == NULL) {
+    GST_CAT_WARNING (GST_CAT_META, "Failed to deserialize %s payload", name);
+    GST_CAT_MEMDUMP (GST_CAT_META, "Meta serialization payload", payload,
+        payload_size);
+    return NULL;
+  }
+
+  return meta;
+
+bad_header:
+  GST_CAT_WARNING (GST_CAT_META, "Could not parse meta serialization header");
+  GST_CAT_MEMDUMP (GST_CAT_META, "Meta serialization data", data, size);
+  return NULL;
+}
diff --git a/gst/gstmeta.h b/gst/gstmeta.h
index 44edbe0..2148471 100644
--- a/gst/gstmeta.h
+++ b/gst/gstmeta.h
@@ -25,6 +25,9 @@
 
 #include <glib.h>
 
+#include <gst/gstbytearrayinterface.h>
+#include <gst/gststructure.h>
+
 G_BEGIN_DECLS
 
 typedef struct _GstMeta GstMeta;
@@ -80,6 +83,7 @@ typedef enum {
  * @flag: the #GstMetaFlags to clear.
  *
  * Clears a metadata flag.
+ *
  */
 #define GST_META_FLAG_UNSET(meta,flag)         (GST_META_FLAGS (meta) &= ~(flag))
 
@@ -115,15 +119,31 @@ struct _GstMeta {
   const GstMetaInfo *info;
 };
 
+/**
+ * GstCustomMeta.structure:
+ *
+ * #GstStructure containing custom metadata.
+ *
+ * Since: 1.24
+ */
+
 /**
  * GstCustomMeta:
+ * @meta: parent #GstMeta
+ * @structure: a #GstStructure containing custom metadata. (Since: 1.24)
  *
- * Simple typing wrapper around #GstMeta
+ * Extra custom metadata. The @structure field is the same as returned by
+ * gst_custom_meta_get_structure().
+ *
+ * Since 1.24 it can be serialized using gst_meta_serialize() and
+ * gst_meta_deserialize(), but only if the #GstStructure does not contain any
+ * fields that cannot be serialized, see %GST_SERIALIZE_FLAG_STRICT.
  *
  * Since: 1.20
  */
 typedef struct {
   GstMeta meta;
+  GstStructure *structure;
 } GstCustomMeta;
 
 #include <gst/gstbuffer.h>
@@ -223,6 +243,83 @@ typedef gboolean (*GstCustomMetaTransformFunction) (GstBuffer *transbuf,
                                                     GstCustomMeta *meta, GstBuffer *buffer,
                                                     GQuark type, gpointer data, gpointer user_data);
 
+/**
+ * GstMetaSerializeFunction:
+ * @meta: a #GstMeta
+ * @data: #GstByteArrayInterface to append serialization data
+ * @version: (out): version of the serialization format
+ *
+ * Serialize @meta into a format that can be stored or transmitted and later
+ * deserialized by #GstMetaDeserializeFunction.
+ *
+ * By default version is set to 0, it should be bumped if incompatible changes
+ * are made to the format so %GstMetaDeserializeFunction can deserialize each
+ * version.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * Since: 1.24
+ */
+typedef gboolean (*GstMetaSerializeFunction) (const GstMeta *meta,
+    GstByteArrayInterface *data, guint8 *version);
+
+/**
+ * GstMetaDeserializeFunction:
+ * @info: #GstMetaInfo of the meta
+ * @buffer: a #GstBuffer
+ * @data: data obtained from #GstMetaSerializeFunction
+ * @size: size of data to avoid buffer overflow
+ *
+ * Recreate a #GstMeta from serialized data returned by
+ * #GstMetaSerializeFunction and add it to @buffer.
+ *
+ * Returns: (transfer none) (nullable): the metadata owned by @buffer, or %NULL.
+ *
+ * Since: 1.24
+ */
+typedef GstMeta *(*GstMetaDeserializeFunction) (const GstMetaInfo *info,
+    GstBuffer *buffer, const guint8 *data, gsize size, guint8 version);
+
+/**
+ * GstMetaClearFunction:
+ * @buffer: a #GstBuffer
+ * @meta: a #GstMeta
+ *
+ * Clears the content of the meta. This will be called by the GstBufferPool
+ * when a pooled buffer is returned.
+ *
+ * Since: 1.24
+ */
+typedef void (*GstMetaClearFunction) (GstBuffer *buffer, GstMeta *meta);
+
+/**
+ * GstMetaInfo.serialize_func:
+ *
+ * Function for serializing the metadata, or %NULL if not supported by this
+ * meta.
+ *
+ * Since: 1.24
+ */
+
+/**
+ * GstMetaInfo.deserialize_func:
+ *
+ * Function for deserializing the metadata, or %NULL if not supported by this
+ * meta.
+ *
+ * Since: 1.24
+ */
+
+/**
+ * GstMetaInfo.clear_func:
+ *
+ * Function for clearing the metadata, or %NULL if not supported by this
+ * meta. This is called by the buffer pool when a buffer is returned for
+ * pooled metas.
+ *
+ * Since: 1.24
+ */
+
 /**
  * GstMetaInfo:
  * @api: tag identifying the metadata structure and api
@@ -231,6 +328,10 @@ typedef gboolean (*GstCustomMetaTransformFunction) (GstBuffer *transbuf,
  * @init_func: function for initializing the metadata
  * @free_func: function for freeing the metadata
  * @transform_func: function for transforming the metadata
+ * @serialize_func: function for serializing the metadata into a #GstStructure,
+ *  or %NULL if not supported by this meta. (Since 1.24)
+ * @deserialize_func: function for deserializing the metadata from a
+ *  #GstStructure, or %NULL if not supported by this meta. (Since 1.24)
  *
  * The #GstMetaInfo provides information about a specific metadata
  * structure.
@@ -243,6 +344,9 @@ struct _GstMetaInfo {
   GstMetaInitFunction        init_func;
   GstMetaFreeFunction        free_func;
   GstMetaTransformFunction   transform_func;
+  GstMetaSerializeFunction   serialize_func;
+  GstMetaDeserializeFunction deserialize_func;
+  GstMetaClearFunction       clear_func;
 
   /* No padding needed, GstMetaInfo is always allocated by GStreamer and is
    * not subclassable or stack-allocatable, so we can extend it as we please
@@ -262,11 +366,21 @@ const GstMetaInfo *  gst_meta_register          (GType api, const gchar *impl,
                                                  GstMetaFreeFunction      free_func,
                                                  GstMetaTransformFunction transform_func);
 
+GST_API
+GstMetaInfo *        gst_meta_info_new (GType api,
+                                        const gchar *impl,
+                                        gsize size);
+GST_API
+const GstMetaInfo *  gst_meta_info_register (GstMetaInfo *info);
+
 GST_API
 const GstMetaInfo *  gst_meta_register_custom   (const gchar *name, const gchar **tags,
                                                  GstCustomMetaTransformFunction transform_func,
                                                  gpointer user_data, GDestroyNotify destroy_data);
 
+GST_API
+const GstMetaInfo *  gst_meta_register_custom_simple (const gchar *name);
+
 GST_API
 gboolean             gst_meta_info_is_custom    (const GstMetaInfo *info);
 
@@ -289,6 +403,18 @@ GST_API
 gint                 gst_meta_compare_seqnum    (const GstMeta * meta1,
                                                  const GstMeta * meta2);
 
+GST_API
+gboolean             gst_meta_serialize         (const GstMeta *meta,
+                                                 GstByteArrayInterface *data);
+GST_API
+gboolean             gst_meta_serialize_simple  (const GstMeta *meta,
+                                                 GByteArray *data);
+GST_API
+GstMeta *            gst_meta_deserialize       (GstBuffer *buffer,
+                                                 const guint8 *data,
+                                                 gsize size,
+                                                 guint32 *consumed);
+
 /* some default tags */
 
 GST_API GQuark _gst_meta_tag_memory;
diff --git a/gst/gstobject.c b/gst/gstobject.c
index 2b7146d..1a57459 100644
--- a/gst/gstobject.c
+++ b/gst/gstobject.c
@@ -138,6 +138,8 @@ G_DEFINE_ABSTRACT_TYPE (GstObject, gst_object, G_TYPE_INITIALLY_UNOWNED);
 static void
 gst_object_constructed (GObject * object)
 {
+  GST_OBJECT_FLAG_SET (object, GST_OBJECT_FLAG_CONSTRUCTED);
+
   GST_TRACER_OBJECT_CREATED (GST_OBJECT_CAST (object));
 
   ((GObjectClass *) gst_object_parent_class)->constructed (object);
diff --git a/gst/gstobject.h b/gst/gstobject.h
index 85e8275..a808522 100644
--- a/gst/gstobject.h
+++ b/gst/gstobject.h
@@ -39,11 +39,30 @@ G_BEGIN_DECLS
 #define GST_OBJECT_CAST(obj)            ((GstObject*)(obj))
 #define GST_OBJECT_CLASS_CAST(klass)    ((GstObjectClass*)(klass))
 
+/**
+ * GST_OBJECT_FLAG_CONSTRUCTED:
+ *
+ * Flag that's set when the object has been constructed. This can be used by
+ * API such as base class setters to differentiate between the case where
+ * they're called from a subclass's instance init function (and where the
+ * object isn't fully constructed yet, and so one shouldn't do anything but
+ * set values in the instance structure), and the case where the object is
+ * constructed.
+ *
+ * Since: 1.24
+ */
+
 /**
  * GstObjectFlags:
  * @GST_OBJECT_FLAG_MAY_BE_LEAKED: the object is expected to stay alive even
  * after gst_deinit() has been called and so should be ignored by leak
  * detection tools. (Since: 1.10)
+ * @GST_OBJECT_FLAG_CONSTRUCTED: flag that's set when the object has been
+ * constructed. This can be used by API such as base class setters to
+ * differentiate between the case where they're called from a subclass's
+ * instance init function (and where the object isn't fully constructed yet,
+ * and so one shouldn't do anything but set values in the instance structure),
+ * and the case where the object is constructed. (Since: 1.24)
  * @GST_OBJECT_FLAG_LAST: subclasses can add additional flags starting from this flag
  *
  * The standard flags that an gstobject may have.
@@ -51,6 +70,7 @@ G_BEGIN_DECLS
 typedef enum
 {
   GST_OBJECT_FLAG_MAY_BE_LEAKED = (1 << 0),
+  GST_OBJECT_FLAG_CONSTRUCTED = (1 << 1),
   /* padding */
   GST_OBJECT_FLAG_LAST = (1<<4)
 } GstObjectFlags;
@@ -88,6 +108,34 @@ typedef enum
  * It blocks until the lock can be obtained.
  */
 #define GST_OBJECT_LOCK(obj)                   g_mutex_lock(GST_OBJECT_GET_LOCK(obj))
+
+/**
+ * GST_OBJECT_AUTO_LOCK:
+ * @obj: a #GstObject to lock
+ * @var: a variable name to be declared
+ *
+ * Declare a #GMutexLocker variable with g_autoptr() and lock the object. The
+ * mutex will be unlocked automatically when leaving the scope.
+ *
+ * ``` c
+ * {
+ *   GST_OBJECT_AUTO_LOCK (obj, locker);
+ *
+ *   obj->stuff_with_lock();
+ *   if (cond) {
+ *     // No need to unlock
+ *     return;
+ *   }
+ *
+ *   // Unlock before end of scope
+ *   g_clear_pointer (&locker, g_mutex_locker_free);
+ *   obj->stuff_without_lock();
+ * }
+ * ```
+ * Since: 1.24.0
+ */
+#define GST_OBJECT_AUTO_LOCK(obj, var) g_autoptr(GMutexLocker) G_GNUC_UNUSED var = g_mutex_locker_new(GST_OBJECT_GET_LOCK(obj))
+
 /**
  * GST_OBJECT_TRYLOCK:
  * @obj: a #GstObject.
diff --git a/gst/gstpad.c b/gst/gstpad.c
index db98933..2341808 100644
--- a/gst/gstpad.c
+++ b/gst/gstpad.c
@@ -659,15 +659,18 @@ _apply_pad_offset (GstPad * pad, GstEvent * event, gboolean upstream,
 
   if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
     GstSegment segment;
+    guint32 seqnum;
 
     g_assert (!upstream);
 
     /* copy segment values */
     gst_event_copy_segment (event, &segment);
+    seqnum = gst_event_get_seqnum (event);
     gst_event_unref (event);
 
     gst_segment_offset_running_time (&segment, segment.format, pad_offset);
     event = gst_event_new_segment (&segment);
+    gst_event_set_seqnum (event, seqnum);
   }
 
   event = gst_event_make_writable (event);
@@ -2378,22 +2381,18 @@ wrong_grandparents:
   }
 }
 
-/* FIXME leftover from an attempt at refactoring... */
-/* call with the two pads unlocked, when this function returns GST_PAD_LINK_OK,
- * the two pads will be locked in the srcpad, sinkpad order. */
+/* check that pads does not have any exisiting links
+ * and that hierarchy is valid for linking.
+ *
+ * The LOCK should be held on both pads
+ */
 static GstPadLinkReturn
-gst_pad_link_prepare (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
+gst_pad_link_check_relations (GstPad * srcpad, GstPad * sinkpad,
+    GstPadLinkCheck flags)
 {
-  GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
-      GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
-
-  GST_OBJECT_LOCK (srcpad);
-
   if (G_UNLIKELY (GST_PAD_PEER (srcpad) != NULL))
     goto src_was_linked;
 
-  GST_OBJECT_LOCK (sinkpad);
-
   if (G_UNLIKELY (GST_PAD_PEER (sinkpad) != NULL))
     goto sink_was_linked;
 
@@ -2403,12 +2402,6 @@ gst_pad_link_prepare (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
       && !gst_pad_link_check_hierarchy (srcpad, sinkpad))
     goto wrong_hierarchy;
 
-  /* check pad caps for non-empty intersection */
-  if (!gst_pad_link_check_compatible_unlocked (srcpad, sinkpad, flags))
-    goto no_format;
-
-  /* FIXME check pad scheduling for non-empty intersection */
-
   return GST_PAD_LINK_OK;
 
 src_was_linked:
@@ -2418,7 +2411,6 @@ src_was_linked:
         GST_DEBUG_PAD_NAME (GST_PAD_PEER (srcpad)));
     /* we do not emit a warning in this case because unlinking cannot
      * be made MT safe.*/
-    GST_OBJECT_UNLOCK (srcpad);
     return GST_PAD_LINK_WAS_LINKED;
   }
 sink_was_linked:
@@ -2428,23 +2420,57 @@ sink_was_linked:
         GST_DEBUG_PAD_NAME (GST_PAD_PEER (sinkpad)));
     /* we do not emit a warning in this case because unlinking cannot
      * be made MT safe.*/
-    GST_OBJECT_UNLOCK (sinkpad);
-    GST_OBJECT_UNLOCK (srcpad);
     return GST_PAD_LINK_WAS_LINKED;
   }
 wrong_hierarchy:
   {
     GST_CAT_INFO (GST_CAT_PADS, "pads have wrong hierarchy");
-    GST_OBJECT_UNLOCK (sinkpad);
-    GST_OBJECT_UNLOCK (srcpad);
     return GST_PAD_LINK_WRONG_HIERARCHY;
   }
-no_format:
-  {
+}
+
+/* FIXME leftover from an attempt at refactoring... */
+/* call with the two pads unlocked, when this function returns GST_PAD_LINK_OK,
+ * the two pads will be locked in the srcpad, sinkpad order. */
+static GstPadLinkReturn
+gst_pad_link_prepare (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
+{
+  GstPadLinkReturn result;
+
+  GST_CAT_INFO (GST_CAT_PADS, "trying to link %s:%s and %s:%s",
+      GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
+
+  GST_OBJECT_LOCK (srcpad);
+  GST_OBJECT_LOCK (sinkpad);
+
+  /* Check pads state, not already linked and correct hierachy. */
+  result = gst_pad_link_check_relations (srcpad, sinkpad, flags);
+  if (result != GST_PAD_LINK_OK)
+    goto unlock_and_return;
+
+  /* check pad caps for non-empty intersection */
+  if (!gst_pad_link_check_compatible_unlocked (srcpad, sinkpad, flags)) {
     GST_CAT_INFO (GST_CAT_PADS, "caps are incompatible");
+    result = GST_PAD_LINK_NOFORMAT;
+    goto unlock_and_return;
+  }
+
+  /* Need to recheck our pads since gst_pad_link_check_compatible_unlocked might have temporarily unlocked them.
+     Keeping the first check, because gst_pad_link_check_compatible_unlocked potentially is an expensive operation
+     which gst_pad_link_check_relations is not. */
+  result = gst_pad_link_check_relations (srcpad, sinkpad, flags);
+  if (result != GST_PAD_LINK_OK)
+    goto unlock_and_return;
+
+  /* FIXME check pad scheduling for non-empty intersection */
+
+  return GST_PAD_LINK_OK;
+
+unlock_and_return:
+  {
     GST_OBJECT_UNLOCK (sinkpad);
     GST_OBJECT_UNLOCK (srcpad);
-    return GST_PAD_LINK_NOFORMAT;
+    return result;
   }
 }
 
@@ -4161,7 +4187,7 @@ gboolean
 gst_pad_query (GstPad * pad, GstQuery * query)
 {
   GstObject *parent;
-  gboolean res, serialized;
+  gboolean res = FALSE, serialized;
   GstPadQueryFunction func;
   GstPadProbeType type;
   GstFlowReturn ret;
@@ -4205,7 +4231,6 @@ gst_pad_query (GstPad * pad, GstQuery * query)
 
   GST_DEBUG_OBJECT (pad, "sent query %p (%s), result %d", query,
       GST_QUERY_TYPE_NAME (query), res);
-  GST_TRACER_PAD_QUERY_POST (pad, query, res);
 
   if (res != TRUE)
     goto query_failed;
@@ -4214,6 +4239,8 @@ gst_pad_query (GstPad * pad, GstQuery * query)
   PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PULL, query, probe_stopped);
   GST_OBJECT_UNLOCK (pad);
 
+  GST_TRACER_PAD_QUERY_POST (pad, query, res);
+
   if (G_UNLIKELY (serialized))
     GST_PAD_STREAM_UNLOCK (pad);
 
@@ -4235,6 +4262,7 @@ no_parent:
   {
     GST_DEBUG_OBJECT (pad, "had no parent");
     GST_OBJECT_UNLOCK (pad);
+    GST_TRACER_PAD_QUERY_POST (pad, query, res);
     if (G_UNLIKELY (serialized))
       GST_PAD_STREAM_UNLOCK (pad);
     return FALSE;
@@ -4243,6 +4271,7 @@ no_func:
   {
     GST_DEBUG_OBJECT (pad, "had no query function");
     RELEASE_PARENT (parent);
+    GST_TRACER_PAD_QUERY_POST (pad, query, res);
     if (G_UNLIKELY (serialized))
       GST_PAD_STREAM_UNLOCK (pad);
     return FALSE;
@@ -4250,6 +4279,7 @@ no_func:
 query_failed:
   {
     GST_DEBUG_OBJECT (pad, "query failed");
+    GST_TRACER_PAD_QUERY_POST (pad, query, res);
     if (G_UNLIKELY (serialized))
       GST_PAD_STREAM_UNLOCK (pad);
     return FALSE;
@@ -4258,6 +4288,7 @@ probe_stopped:
   {
     GST_DEBUG_OBJECT (pad, "probe stopped: %s", gst_flow_get_name (ret));
     GST_OBJECT_UNLOCK (pad);
+    GST_TRACER_PAD_QUERY_POST (pad, query, res);
     if (G_UNLIKELY (serialized))
       GST_PAD_STREAM_UNLOCK (pad);
 
@@ -4536,7 +4567,7 @@ probe_handled:
 probe_stopped:
   {
     /* We unref the buffer, except if the probe handled it (CUSTOM_SUCCESS_1) */
-    if (!handled)
+    if (data && !handled)
       gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
 
     switch (ret) {
@@ -5538,8 +5569,12 @@ gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
   PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
 
   /* recheck sticky events because the probe might have cause a relink */
+  /* Note: FLUSH_STOP is a serialized event, but must not propagate sticky
+   * events. FLUSH_STOP is only targeted at removing the flushing state from
+   * pads and elements, and not actually pushing data/events. */
   if (GST_PAD_HAS_PENDING_EVENTS (pad) && GST_PAD_IS_SRC (pad)
-      && (GST_EVENT_IS_SERIALIZED (event))) {
+      && (GST_EVENT_IS_SERIALIZED (event))
+      && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_STOP) {
     PushStickyData data = { GST_FLOW_OK, FALSE, event };
     GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
 
@@ -5566,8 +5601,9 @@ gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
   pad->priv->using++;
   GST_OBJECT_UNLOCK (pad);
 
-  GST_LOG_OBJECT (pad, "sending event %p (%s) to peerpad %" GST_PTR_FORMAT,
-      event, gst_event_type_get_name (event_type), peerpad);
+  GST_LOG_OBJECT (pad,
+      "sending event %" GST_PTR_FORMAT " to peerpad %" GST_PTR_FORMAT,
+      event, peerpad);
 
   ret = gst_pad_send_event_unchecked (peerpad, event, type);
 
@@ -5604,7 +5640,7 @@ inactive:
 probe_stopped:
   {
     GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-    if (ret != GST_FLOW_CUSTOM_SUCCESS_1)
+    if (event && ret != GST_FLOW_CUSTOM_SUCCESS_1)
       gst_event_unref (event);
 
     switch (ret) {
@@ -5697,11 +5733,18 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
         break;
     }
   }
-  if (GST_PAD_IS_SRC (pad) && serialized) {
+  if (GST_PAD_IS_SRC (pad) && serialized
+      && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_STOP) {
     /* All serialized events on the srcpad trigger push of sticky events.
      *
      * Note that we do not do this for non-serialized sticky events since it
-     * could potentially block. */
+     * could potentially block.
+     *
+     * We must NOT propagate sticky events in response to FLUSH_STOP either, as
+     * FLUSH_STOP is only targeted at removing the flushing state from pads and
+     * elements, and not actually pushing data/events. This also makes it
+     * consistent with the way flush events are handled in "blocking" pad
+     * probes. */
     res = (check_sticky (pad, event) == GST_FLOW_OK);
   }
   if (!serialized || !sticky) {
@@ -6013,7 +6056,7 @@ probe_stopped:
     if (need_unlock)
       GST_PAD_STREAM_UNLOCK (pad);
     /* Only unref if unhandled */
-    if (ret != GST_FLOW_CUSTOM_SUCCESS_1)
+    if (event && ret != GST_FLOW_CUSTOM_SUCCESS_1)
       gst_event_unref (event);
 
     switch (ret) {
@@ -6324,6 +6367,7 @@ gst_pad_start_task (GstPad * pad, GstTaskFunction func, gpointer user_data,
   task = GST_PAD_TASK (pad);
   if (task == NULL) {
     task = gst_task_new (func, user_data, notify);
+    notify = NULL;
     gst_task_set_lock (task, GST_PAD_GET_STREAM_LOCK (pad));
     gst_task_set_enter_callback (task, pad_enter_thread, pad, NULL);
     gst_task_set_leave_callback (task, pad_leave_thread, pad, NULL);
@@ -6345,6 +6389,10 @@ gst_pad_start_task (GstPad * pad, GstTaskFunction func, gpointer user_data,
   res = gst_task_set_state (task, GST_TASK_STARTED);
   GST_OBJECT_UNLOCK (pad);
 
+  /* free user_data if it wasn't used for gst_task_new */
+  if (notify)
+    notify (user_data);
+
   return res;
 
   /* ERRORS */
diff --git a/gst/gstpad.h b/gst/gstpad.h
index c89be30..86f2af1 100644
--- a/gst/gstpad.h
+++ b/gst/gstpad.h
@@ -1249,6 +1249,34 @@ struct _GstPadClass {
  * when buffers or serialized downstream events are pushed on a pad.
  */
 #define GST_PAD_STREAM_LOCK(pad)        g_rec_mutex_lock(GST_PAD_GET_STREAM_LOCK(pad))
+
+/**
+ * GST_PAD_STREAM_AUTO_LOCK
+ * @pad: a #GstPad
+ * @var: a variable name to be declared
+ *
+ * Declare a #GRecMutexLocker variable with g_autoptr() and lock the pad. The
+ * recursive mutex will be unlocked automatically when leaving the scope.
+ *
+ * ``` c
+ * {
+ *   GST_PAD_STREAM_AUTO_LOCK (pad, locker);
+ *
+ *   gst_pad_push_event(pad, event1);
+ *   if (cond) {
+ *     // No need to unlock
+ *     return;
+ *   }
+ *
+ *   // Unlock before end of scope
+ *   g_clear_pointer (&locker, g_rec_mutex_locker_free);
+ *   gst_pad_push_event(pad, event2);
+ * }
+ * ```
+ * Since: 1.24.0
+ */
+#define GST_PAD_STREAM_AUTO_LOCK(pad, var) g_autoptr(GRecMutexLocker) G_GNUC_UNUSED var = g_rec_mutex_locker_new(GST_PAD_GET_STREAM_LOCK(pad))
+
 /**
  * GST_PAD_STREAM_TRYLOCK:
  * @pad: a #GstPad
diff --git a/gst/gstparse.c b/gst/gstparse.c
index 1a0d34b..7b130f4 100644
--- a/gst/gstparse.c
+++ b/gst/gstparse.c
@@ -84,7 +84,7 @@ gst_parse_context_new (void)
 #ifndef GST_DISABLE_PARSE
   GstParseContext *ctx;
 
-  ctx = g_slice_new (GstParseContext);
+  ctx = g_new (GstParseContext, 1);
   ctx->missing_elements = NULL;
 
   return ctx;
@@ -136,7 +136,7 @@ gst_parse_context_free (GstParseContext * context)
   if (context) {
     g_list_foreach (context->missing_elements, (GFunc) g_free, NULL);
     g_list_free (context->missing_elements);
-    g_slice_free (GstParseContext, context);
+    g_free (context);
   }
 #endif
 }
diff --git a/gst/gstpipeline.c b/gst/gstpipeline.c
index f2e694f..c141833 100644
--- a/gst/gstpipeline.c
+++ b/gst/gstpipeline.c
@@ -114,6 +114,7 @@ struct _GstPipelinePrivate
   /* with LOCK */
   gboolean auto_flush_bus;
   gboolean is_live;
+  GstClockTime min_latency;
 
   /* when we need to update stream_time or clock when going back to
    * PLAYING*/
@@ -234,6 +235,7 @@ gst_pipeline_init (GstPipeline * pipeline)
   pipeline->priv->latency = DEFAULT_LATENCY;
 
   pipeline->priv->is_live = FALSE;
+  pipeline->priv->min_latency = GST_CLOCK_TIME_NONE;
 
   /* create and set a default bus */
   bus = gst_bus_new ();
@@ -519,7 +521,10 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
       break;
     }
     case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_OBJECT_LOCK (element);
       pipeline->priv->is_live = FALSE;
+      pipeline->priv->min_latency = GST_CLOCK_TIME_NONE;
+      GST_OBJECT_UNLOCK (element);
       reset_start_time (pipeline, 0);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
@@ -529,9 +534,11 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
   if (GST_STATE_TRANSITION_NEXT (transition) == GST_STATE_PAUSED) {
+    GST_OBJECT_LOCK (element);
     pipeline->priv->is_live = result == GST_STATE_CHANGE_NO_PREROLL;
     GST_INFO_OBJECT (pipeline, "pipeline is%slive",
         pipeline->priv->is_live ? " " : " not ");
+    GST_OBJECT_UNLOCK (element);
   }
 
   switch (transition) {
@@ -621,6 +628,7 @@ gst_pipeline_handle_message (GstBin * bin, GstMessage * message)
     case GST_MESSAGE_RESET_TIME:
     {
       GstClockTime running_time;
+      gboolean is_live;
 
       gst_message_parse_reset_time (message, &running_time);
 
@@ -628,9 +636,12 @@ gst_pipeline_handle_message (GstBin * bin, GstMessage * message)
        * children. */
       reset_start_time (pipeline, running_time);
 
+      GST_OBJECT_LOCK (pipeline);
+      is_live = pipeline->priv->is_live;
+      GST_OBJECT_UNLOCK (pipeline);
+
       /* If we are live, sample a new base_time immediately */
-      if (pipeline->priv->is_live
-          && GST_STATE_TARGET (pipeline) == GST_STATE_PLAYING) {
+      if (is_live && GST_STATE_TARGET (pipeline) == GST_STATE_PLAYING) {
         gst_pipeline_change_state (GST_ELEMENT (pipeline),
             GST_STATE_CHANGE_PAUSED_TO_PLAYING);
       }
@@ -693,6 +704,10 @@ gst_pipeline_do_latency (GstBin * bin)
 
     gst_query_parse_latency (query, &live, &min_latency, &max_latency);
 
+    GST_OBJECT_LOCK (pipeline);
+    pipeline->priv->min_latency = min_latency;
+    GST_OBJECT_UNLOCK (pipeline);
+
     GST_DEBUG_OBJECT (pipeline,
         "got min latency %" GST_TIME_FORMAT ", max latency %"
         GST_TIME_FORMAT ", live %d", GST_TIME_ARGS (min_latency),
@@ -1168,3 +1183,52 @@ gst_pipeline_handle_instant_rate (GstPipeline * pipeline, gdouble rate,
 
   return gst_element_send_event (GST_ELEMENT_CAST (pipeline), event);
 }
+
+/**
+ * gst_pipeline_is_live:
+ * @pipeline: a #GstPipeline
+ *
+ * Check if @pipeline is live.
+ *
+ * Returns: %TRUE if @pipeline is live, %FALSE if not or if it did not reach the PAUSED state yet.
+ *
+ * MT safe.
+ *
+ * Since: 1.24
+ */
+gboolean
+gst_pipeline_is_live (GstPipeline * pipeline)
+{
+  gboolean is_live;
+
+  GST_OBJECT_LOCK (pipeline);
+  is_live = pipeline->priv->is_live;
+  GST_OBJECT_UNLOCK (pipeline);
+
+  return is_live;
+}
+
+/**
+ * gst_pipeline_get_configured_latency:
+ * @pipeline: a #GstPipeline
+ *
+ * Return the configured latency on @pipeline.
+ *
+ * Returns: @pipeline configured latency, or %GST_CLOCK_TIME_NONE if none has been configured
+ * because @pipeline did not reach the PLAYING state yet.
+ *
+ * MT safe.
+ *
+ * Since: 1.24
+ */
+GstClockTime
+gst_pipeline_get_configured_latency (GstPipeline * pipeline)
+{
+  GstClockTime min_latency;
+
+  GST_OBJECT_LOCK (pipeline);
+  min_latency = pipeline->priv->min_latency;
+  GST_OBJECT_UNLOCK (pipeline);
+
+  return min_latency;
+}
diff --git a/gst/gstpipeline.h b/gst/gstpipeline.h
index 6406fb8..5227c9b 100644
--- a/gst/gstpipeline.h
+++ b/gst/gstpipeline.h
@@ -130,6 +130,12 @@ void            gst_pipeline_set_auto_flush_bus (GstPipeline *pipeline, gboolean
 GST_API
 gboolean        gst_pipeline_get_auto_flush_bus (GstPipeline *pipeline);
 
+GST_API
+gboolean        gst_pipeline_is_live            (GstPipeline *pipeline);
+
+GST_API
+GstClockTime    gst_pipeline_get_configured_latency    (GstPipeline * pipeline);
+
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstPipeline, gst_object_unref)
 
 G_END_DECLS
diff --git a/gst/gstplugin.c b/gst/gstplugin.c
index ced754c..4a99635 100644
--- a/gst/gstplugin.c
+++ b/gst/gstplugin.c
@@ -156,6 +156,10 @@ gst_plugin_finalize (GObject * object)
     gst_structure_free (plugin->priv->cache_data);
   }
 
+  if (plugin->priv->status_info) {
+    gst_structure_free (plugin->priv->status_info);
+  }
+
   G_OBJECT_CLASS (gst_plugin_parent_class)->finalize (object);
 }
 
@@ -345,7 +349,8 @@ _priv_gst_plugin_initialize (void)
  *   plugin1,plugin2 or
  *   source-package@pathprefix or
  *   source-package@* or just
- *   source-package
+ *   source-package or
+ *   *
  *
  * ie. the bit before the path will be checked against both the plugin
  * name and the plugin's source package name, to keep the format simple.
@@ -361,6 +366,9 @@ gst_plugin_desc_matches_whitelist_entry (const GstPluginDesc * desc,
   GST_LOG ("Whitelist pattern '%s', plugin: %s of %s@%s", pattern, desc->name,
       desc->source, GST_STR_NULL (filename));
 
+  if (strcmp (pattern, "*") == 0)
+    return TRUE;
+
   /* do we have a path prefix? */
   sep = strchr (pattern, '@');
   if (sep != NULL && strcmp (sep, "@*") != 0 && strcmp (sep, "@") != 0) {
@@ -1619,8 +1627,9 @@ gst_plugin_ext_dep_extract_env_vars_paths (GstPlugin * plugin,
         gchar *full_path;
 
         if (!g_path_is_absolute (arr[i])) {
-          GST_INFO_OBJECT (plugin, "ignoring environment variable content '%s'"
-              ": either not an absolute path or not a path at all", arr[i]);
+          GST_INFO_OBJECT (plugin, "ignoring environment variable '%s' with "
+              "content #%u '%s': either not an absolute path or not a path at all",
+              components[0], i, arr[i]);
           continue;
         }
 
@@ -1702,7 +1711,7 @@ gst_plugin_ext_dep_scan_dir_and_match_names (GstPlugin * plugin,
   GDir *dir;
   guint hash = 0;
 
-  recurse_dirs = ! !(flags & GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
+  recurse_dirs = !!(flags & GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
 
   dir = g_dir_open (path, 0, &err);
   if (dir == NULL) {
@@ -1764,7 +1773,7 @@ gst_plugin_ext_dep_scan_path_with_filenames (GstPlugin * plugin,
   if (filenames == NULL || *filenames == NULL)
     filenames = empty_filenames;
 
-  recurse_into_dirs = ! !(flags & GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
+  recurse_into_dirs = !!(flags & GST_PLUGIN_DEPENDENCY_FLAG_RECURSE);
 
   if ((flags & GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX) ||
       (flags & GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX))
@@ -1881,7 +1890,7 @@ gst_plugin_ext_dep_free (GstPluginDep * dep)
   g_strfreev (dep->env_vars);
   g_strfreev (dep->paths);
   g_strfreev (dep->names);
-  g_slice_free (GstPluginDep, dep);
+  g_free (dep);
 }
 
 static gboolean
@@ -1960,7 +1969,7 @@ gst_plugin_add_dependency (GstPlugin * plugin, const gchar ** env_vars,
     }
   }
 
-  dep = g_slice_new (GstPluginDep);
+  dep = g_new (GstPluginDep, 1);
 
   dep->env_vars = g_strdupv ((gchar **) env_vars);
   dep->paths = g_strdupv ((gchar **) paths);
@@ -2034,3 +2043,148 @@ gst_plugin_add_dependency_simple (GstPlugin * plugin,
   if (a_names)
     g_strfreev (a_names);
 }
+
+static void
+gst_plugin_add_status_message (GstPlugin * plugin, const gchar * field_name,
+    const gchar * message)
+{
+  const GValue *val = NULL;
+  GValue str_val = G_VALUE_INIT;
+
+  g_return_if_fail (GST_IS_PLUGIN (plugin));
+  g_return_if_fail (message != NULL);
+
+  g_value_init (&str_val, G_TYPE_STRING);
+  g_value_set_string (&str_val, message);
+
+  if (plugin->priv->status_info == NULL)
+    plugin->priv->status_info = gst_structure_new_empty ("plugin-status-info");
+  else
+    val = gst_structure_get_value (plugin->priv->status_info, field_name);
+
+  if (val != NULL) {
+    gst_value_list_append_and_take_value ((GValue *) val, &str_val);
+  } else {
+    GValue list_val = G_VALUE_INIT;
+
+    gst_value_list_init (&list_val, 1);
+    gst_value_list_append_and_take_value (&list_val, &str_val);
+    gst_structure_take_value (plugin->priv->status_info, field_name, &list_val);
+  }
+
+  GST_TRACE_OBJECT (plugin, "Status info now: %" GST_PTR_FORMAT,
+      plugin->priv->status_info);
+}
+
+/**
+ * gst_plugin_add_status_error:
+ * @plugin: a #GstPlugin
+ * @message: the status error message
+ *
+ * Since: 1.24
+ */
+void
+gst_plugin_add_status_error (GstPlugin * plugin, const gchar * message)
+{
+  gst_plugin_add_status_message (plugin, "error-message", message);
+}
+
+/**
+ * gst_plugin_add_status_warning:
+ * @plugin: a #GstPlugin
+ * @message: the status warning message
+ *
+ * Since: 1.24
+ */
+void
+gst_plugin_add_status_warning (GstPlugin * plugin, const gchar * message)
+{
+  gst_plugin_add_status_message (plugin, "warning-message", message);
+}
+
+/**
+ * gst_plugin_add_status_info:
+ * @plugin: a #GstPlugin
+ * @message: the status info message
+ *
+ * Since: 1.24
+ */
+void
+gst_plugin_add_status_info (GstPlugin * plugin, const gchar * message)
+{
+  gst_plugin_add_status_message (plugin, "info-message", message);
+}
+
+static gchar **
+gst_plugin_get_status_messages (GstPlugin * plugin, const gchar * field_name)
+{
+  const GValue *list_val;
+  guint n_vals, i;
+  gchar **arr;
+
+  g_return_val_if_fail (GST_IS_PLUGIN (plugin), NULL);
+
+  if (plugin->priv->status_info == NULL)
+    return NULL;
+
+  list_val = gst_structure_get_value (plugin->priv->status_info, field_name);
+
+  if (list_val == NULL)
+    return NULL;
+
+  n_vals = gst_value_list_get_size (list_val);
+
+  if (n_vals == 0)
+    return NULL;
+
+  arr = g_new0 (gchar *, n_vals + 1);
+
+  for (i = 0; i < n_vals; ++i) {
+    const GValue *str_val = gst_value_list_get_value (list_val, i);
+    arr[i] = g_value_dup_string (str_val);
+  }
+
+  return arr;
+}
+
+/**
+ * gst_plugin_get_status_errors:
+ * @plugin: a #GstPlugin
+ *
+ * Returns: (transfer full) (nullable): an array of plugin status error messages, or NULL
+ *
+ * Since: 1.24
+ */
+gchar **
+gst_plugin_get_status_errors (GstPlugin * plugin)
+{
+  return gst_plugin_get_status_messages (plugin, "error-message");
+}
+
+/**
+ * gst_plugin_get_status_warnings:
+ * @plugin: a #GstPlugin
+ *
+ * Returns: (transfer full) (nullable): an array of plugin status warning messages, or NULL
+ *
+ * Since: 1.24
+ */
+gchar **
+gst_plugin_get_status_warnings (GstPlugin * plugin)
+{
+  return gst_plugin_get_status_messages (plugin, "warning-message");
+}
+
+/**
+ * gst_plugin_get_status_infos:
+ * @plugin: a #GstPlugin
+ *
+ * Returns: (transfer full) (nullable): an array of plugin status info messages, or NULL
+ *
+ * Since: 1.24
+ */
+gchar **
+gst_plugin_get_status_infos (GstPlugin * plugin)
+{
+  return gst_plugin_get_status_messages (plugin, "info-message");
+}
diff --git a/gst/gstplugin.h b/gst/gstplugin.h
index 7bb3356..acbd71a 100644
--- a/gst/gstplugin.h
+++ b/gst/gstplugin.h
@@ -392,6 +392,24 @@ void                    gst_plugin_add_dependency_simple (GstPlugin   * plugin,
                                                           const gchar * paths,
                                                           const gchar * names,
                                                           GstPluginDependencyFlags flags);
+GST_API
+void                    gst_plugin_add_status_error      (GstPlugin   * plugin,
+                                                          const gchar * message);
+GST_API
+void                    gst_plugin_add_status_warning    (GstPlugin   * plugin,
+                                                          const gchar * message);
+GST_API
+void                    gst_plugin_add_status_info       (GstPlugin   * plugin,
+                                                          const gchar * message);
+GST_API
+gchar **                gst_plugin_get_status_errors     (GstPlugin   * plugin);
+
+GST_API
+gchar **                gst_plugin_get_status_warnings   (GstPlugin   * plugin);
+
+GST_API
+gchar **                gst_plugin_get_status_infos      (GstPlugin   * plugin);
+
 GST_API
 void                    gst_plugin_list_free (GList *list);
 
diff --git a/gst/gstpluginfeature.c b/gst/gstpluginfeature.c
index bdcabb4..714dda2 100644
--- a/gst/gstpluginfeature.c
+++ b/gst/gstpluginfeature.c
@@ -310,8 +310,13 @@ gst_plugin_feature_list_debug (GList * list)
  * @min_minor: minimum required minor version
  * @min_micro: minimum required micro version
  *
- * Checks whether the given plugin feature is at least
- *  the required version
+ * Checks whether the given plugin feature is at least the required version.
+ *
+ * Note: Since version 1.24 this function no longer returns %TRUE if the
+ * version is a git development version (e.g. 1.23.0.1) and the check is
+ * for the "next" micro version, that is it will no longer return %TRUE for
+ * e.g. 1.23.0.1 if the check is for 1.23.1. It is still possible to parse
+ * the nano version from the string and do this check that way if needed.
  *
  * Returns: %TRUE if the plugin feature has at least
  *  the required version, otherwise %FALSE.
@@ -355,10 +360,6 @@ gst_plugin_feature_check_version (GstPluginFeature * feature,
         ret = FALSE;
       else if (micro > min_micro)
         ret = TRUE;
-      /* micro is 1 smaller but we have a nano version, this is the upcoming
-       * release of the requested version and we're ok then */
-      else if (nscan == 4 && nano > 0 && (micro + 1 == min_micro))
-        ret = TRUE;
       else
         ret = (micro == min_micro);
 
diff --git a/gst/gstpluginloader-win32.c b/gst/gstpluginloader-win32.c
new file mode 100644
index 0000000..0b31d3a
--- /dev/null
+++ b/gst/gstpluginloader-win32.c
@@ -0,0 +1,1368 @@
+/* GStreamer
+ * Copyright (C) 2023 Seungha Yang <seungha@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <windows.h>
+#include <gst/gst_private.h>
+#include <gst/gstconfig.h>
+#include <gst/gstutils.h>
+#include <gst/gstpluginloader.h>
+#include <gst/gstregistrychunks.h>
+#include <gst/gstregistrybinary.h>
+
+#include <string.h>
+#include <malloc.h>
+
+extern HMODULE _priv_gst_dll_handle;
+
+/* IMPORTANT: Bump the version number if the plugin loader packet protocol
+ * changes. Changes in the binary registry format itself are handled by
+ * bumping the GST_MAGIC_BINARY_VERSION_STR
+ */
+static const guint32 loader_protocol_version = 3;
+
+#define GST_CAT_DEFAULT GST_CAT_PLUGIN_LOADING
+
+#define BUF_INIT_SIZE 512
+#define BUF_GROW_EXTRA 512
+#define BUF_MAX_SIZE (32 * 1024 * 1024)
+
+#define HEADER_SIZE 16
+/* 4 magic hex bytes to mark each packet */
+#define HEADER_MAGIC 0xbefec0ae
+#define ALIGNMENT   (sizeof (void *))
+
+#ifdef _MSC_VER
+#define GST_PLUGIN_LOADER_ARCH TARGET_CPU "-msvc"
+#else
+#define GST_PLUGIN_LOADER_ARCH TARGET_CPU "-mingw"
+#endif
+
+#define GST_PLUGIN_LOADER_ARCH_LEN 64
+
+#define GST_PLUGIN_LOADER_VERSION_INFO_SIZE \
+  (sizeof (guint32) + GST_MAGIC_BINARY_VERSION_LEN + GST_PLUGIN_LOADER_ARCH_LEN)
+
+static ULONG global_pipe_index = 0;
+
+#define SET_LAST_ERROR_AND_RETURN(l) G_STMT_START { \
+  gchar *_err; \
+  (l)->last_err = GetLastError(); \
+  _err = g_win32_error_message ((l)->last_err); \
+  GST_WARNING ("Operation failed with 0x%x (%s)", (l)->last_err, \
+      GST_STR_NULL (_err)); \
+  g_free (_err); \
+  if ((l)->last_err == ERROR_SUCCESS) \
+    (l)->last_err = ERROR_OPERATION_ABORTED; \
+  SetEvent ((l)->cancellable); \
+  return; \
+} G_STMT_END
+
+#define SET_ERROR_AND_RETURN(l,e) G_STMT_START { \
+  (l)->last_err = e; \
+  if (e != ERROR_SUCCESS) { \
+    gchar *_err = g_win32_error_message ((l)->last_err); \
+    GST_WARNING ("Operation failed with 0x%x (%s)", (l)->last_err, \
+        GST_STR_NULL (_err)); \
+    g_free (_err); \
+  } \
+  SetEvent ((l)->cancellable); \
+  return; \
+} G_STMT_END
+
+static GstPluginLoader *gst_plugin_loader_new (GstRegistry * registry);
+static gboolean gst_plugin_loader_free (GstPluginLoader * loader);
+static gboolean gst_plugin_loader_load (GstPluginLoader * loader,
+    const gchar * filename, off_t file_size, time_t file_mtime);
+
+/* functions used in GstRegistry scanning */
+const GstPluginLoaderFuncs _priv_gst_plugin_loader_funcs = {
+  gst_plugin_loader_new, gst_plugin_loader_free, gst_plugin_loader_load
+};
+
+typedef enum
+{
+  PACKET_VERSION = (1 << 0),
+  PACKET_LOAD_PLUGIN = (1 << 1),
+  PACKET_PLUGIN_DETAILS = (1 << 2),
+  PACKET_EXIT = (1 << 3),
+} PacketType;
+
+typedef struct
+{
+  guint32 seq_num;
+  gchar *filename;
+  off_t file_size;
+  time_t file_mtime;
+} PendingPluginEntry;
+
+static void
+pending_plugin_entry_free (PendingPluginEntry * entry)
+{
+  g_free (entry->filename);
+  g_free (entry);
+}
+
+typedef struct
+{
+  guint32 type;
+  guint32 seq_num;
+  guint32 payload_size;
+  guint32 magic;
+} PacketHeader;
+
+G_STATIC_ASSERT (sizeof (PacketHeader) == HEADER_SIZE);
+
+/* Base struct both for server and client */
+typedef struct
+{
+  OVERLAPPED overlap;
+  HANDLE cancellable;
+
+  gboolean is_client;
+  PacketType expected_pkt;
+
+  HANDLE pipe;
+  guint last_err;
+
+  PacketHeader rx_header;
+  guint8 *rx_buf;
+  guint rx_buf_size;
+
+  PacketHeader tx_header;
+  guint8 *tx_buf;
+  guint tx_buf_size;
+
+  /* loader-protocol-version: 4 bytes
+   * binary chunk format: 64 bytes
+   * architecture: 64 bytes */
+  guint8 version_info[GST_PLUGIN_LOADER_VERSION_INFO_SIZE];
+  gboolean apc_called;
+} Win32PluginLoader;
+
+struct _GstPluginLoader
+{
+  Win32PluginLoader parent;
+
+  gchar *helper_bin;
+
+  GstRegistry *registry;
+  gchar *pipe_prefix;
+
+  wchar_t *env_string;
+
+  PROCESS_INFORMATION child_info;
+  LARGE_INTEGER frequency;
+
+  gboolean got_plugin_detail;
+  gboolean client_running;
+  guint seq_num;
+
+  GQueue pending_plugins;
+};
+
+static void
+win32_plugin_loader_init (Win32PluginLoader * self, gboolean is_client)
+{
+  memset (self, 0, sizeof (Win32PluginLoader));
+  self->cancellable = CreateEventA (NULL, TRUE, FALSE, NULL);
+  GST_WRITE_UINT32_BE (self->version_info, loader_protocol_version);
+  strcpy ((char *) self->version_info + sizeof (guint32),
+      GST_MAGIC_BINARY_VERSION_STR);
+  strcpy ((char *) self->version_info + sizeof (guint32) +
+      GST_MAGIC_BINARY_VERSION_LEN, GST_PLUGIN_LOADER_ARCH);
+
+  self->is_client = is_client;
+  self->pipe = INVALID_HANDLE_VALUE;
+  self->last_err = ERROR_SUCCESS;
+
+  self->rx_buf_size = self->tx_buf_size = BUF_INIT_SIZE;
+  self->rx_buf = _aligned_malloc (BUF_INIT_SIZE, ALIGNMENT);
+  self->tx_buf = _aligned_malloc (BUF_INIT_SIZE, ALIGNMENT);
+}
+
+static void
+win32_plugin_loader_clear (Win32PluginLoader * self)
+{
+  if (self->pipe != INVALID_HANDLE_VALUE)
+    CloseHandle (self->pipe);
+  if (self->cancellable)
+    CloseHandle (self->cancellable);
+  if (self->overlap.hEvent)
+    CloseHandle (self->overlap.hEvent);
+
+  _aligned_free (self->tx_buf);
+  _aligned_free (self->rx_buf);
+}
+
+static gboolean
+win32_plugin_loader_resize (Win32PluginLoader * self, gboolean is_tx,
+    guint size)
+{
+  guint new_size;
+
+  if (size > BUF_MAX_SIZE) {
+    GST_WARNING ("Too large size %u", size);
+    return FALSE;
+  }
+
+  if (is_tx) {
+    if (self->tx_buf_size <= size) {
+      new_size = size + BUF_GROW_EXTRA;
+      GST_LOG ("Resizing TX buffer %u -> %u", self->tx_buf_size, new_size);
+      self->tx_buf_size = new_size;
+      self->tx_buf = _aligned_realloc (self->tx_buf,
+          self->tx_buf_size, ALIGNMENT);
+    }
+  } else {
+    if (self->rx_buf_size <= size) {
+      new_size = size + BUF_GROW_EXTRA;
+      GST_LOG ("Resizing RX buffer %u -> %u", self->rx_buf_size, new_size);
+      self->rx_buf_size = new_size;
+      self->rx_buf = _aligned_realloc (self->rx_buf,
+          self->rx_buf_size, ALIGNMENT);
+    }
+  }
+
+  return TRUE;
+}
+
+static void win32_plugin_loader_write_packet_async (Win32PluginLoader * self,
+    guint type, guint seq_num, const guint8 * payload, guint payload_size);
+static void win32_plugin_loader_read_header_async (Win32PluginLoader * self);
+static gboolean win32_plugin_loader_run (Win32PluginLoader * self,
+    DWORD timeout);
+
+static void
+gst_plugin_loader_create_blacklist (GstPluginLoader * self,
+    PendingPluginEntry * entry)
+{
+  GstPlugin *plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
+
+  plugin->filename = g_strdup (entry->filename);
+  plugin->file_mtime = entry->file_mtime;
+  plugin->file_size = entry->file_size;
+  GST_OBJECT_FLAG_SET (plugin, GST_PLUGIN_FLAG_BLACKLISTED);
+
+  plugin->basename = g_path_get_basename (plugin->filename);
+  plugin->desc.name = g_intern_string (plugin->basename);
+  plugin->desc.description = "Plugin for blacklisted file";
+  plugin->desc.version = "0.0.0";
+  plugin->desc.license = "BLACKLIST";
+  plugin->desc.source = plugin->desc.license;
+  plugin->desc.package = plugin->desc.license;
+  plugin->desc.origin = plugin->desc.license;
+
+  GST_DEBUG ("Adding blacklist plugin '%s'", plugin->desc.name);
+  gst_registry_add_plugin (self->registry, plugin);
+}
+
+static gboolean
+gst_plugin_loader_try_helper (GstPluginLoader * self, gchar * location)
+{
+  Win32PluginLoader *loader = (Win32PluginLoader *) self;
+  gchar *cmd = NULL;
+  gchar *err = NULL;
+  gint last_err;
+  gunichar2 *wcmd = NULL;
+  STARTUPINFOW si;
+  BOOL ret;
+  DWORD n_bytes;
+  DWORD wait_ret;
+  gchar *pipe_name = NULL;
+  HANDLE waitables[2];
+  LARGE_INTEGER now;
+  LONGLONG timeout;
+
+  memset (&si, 0, sizeof (STARTUPINFOW));
+  si.cb = sizeof (STARTUPINFOW);
+
+  pipe_name = g_strdup_printf ("%s.%u", self->pipe_prefix,
+      (guint) InterlockedIncrement ((LONG *) & global_pipe_index));
+  cmd = g_strdup_printf ("%s -l %s %s", location, _gst_executable_path,
+      pipe_name);
+  wcmd = g_utf8_to_utf16 (cmd, -1, NULL, NULL, NULL);
+  if (!wcmd) {
+    GST_WARNING ("Couldn't build cmd string");
+    goto error;
+  }
+
+  loader->pipe = CreateNamedPipeA (pipe_name,
+      FILE_FLAG_FIRST_PIPE_INSTANCE | PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+      PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+      1, BUF_INIT_SIZE, BUF_INIT_SIZE, 5000, NULL);
+
+  if (loader->pipe == INVALID_HANDLE_VALUE) {
+    last_err = GetLastError ();
+    err = g_win32_error_message (last_err);
+    GST_WARNING ("CreateNamedPipeA failed with 0x%x (%s)",
+        last_err, GST_STR_NULL (err));
+    goto error;
+  }
+
+  loader->overlap.Internal = 0;
+  loader->overlap.InternalHigh = 0;
+  loader->overlap.Offset = 0;
+  loader->overlap.OffsetHigh = 0;
+  loader->apc_called = FALSE;
+
+  /* Async pipe should return zero */
+  if (ConnectNamedPipe (loader->pipe, &loader->overlap)) {
+    last_err = GetLastError ();
+    err = g_win32_error_message (last_err);
+    GST_ERROR ("ConnectNamedPipe failed with 0x%x (%s)",
+        last_err, GST_STR_NULL (err));
+    goto error;
+  }
+
+  /* We didn't create child process yet. So GetLastError should return
+   * ERROR_IO_PENDING. Otherwise there's some error or unexpected process is
+   * trying to connect to our pipe */
+  last_err = GetLastError ();
+  if (last_err != ERROR_IO_PENDING) {
+    err = g_win32_error_message (last_err);
+    GST_ERROR ("ConnectNamedPipe failed with 0x%x (%s)",
+        last_err, GST_STR_NULL (err));
+    goto error;
+  }
+
+  GST_LOG ("Trying to spawn gst-plugin-scanner helper at %s, command %s",
+      location, cmd);
+  ret = CreateProcessW (NULL, (WCHAR *) wcmd, NULL, NULL, FALSE,
+      CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW, (LPVOID) self->env_string,
+      NULL, &si, &self->child_info);
+
+  if (!ret) {
+    last_err = GetLastError ();
+    err = g_win32_error_message (last_err);
+    GST_ERROR ("Spawning gst-plugin-scanner helper failed with 0x%x (%s)",
+        last_err, GST_STR_NULL (err));
+    goto error;
+  }
+
+  ret = QueryPerformanceCounter (&now);
+  g_assert (ret);
+
+  /* 10 seconds timeout */
+  timeout = now.QuadPart + 10 * self->frequency.QuadPart;
+
+  /* Wait for client connection */
+  waitables[0] = loader->overlap.hEvent;
+  waitables[1] = self->child_info.hProcess;
+  do {
+    wait_ret = WaitForMultipleObjectsEx (2, waitables, FALSE, 5000, TRUE);
+    switch (wait_ret) {
+      case WAIT_OBJECT_0:
+        ret = GetOverlappedResult (loader->pipe,
+            &loader->overlap, &n_bytes, FALSE);
+        if (!ret) {
+          last_err = GetLastError ();
+          err = g_win32_error_message (last_err);
+          GST_ERROR ("GetOverlappedResult failed with 0x%x (%s)",
+              last_err, GST_STR_NULL (err));
+          goto kill_child;
+        }
+        break;
+      case WAIT_OBJECT_0 + 1:
+        GST_ERROR ("Child process got terminated");
+        goto kill_child;
+      case WAIT_IO_COMPLETION:
+        ret = QueryPerformanceCounter (&now);
+        g_assert (ret);
+
+        if (now.QuadPart > timeout) {
+          GST_ERROR ("Connection takes too long, give up");
+          goto kill_child;
+        }
+
+        if (loader->apc_called) {
+          GST_WARNING
+              ("Unexpected our APC called while waiting for client connection");
+        } else {
+          GST_DEBUG ("WAIT_IO_COMPLETION, waiting again");
+        }
+        break;
+      case WAIT_TIMEOUT:
+        GST_ERROR ("WaitForMultipleObjectsEx timeout");
+        goto kill_child;
+      default:
+        last_err = GetLastError ();
+        err = g_win32_error_message (last_err);
+        GST_ERROR
+            ("Unexpected WaitForMultipleObjectsEx return 0x%x, with 0x%x (%s)",
+            (guint) wait_ret, last_err, GST_STR_NULL (err));
+        goto kill_child;
+    }
+  } while (wait_ret == WAIT_IO_COMPLETION);
+
+  /* Do version check */
+  loader->expected_pkt = PACKET_VERSION;
+  win32_plugin_loader_write_packet_async (loader, PACKET_VERSION, 0, NULL, 0);
+  if (!win32_plugin_loader_run (loader, 10000)) {
+    GST_ERROR ("Version check failed");
+    goto kill_child;
+  }
+
+  GST_LOG ("Child pid %u is running now", (guint) self->child_info.dwProcessId);
+
+  self->client_running = TRUE;
+
+  g_free (cmd);
+  g_free (wcmd);
+  g_free (err);
+  g_free (pipe_name);
+
+  return TRUE;
+
+kill_child:
+  TerminateProcess (self->child_info.hProcess, 0);
+  CloseHandle (self->child_info.hProcess);
+  CloseHandle (self->child_info.hThread);
+  memset (&self->child_info, 0, sizeof (PROCESS_INFORMATION));
+
+  goto error;
+
+error:
+  if (loader->pipe != INVALID_HANDLE_VALUE)
+    CloseHandle (loader->pipe);
+  loader->pipe = INVALID_HANDLE_VALUE;
+  g_free (cmd);
+  g_free (wcmd);
+  g_free (err);
+  g_free (pipe_name);
+
+  return FALSE;
+}
+
+static gchar *
+find_helper_bin_location (void)
+{
+  const gchar *env;
+  char *relocated_libgstreamer;
+
+  /* Find the gst-plugin-scanner */
+  env = g_getenv ("GST_PLUGIN_SCANNER_1_0");
+  if (!env)
+    env = g_getenv ("GST_PLUGIN_SCANNER");
+
+  if (env && *env != '\0') {
+    /* use the env-var if it is set */
+    GST_LOG ("Trying GST_PLUGIN_SCANNER env var: %s", env);
+    return g_strdup (env);
+  }
+
+  /* use the installed version */
+  GST_LOG ("Trying installed plugin scanner");
+
+#define MAX_PATH_DEPTH 64
+
+  relocated_libgstreamer = priv_gst_get_relocated_libgstreamer ();
+  if (relocated_libgstreamer) {
+    int plugin_subdir_depth = priv_gst_count_directories (GST_PLUGIN_SUBDIR);
+
+    GST_DEBUG ("found libgstreamer-" GST_API_VERSION " library "
+        "at %s", relocated_libgstreamer);
+
+    if (plugin_subdir_depth < MAX_PATH_DEPTH) {
+      const char *filenamev[MAX_PATH_DEPTH + 5];
+      int i = 0, j;
+      gchar *helper_bin_location;
+
+      filenamev[i++] = relocated_libgstreamer;
+      for (j = 0; j < plugin_subdir_depth; j++)
+        filenamev[i++] = "..";
+      filenamev[i++] = GST_PLUGIN_SCANNER_SUBDIR;
+      filenamev[i++] = "gstreamer-" GST_API_VERSION;
+      filenamev[i++] = "gst-plugin-scanner.exe";
+      filenamev[i++] = NULL;
+      g_assert (i <= MAX_PATH_DEPTH + 5);
+
+      GST_DEBUG ("constructing path to system plugin scanner using "
+          "plugin dir: \'%s\', plugin scanner dir: \'%s\'",
+          GST_PLUGIN_SUBDIR, GST_PLUGIN_SCANNER_SUBDIR);
+      helper_bin_location = g_build_filenamev ((char **) filenamev);
+      g_free (relocated_libgstreamer);
+      return helper_bin_location;
+    } else {
+      GST_WARNING ("GST_PLUGIN_SUBDIR: \'%s\' has too many path segments",
+          GST_PLUGIN_SUBDIR);
+    }
+  }
+#undef MAX_PATH_DEPTH
+
+  g_free (relocated_libgstreamer);
+  return g_strdup (GST_PLUGIN_SCANNER_INSTALLED);
+}
+
+static gboolean
+gst_plugin_loader_spawn (GstPluginLoader * loader)
+{
+  if (loader->client_running)
+    return TRUE;
+
+  if (!loader->helper_bin) {
+    GST_ERROR ("Unknown helper bin location");
+    return FALSE;
+  }
+
+  if (!gst_plugin_loader_try_helper (loader, loader->helper_bin))
+    GST_INFO ("No gst-plugin-scanner available, or not working");
+
+  return loader->client_running;
+}
+
+static VOID WINAPI
+win32_plugin_loader_write_payload_finish (DWORD error_code, DWORD n_bytes,
+    LPOVERLAPPED overlapped)
+{
+  Win32PluginLoader *self = (Win32PluginLoader *) overlapped;
+  PacketHeader *header = &self->tx_header;
+
+  self->apc_called = TRUE;
+
+  if (error_code != ERROR_SUCCESS)
+    SET_ERROR_AND_RETURN (self, error_code);
+
+  if (n_bytes != header->payload_size) {
+    GST_WARNING ("Unexpected sent byte size %u", (guint) n_bytes);
+    SET_ERROR_AND_RETURN (self, ERROR_BAD_FORMAT);
+  }
+
+  GST_LOG ("Payload (%u) sent for type %u", header->payload_size, header->type);
+  win32_plugin_loader_read_header_async (self);
+}
+
+static VOID WINAPI
+win32_plugin_loader_write_header_finish (DWORD error_code, DWORD n_bytes,
+    LPOVERLAPPED overlapped)
+{
+  Win32PluginLoader *self = (Win32PluginLoader *) overlapped;
+  PacketHeader *header = &self->tx_header;
+
+  self->apc_called = TRUE;
+
+  if (error_code != ERROR_SUCCESS)
+    SET_ERROR_AND_RETURN (self, error_code);
+
+  if (n_bytes != HEADER_SIZE) {
+    GST_WARNING ("Unexpected header byte size received %d", (guint) n_bytes);
+    SET_ERROR_AND_RETURN (self, ERROR_BAD_FORMAT);
+  }
+
+  GST_LOG ("Header type %u sent", header->type);
+  if (self->tx_header.payload_size) {
+    GST_LOG ("Sending payload %u", self->tx_header.payload_size);
+    if (!WriteFileEx (self->pipe, self->tx_buf + HEADER_SIZE,
+            self->tx_header.payload_size, (OVERLAPPED *) self,
+            win32_plugin_loader_write_payload_finish)) {
+      SET_LAST_ERROR_AND_RETURN (self);
+    }
+  } else {
+    /* This is our final message */
+    if (self->is_client && header->type == PACKET_EXIT)
+      SET_ERROR_AND_RETURN (self, ERROR_SUCCESS);
+
+    win32_plugin_loader_read_header_async (self);
+  }
+}
+
+static void
+win32_plugin_loader_write_packet_async (Win32PluginLoader * self, guint type,
+    guint seq_num, const guint8 * payload, guint payload_size)
+{
+  PacketHeader *header = &self->tx_header;
+
+  if (!win32_plugin_loader_resize (self, TRUE, HEADER_SIZE + payload_size))
+    SET_ERROR_AND_RETURN (self, ERROR_BAD_FORMAT);
+
+  header->type = type;
+  header->seq_num = seq_num;
+  header->payload_size = payload_size;
+  header->magic = HEADER_MAGIC;
+
+  GST_LOG ("Sending header - type %d, seq_num %d, payload_size %d, magic 0x%x",
+      header->type, header->seq_num, header->payload_size, header->magic);
+
+  memcpy (self->tx_buf, &self->tx_header, sizeof (PacketHeader));
+  if (payload && payload_size)
+    memcpy (self->tx_buf + HEADER_SIZE, payload, payload_size);
+
+  if (!WriteFileEx (self->pipe, self->tx_buf, HEADER_SIZE,
+          (OVERLAPPED *) self, win32_plugin_loader_write_header_finish)) {
+    SET_LAST_ERROR_AND_RETURN (self);
+  }
+}
+
+static void
+win32_plugin_loader_client_load (Win32PluginLoader * self,
+    const gchar * file_name, guint seq_num)
+{
+  GstPlugin *plugin;
+  GList *chunks = NULL;
+
+  GST_DEBUG ("Plugin scanner loading file %s, seq-num %u", file_name, seq_num);
+
+  plugin = gst_plugin_load_file (file_name, NULL);
+  if (plugin) {
+    GList *iter;
+    guint offset;
+    guint i;
+
+    GST_LOG ("Plugin %s loaded", file_name);
+    if (!_priv_gst_registry_chunks_save_plugin (&chunks, gst_registry_get (),
+            plugin)) {
+      GST_LOG ("Saving plugin %s failed", file_name);
+      gst_object_unref (plugin);
+      win32_plugin_loader_write_packet_async (self, PACKET_PLUGIN_DETAILS,
+          seq_num, NULL, 0);
+      return;
+    }
+
+    offset = HEADER_SIZE;
+
+    for (iter = chunks, i = 0; iter; iter = g_list_next (iter), i++) {
+      GstRegistryChunk *c = (GstRegistryChunk *) iter->data;
+      guint padsize = 0;
+
+      if (c->align && (offset % ALIGNMENT) != 0)
+        padsize = ALIGNMENT - (offset % ALIGNMENT);
+
+      GST_LOG ("Plugin %s chunk %d, size %d, offset %d, padding size %d",
+          file_name, i, c->size, offset, padsize);
+
+      if (!win32_plugin_loader_resize (self, TRUE, offset + padsize + c->size)) {
+        g_list_free_full (chunks,
+            (GDestroyNotify) _priv_gst_registry_chunk_free);
+        gst_object_unref (plugin);
+        SET_ERROR_AND_RETURN (self, ERROR_BAD_FORMAT);
+      }
+
+      if (padsize)
+        memset (self->tx_buf + offset, 0, padsize);
+
+      memcpy (self->tx_buf + offset + padsize, c->data, c->size);
+      offset += padsize + c->size;
+    }
+
+    if (chunks)
+      g_list_free_full (chunks, (GDestroyNotify) _priv_gst_registry_chunk_free);
+
+    gst_object_unref (plugin);
+
+    self->tx_header.type = PACKET_PLUGIN_DETAILS;
+    self->tx_header.seq_num = seq_num;
+    self->tx_header.payload_size = offset - HEADER_SIZE;
+    self->tx_header.magic = HEADER_MAGIC;
+
+    memcpy (self->tx_buf, &self->tx_header, sizeof (PacketHeader));
+    if (!WriteFileEx (self->pipe, self->tx_buf, HEADER_SIZE,
+            (OVERLAPPED *) self, win32_plugin_loader_write_header_finish)) {
+      SET_LAST_ERROR_AND_RETURN (self);
+    }
+  } else {
+    win32_plugin_loader_write_packet_async (self,
+        PACKET_PLUGIN_DETAILS, seq_num, NULL, 0);
+  }
+}
+
+static void
+win32_plugin_loader_process_packet (Win32PluginLoader * self)
+{
+  PacketHeader *header = &self->rx_header;
+  gchar *payload = (gchar *) self->rx_buf + HEADER_SIZE;
+
+  GST_LOG ("Processing packet - type %u, seq-num %u, payload-size %u",
+      header->type, header->seq_num, header->payload_size);
+
+  if ((header->type & self->expected_pkt) == 0) {
+    GST_WARNING ("Unexpected packet type %u", header->type);
+    goto error;
+  }
+
+  switch (header->type) {
+    case PACKET_VERSION:
+      if (self->is_client) {
+        self->expected_pkt = PACKET_LOAD_PLUGIN | PACKET_EXIT;
+        GST_LOG ("Got version packet from server, responding");
+        win32_plugin_loader_write_packet_async (self, PACKET_VERSION,
+            header->seq_num, self->version_info,
+            GST_PLUGIN_LOADER_VERSION_INFO_SIZE);
+      } else {
+        guint32 client_ver;
+        gchar *binary_reg_ver;
+        gchar *arch_ver;
+
+        GST_LOG ("Got version packet from client");
+        if (header->payload_size < GST_PLUGIN_LOADER_VERSION_INFO_SIZE) {
+          GST_WARNING ("Too small size of version pkt");
+          goto error;
+        }
+
+        client_ver = GST_READ_UINT32_BE (self->rx_buf + HEADER_SIZE);
+        if (client_ver != loader_protocol_version) {
+          GST_WARNING ("Different protocol version %d (ours %d)",
+              client_ver, loader_protocol_version);
+          goto error;
+        }
+
+        binary_reg_ver = (gchar *)
+            (self->rx_buf + HEADER_SIZE + sizeof (guint32));
+        if (strncmp (binary_reg_ver, GST_MAGIC_BINARY_VERSION_STR,
+                GST_MAGIC_BINARY_VERSION_LEN) != 0) {
+          GST_WARNING ("Different binary chunk format");
+          goto error;
+        }
+
+        arch_ver = binary_reg_ver + GST_MAGIC_BINARY_VERSION_LEN;
+        if (strncmp (arch_ver, GST_PLUGIN_LOADER_ARCH,
+                GST_PLUGIN_LOADER_ARCH_LEN) != 0) {
+          GST_WARNING ("Different architecture");
+          goto error;
+        }
+
+        GST_LOG ("Version packet handled");
+        SET_ERROR_AND_RETURN (self, ERROR_SUCCESS);
+      }
+      return;
+    case PACKET_LOAD_PLUGIN:
+      if (self->is_client) {
+        win32_plugin_loader_client_load (self, payload, header->seq_num);
+      } else {
+        /* Something went wrong, server shouldn't receive this pkt */
+        SET_ERROR_AND_RETURN (self, ERROR_BAD_FORMAT);
+      }
+      return;
+    case PACKET_PLUGIN_DETAILS:
+      if (self->is_client) {
+        /* Something went wrong, client shouldn't receive this pkt */
+        SET_ERROR_AND_RETURN (self, ERROR_BAD_FORMAT);
+      } else {
+        GstPluginLoader *server = (GstPluginLoader *) self;
+        PendingPluginEntry *entry = NULL;
+
+        /* remove outdated ones */
+        while (!g_queue_is_empty (&server->pending_plugins)) {
+          PendingPluginEntry *pending =
+              g_queue_peek_head (&server->pending_plugins);
+          if (pending->seq_num > header->seq_num) {
+            break;
+          } else if (pending->seq_num == header->seq_num) {
+            entry = pending;
+            break;
+          } else {
+            /* Remove old entry */
+            g_queue_pop_head (&server->pending_plugins);
+            pending_plugin_entry_free (pending);
+          }
+        }
+
+        if (header->payload_size > 0) {
+          GstPlugin *new_plugin = NULL;
+          if (!_priv_gst_registry_chunks_load_plugin (server->registry,
+                  &payload, payload + header->payload_size, &new_plugin)) {
+            /* Got garbage from the child, so fail and trigger replay of plugins */
+            GST_ERROR ("Problems loading plugin details with seqnum %u",
+                header->seq_num);
+            goto error;
+          }
+
+          GST_OBJECT_FLAG_UNSET (new_plugin, GST_PLUGIN_FLAG_CACHED);
+
+          GST_LOG ("Marking plugin %p as registered as %s", new_plugin,
+              new_plugin->filename);
+          new_plugin->registered = TRUE;
+          server->got_plugin_detail = TRUE;
+        } else if (entry) {
+          gst_plugin_loader_create_blacklist (server, entry);
+          server->got_plugin_detail = TRUE;
+        }
+
+        /* Done with this entry, pop from pending list */
+        if (entry) {
+          g_queue_pop_head (&server->pending_plugins);
+          pending_plugin_entry_free (entry);
+        }
+
+        SET_ERROR_AND_RETURN (self, ERROR_SUCCESS);
+      }
+      return;
+    case PACKET_EXIT:
+      if (self->is_client) {
+        GST_LOG ("Replying EXIT packet");
+        win32_plugin_loader_write_packet_async (self,
+            PACKET_EXIT, header->seq_num, NULL, 0);
+      } else {
+        GST_LOG ("Got EXIT packet from child");
+        SET_ERROR_AND_RETURN (self, ERROR_SUCCESS);
+      }
+      return;
+    default:
+      break;
+  }
+
+  /* Unexpected pkt type */
+  GST_WARNING ("Unexpected packet type %d", header->type);
+
+error:
+  SET_ERROR_AND_RETURN (self, ERROR_BAD_FORMAT);
+}
+
+static VOID WINAPI
+win32_plugin_loader_read_payload_finish (DWORD error_code, DWORD n_bytes,
+    LPOVERLAPPED overlapped)
+{
+  Win32PluginLoader *self = (Win32PluginLoader *) overlapped;
+  PacketHeader *header = &self->rx_header;
+
+  self->apc_called = TRUE;
+
+  if (error_code != ERROR_SUCCESS)
+    SET_ERROR_AND_RETURN (self, error_code);
+
+  if (n_bytes != header->payload_size) {
+    GST_WARNING ("Unexpected payload size %u", (guint) n_bytes);
+    SET_ERROR_AND_RETURN (self, ERROR_BAD_FORMAT);
+  }
+
+  GST_LOG ("Received payload size %u", header->payload_size);
+  win32_plugin_loader_process_packet (self);
+}
+
+static VOID WINAPI
+win32_plugin_loader_read_header_finish (DWORD error_code, DWORD n_bytes,
+    LPOVERLAPPED overlapped)
+{
+  Win32PluginLoader *self = (Win32PluginLoader *) overlapped;
+  PacketHeader *header = &self->rx_header;
+
+  self->apc_called = TRUE;
+
+  if (error_code != ERROR_SUCCESS)
+    SET_ERROR_AND_RETURN (self, error_code);
+
+  if (n_bytes != HEADER_SIZE) {
+    GST_WARNING ("Unexpected header byte size received %d", (guint) n_bytes);
+    goto error;
+  }
+
+  /* Validates pkt header */
+  memcpy (header, self->rx_buf, sizeof (PacketHeader));
+  if (header->payload_size + HEADER_SIZE > BUF_MAX_SIZE) {
+    GST_WARNING ("Received excessively large packet");
+    goto error;
+  }
+
+  GST_LOG ("Received header - type %d, seq-num %d, payload-size %d, magic 0x%x",
+      header->type, header->seq_num, header->payload_size, header->magic);
+
+  if (header->magic != HEADER_MAGIC) {
+    GST_WARNING ("Invalid packet (bad magic number) received");
+    goto error;
+  }
+
+  /* Reads remaining payload if any */
+  if (header->payload_size > 0) {
+    GST_LOG ("Reading payload size %u", header->payload_size);
+    if (!win32_plugin_loader_resize (self,
+            FALSE, HEADER_SIZE + header->payload_size)) {
+      goto error;
+    }
+
+    if (!ReadFileEx (self->pipe, self->rx_buf + HEADER_SIZE,
+            header->payload_size, (OVERLAPPED *) self,
+            win32_plugin_loader_read_payload_finish)) {
+      SET_LAST_ERROR_AND_RETURN (self);
+    }
+  } else {
+    /* Or this is header only pkt */
+    win32_plugin_loader_process_packet (self);
+  }
+
+  return;
+
+error:
+  SET_ERROR_AND_RETURN (self, ERROR_BAD_FORMAT);
+}
+
+static void
+win32_plugin_loader_read_header_async (Win32PluginLoader * self)
+{
+  if (!ReadFileEx (self->pipe, self->rx_buf, HEADER_SIZE,
+          (OVERLAPPED *) self, win32_plugin_loader_read_header_finish)) {
+    SET_LAST_ERROR_AND_RETURN (self);
+  }
+
+  self->last_err = ERROR_SUCCESS;
+}
+
+static gboolean
+win32_plugin_loader_run (Win32PluginLoader * self, DWORD timeout_ms)
+{
+  gboolean ret = FALSE;
+
+  do {
+    DWORD wait_ret =
+        WaitForSingleObjectEx (self->cancellable, timeout_ms, TRUE);
+
+    switch (wait_ret) {
+      case WAIT_OBJECT_0:
+        if (self->last_err != ERROR_SUCCESS) {
+          GST_DEBUG ("Operation cancelled");
+        } else {
+          GST_LOG ("Operation finished");
+          ret = TRUE;
+        }
+        goto out;
+      case WAIT_IO_COMPLETION:
+        /* do nothing */
+        break;
+      default:
+        /* timeout or unexpected wake up */
+        GST_WARNING ("Unexpected wait return 0x%x", (guint) wait_ret);
+        goto out;
+    }
+  } while (TRUE);
+
+out:
+  CancelIoEx (self->pipe, &self->overlap);
+  ResetEvent (self->cancellable);
+
+  return ret;
+}
+
+static gboolean
+gst_plugin_loader_server_load (GstPluginLoader * self,
+    PendingPluginEntry * entry)
+{
+  Win32PluginLoader *loader = (Win32PluginLoader *) self;
+
+  GST_DEBUG ("Synchronously loading plugin file %s", entry->filename);
+
+  loader->last_err = ERROR_SUCCESS;
+  loader->expected_pkt = PACKET_PLUGIN_DETAILS;
+  win32_plugin_loader_write_packet_async (loader, PACKET_LOAD_PLUGIN,
+      entry->seq_num, (guint8 *) entry->filename, strlen (entry->filename) + 1);
+  if (loader->last_err != ERROR_SUCCESS) {
+    ResetEvent (loader->cancellable);
+    return FALSE;
+  }
+
+  return win32_plugin_loader_run (loader, 60000);
+}
+
+/* *INDENT-OFF* */
+static gboolean
+is_path_env_string (wchar_t *str)
+{
+  if (wcslen (str) <= wcslen (L"PATH="))
+    return FALSE;
+
+  /* Env variable is case-insensitive */
+  if ((str[0] == L'P' || str[0] == L'p') &&
+      (str[1] == L'A' || str[1] == L'a') &&
+      (str[2] == L'T' || str[2] == L't') &&
+      (str[3] == L'H' || str[3] == L'h') && str[4] == L'=') {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+/* *INDENT-ON* */
+
+static wchar_t *
+generate_env_string (void)
+{
+  wchar_t *env_str;
+  wchar_t *new_env_string = NULL;
+  size_t origin_len;
+  wchar_t lib_dir[MAX_PATH];
+  wchar_t *origin_path = NULL;
+  guint i;
+
+  env_str = GetEnvironmentStringsW ();
+  /* Count original env string length */
+  for (i = 0, origin_len = 0; env_str[origin_len]; i++) {
+    if (!origin_path) {
+      if (is_path_env_string (&env_str[origin_len]))
+        origin_path = _wcsdup (&env_str[origin_len]);
+    }
+
+    origin_len += wcslen (&env_str[origin_len]) + 1;
+  }
+
+  /* Environment string is terminated with additional L'\0' */
+  origin_len++;
+
+  if (GetModuleFileNameW (_priv_gst_dll_handle, lib_dir, MAX_PATH)) {
+    wchar_t *pos;
+    size_t new_len;
+    size_t lib_dir_len;
+    wchar_t *sep = wcsrchr (lib_dir, L'\\');
+    if (sep)
+      *sep = L'\0';
+
+    lib_dir_len = wcslen (lib_dir);
+
+    /* +1 for L';' seperator */
+    new_len = origin_len + lib_dir_len + 1;
+
+    new_env_string = calloc (1, sizeof (wchar_t) * new_len);
+
+    pos = new_env_string;
+    /* Copy every env except for PATH */
+    for (i = 0, origin_len = 0; env_str[origin_len]; i++) {
+      size_t len = wcslen (&env_str[origin_len]);
+      if (!is_path_env_string (&env_str[origin_len])) {
+        wcscpy (pos, &env_str[origin_len]);
+        pos += len + 1;
+      }
+
+      origin_len += len + 1;
+    }
+
+    /* Then copy PATH env */
+    wcscpy (pos, L"PATH=");
+    pos += wcslen (L"PATH=");
+    wcscpy (pos, lib_dir);
+    pos += lib_dir_len;
+    *pos = L';';
+    if (origin_path)
+      wcscpy (pos + 1, origin_path + wcslen (L"PATH="));
+  }
+
+  free (origin_path);
+  FreeEnvironmentStringsW (env_str);
+
+  return new_env_string;
+}
+
+static GstPluginLoader *
+gst_plugin_loader_new (GstRegistry * registry)
+{
+  GstPluginLoader *self;
+  Win32PluginLoader *loader;
+  BOOL ret;
+  gchar *helper_bin_location;
+  wchar_t *helper_bin_location_wide;
+  wchar_t *env_string;
+  STARTUPINFOW si;
+  PROCESS_INFORMATION pi;
+  DWORD wait_ret;
+  DWORD exit_code = 0;
+
+  if (!registry)
+    return NULL;
+
+  helper_bin_location = find_helper_bin_location ();
+  if (!helper_bin_location)
+    return NULL;
+
+  helper_bin_location_wide = g_utf8_to_utf16 (helper_bin_location, -1, NULL,
+      NULL, NULL);
+  if (!helper_bin_location_wide) {
+    g_free (helper_bin_location);
+    return NULL;
+  }
+
+  env_string = generate_env_string ();
+
+  memset (&si, 0, sizeof (STARTUPINFOW));
+  memset (&pi, 0, sizeof (PROCESS_INFORMATION));
+
+  /* Checks whether helper bin is installed or not. Expected exit code is 1 */
+  ret = CreateProcessW (NULL, helper_bin_location_wide, NULL, NULL, FALSE,
+      CREATE_UNICODE_ENVIRONMENT, env_string, NULL, &si, &pi);
+  g_free (helper_bin_location_wide);
+
+  if (!ret) {
+    GST_WARNING ("Couldn't create helper process");
+    g_free (helper_bin_location);
+    free (env_string);
+    return NULL;
+  }
+
+  wait_ret = WaitForSingleObject (pi.hProcess, 5000);
+  if (wait_ret != WAIT_OBJECT_0) {
+    GST_WARNING ("Child process is not terminated");
+    TerminateProcess (pi.hProcess, 0);
+    CloseHandle (pi.hProcess);
+    CloseHandle (pi.hThread);
+    g_free (helper_bin_location);
+    free (env_string);
+
+    return NULL;
+  }
+
+  ret = GetExitCodeProcess (pi.hProcess, &exit_code);
+  CloseHandle (pi.hProcess);
+  CloseHandle (pi.hThread);
+
+  if (!ret || exit_code != 1) {
+    GST_WARNING ("Unexpected child process exit state, GetExitCodeProcess() "
+        "return: %d, exit code: %d", ret, (gint) exit_code);
+    g_free (helper_bin_location);
+    free (env_string);
+    return NULL;
+  }
+
+  self = g_new0 (GstPluginLoader, 1);
+  loader = (Win32PluginLoader *) self;
+
+  win32_plugin_loader_init (loader, FALSE);
+  self->env_string = env_string;
+  self->helper_bin = helper_bin_location;
+
+  loader->overlap.hEvent = CreateEventA (NULL, TRUE, TRUE, NULL);
+  self->pipe_prefix = g_strdup_printf ("\\\\.\\pipe\\gst.plugin.loader.%u",
+      (guint) GetCurrentProcessId ());
+
+  g_queue_init (&self->pending_plugins);
+  self->registry = gst_object_ref (registry);
+
+  ret = QueryPerformanceFrequency (&self->frequency);
+  /* Must not return zero */
+  g_assert (ret);
+
+  return self;
+}
+
+static void
+gst_plugin_loader_cleanup_child (GstPluginLoader * self)
+{
+  Win32PluginLoader *loader;
+  DWORD ret;
+
+  if (!self->client_running)
+    return;
+
+  loader = (Win32PluginLoader *) self;
+
+  if (loader->pipe != INVALID_HANDLE_VALUE) {
+    GST_LOG ("Disconnecting pipe");
+    DisconnectNamedPipe (loader->pipe);
+    CloseHandle (loader->pipe);
+    loader->pipe = INVALID_HANDLE_VALUE;
+  }
+
+  GST_LOG ("Waiting for child term");
+  ret = WaitForSingleObject (self->child_info.hProcess, 1000);
+  GST_LOG ("Wait return 0x%x", (guint) ret);
+
+  CloseHandle (self->child_info.hProcess);
+  CloseHandle (self->child_info.hThread);
+  memset (&self->child_info, 0, sizeof (PROCESS_INFORMATION));
+
+  self->client_running = FALSE;
+}
+
+static gboolean
+gst_plugin_loader_retry_pending (GstPluginLoader * self)
+{
+  if (g_queue_is_empty (&self->pending_plugins))
+    return TRUE;
+
+  if (!gst_plugin_loader_spawn (self))
+    return FALSE;
+
+  while (!g_queue_is_empty (&self->pending_plugins)) {
+    PendingPluginEntry *pending = g_queue_peek_head (&self->pending_plugins);
+
+    GST_LOG ("Retrying plugin %s", pending->filename);
+
+    if (!gst_plugin_loader_server_load (self, pending)) {
+      GST_ERROR ("Loading plugin %s failed", pending->filename);
+      gst_plugin_loader_create_blacklist (self, pending);
+      self->got_plugin_detail = TRUE;
+      pending_plugin_entry_free (pending);
+      g_queue_pop_head (&self->pending_plugins);
+      gst_plugin_loader_cleanup_child (self);
+
+      if (!gst_plugin_loader_spawn (self))
+        return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_plugin_loader_load (GstPluginLoader * self, const gchar * filename,
+    off_t file_size, time_t file_mtime)
+{
+  PendingPluginEntry *entry;
+
+  GST_LOG ("Loading new plugin");
+
+  if (!self || !filename)
+    return FALSE;
+
+  if (!gst_plugin_loader_spawn (self))
+    return FALSE;
+
+  /* Send a packet to the child requesting that it load the given file */
+  GST_LOG ("Sending file %s to child. tag %u", filename, self->seq_num);
+
+  entry = g_new0 (PendingPluginEntry, 1);
+  entry->filename = g_strdup (filename);
+  entry->file_size = file_size;
+  entry->file_mtime = file_mtime;
+  entry->seq_num = self->seq_num++;
+
+  g_queue_push_tail (&self->pending_plugins, entry);
+  if (!gst_plugin_loader_server_load (self, entry)) {
+    GST_WARNING ("Loading plugin %s failed", filename);
+    gst_plugin_loader_cleanup_child (self);
+
+    if (!gst_plugin_loader_retry_pending (self)) {
+      gst_plugin_loader_cleanup_child (self);
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_plugin_loader_free (GstPluginLoader * self)
+{
+  gboolean got_plugin_detail;
+  Win32PluginLoader *loader;
+
+  GST_LOG ("Freeing %p", self);
+
+  if (!self)
+    return FALSE;
+
+  loader = (Win32PluginLoader *) self;
+
+  gst_plugin_loader_retry_pending (self);
+  if (self->client_running) {
+    loader->expected_pkt = PACKET_EXIT;
+    GST_LOG ("Sending EXIT packet to client");
+
+    win32_plugin_loader_write_packet_async (loader, PACKET_EXIT, 0, NULL, 0);
+    win32_plugin_loader_run (loader, 10000);
+  }
+
+  gst_plugin_loader_cleanup_child (self);
+
+  got_plugin_detail = self->got_plugin_detail;
+  win32_plugin_loader_clear (loader);
+  g_free (self->pipe_prefix);
+  gst_clear_object (&self->registry);
+  g_queue_clear_full (&self->pending_plugins,
+      (GDestroyNotify) pending_plugin_entry_free);
+
+  free (self->env_string);
+  g_free (self->helper_bin);
+  g_free (self);
+
+  return got_plugin_detail;
+}
+
+static HANDLE
+gst_plugin_loader_client_create_file (LPCWSTR pipe_name)
+{
+#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
+  CREATEFILE2_EXTENDED_PARAMETERS params;
+  memset (&params, 0, sizeof (CREATEFILE2_EXTENDED_PARAMETERS));
+  params.dwSize = sizeof (CREATEFILE2_EXTENDED_PARAMETERS);
+  params.dwFileFlags = FILE_FLAG_OVERLAPPED;
+  params.dwSecurityQosFlags = SECURITY_IMPERSONATION;
+
+  return CreateFile2 (pipe_name,
+      GENERIC_READ | GENERIC_WRITE, 0, OPEN_EXISTING, &params);
+#else
+  return CreateFileW (pipe_name,
+      GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+      FILE_FLAG_OVERLAPPED, NULL);
+#endif
+}
+
+/* child process routine */
+gboolean
+_gst_plugin_loader_client_run (const gchar * pipe_name)
+{
+  gboolean ret = FALSE;
+  Win32PluginLoader loader;
+  DWORD pipe_mode = PIPE_READMODE_MESSAGE;
+  gchar *err = NULL;
+  LPWSTR pipe_name_wide;
+
+  pipe_name_wide = (LPWSTR) g_utf8_to_utf16 (pipe_name, -1, NULL, NULL, NULL);
+  if (!pipe_name_wide) {
+    GST_ERROR ("Couldn't convert %s to wide string", pipe_name);
+    return FALSE;
+  }
+
+  win32_plugin_loader_init (&loader, TRUE);
+
+  GST_DEBUG ("Connecting pipe %s", pipe_name);
+
+  /* Connect to server's named pipe */
+  loader.pipe = gst_plugin_loader_client_create_file (pipe_name_wide);
+  loader.last_err = GetLastError ();
+  if (loader.pipe == INVALID_HANDLE_VALUE) {
+    /* Server should be pending (waiting for connection) state already,
+     * but do retry if it's not the case */
+    if (loader.last_err == ERROR_PIPE_BUSY) {
+      if (WaitNamedPipeW (pipe_name_wide, 5000))
+        loader.pipe = gst_plugin_loader_client_create_file (pipe_name_wide);
+
+      loader.last_err = GetLastError ();
+    }
+
+    if (loader.pipe == INVALID_HANDLE_VALUE) {
+      err = g_win32_error_message (loader.last_err);
+      GST_ERROR ("CreateFileA failed with 0x%x (%s)",
+          loader.last_err, GST_STR_NULL (err));
+      goto out;
+    }
+  }
+
+  /* We use message mode */
+  if (!SetNamedPipeHandleState (loader.pipe, &pipe_mode, NULL, NULL)) {
+    loader.last_err = GetLastError ();
+    err = g_win32_error_message (loader.last_err);
+    GST_ERROR ("SetNamedPipeHandleState failed with 0x%x (%s)",
+        loader.last_err, err);
+    goto out;
+  }
+
+  GST_DEBUG ("Plugin scanner child running. Waiting for instructions");
+  /* version packet should be the first packet */
+  loader.expected_pkt = PACKET_VERSION;
+
+  /* Setup initial read callback */
+  win32_plugin_loader_read_header_async (&loader);
+  if (loader.last_err != ERROR_SUCCESS)
+    goto out;
+
+  ret = win32_plugin_loader_run (&loader, 60000);
+
+out:
+  g_free (err);
+  g_free (pipe_name_wide);
+  win32_plugin_loader_clear (&loader);
+
+  return ret;
+}
diff --git a/gst/gstpluginloader.c b/gst/gstpluginloader.c
index 8dc96fd..8374ba7 100644
--- a/gst/gstpluginloader.c
+++ b/gst/gstpluginloader.c
@@ -26,21 +26,11 @@
 
 #include <gst/gst_private.h>
 
-#ifndef G_OS_WIN32
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
-#else
-#define WIN32_LEAN_AND_MEAN
-
-#define fsync(fd) _commit(fd)
-#include <io.h>
-
-#include <windows.h>
-extern HMODULE _priv_gst_dll_handle;
-#endif
 
 #ifdef HAVE_SYS_UTSNAME_H
 #include <sys/utsname.h>
@@ -147,7 +137,7 @@ static gboolean plugin_loader_sync_with_child (GstPluginLoader * l);
 static GstPluginLoader *
 plugin_loader_new (GstRegistry * registry)
 {
-  GstPluginLoader *l = g_slice_new0 (GstPluginLoader);
+  GstPluginLoader *l = g_new0 (GstPluginLoader, 1);
 
   if (registry)
     l->registry = gst_object_ref (registry);
@@ -211,12 +201,12 @@ plugin_loader_free (GstPluginLoader * loader)
   while (cur) {
     PendingPluginEntry *entry = (PendingPluginEntry *) (cur->data);
     g_free (entry->filename);
-    g_slice_free (PendingPluginEntry, entry);
+    g_free (entry);
 
     cur = g_list_delete_link (cur, cur);
   }
 
-  g_slice_free (GstPluginLoader, loader);
+  g_free (loader);
 
   return got_plugin_details;
 }
@@ -235,7 +225,7 @@ plugin_loader_load (GstPluginLoader * loader, const gchar * filename,
   GST_LOG_OBJECT (loader->registry,
       "Sending file %s to child. tag %u", filename, loader->next_tag);
 
-  entry = g_slice_new (PendingPluginEntry);
+  entry = g_new (PendingPluginEntry, 1);
   entry->tag = loader->next_tag++;
   entry->filename = g_strdup (filename);
   entry->file_size = file_size;
@@ -283,7 +273,7 @@ restart:
       /* Now remove this crashy plugin from the head of the list */
       l->pending_plugins = g_list_delete_link (cur, cur);
       g_free (entry->filename);
-      g_slice_free (PendingPluginEntry, entry);
+      g_free (entry);
       if (l->pending_plugins == NULL)
         l->pending_plugins_tail = NULL;
       if (!gst_plugin_loader_spawn (l))
@@ -460,83 +450,6 @@ gst_plugin_loader_try_helper (GstPluginLoader * loader, gchar * location)
   return TRUE;
 }
 
-static int
-count_directories (const char *filepath)
-{
-  int i = 0;
-  char *tmp;
-  gsize len;
-
-  g_return_val_if_fail (!g_path_is_absolute (filepath), 0);
-
-  tmp = g_strdup (filepath);
-  len = strlen (tmp);
-
-#if defined(G_OS_WIN32)
-  /* ignore UNC share paths entirely */
-  if (len >= 3 && G_IS_DIR_SEPARATOR (tmp[0]) && G_IS_DIR_SEPARATOR (tmp[1])
-      && !G_IS_DIR_SEPARATOR (tmp[2])) {
-    GST_WARNING ("found a UNC share path, ignoring");
-    return 0;
-  }
-#endif
-
-  /* remove trailing slashes if they exist */
-  while (
-#if defined(G_OS_WIN32)
-      /* don't remove the trailing slash for C:\.
-       * UNC paths are at least \\s\s */
-      len > 3
-#else
-      /* don't remove the trailing slash for / */
-      len > 1
-#endif
-      && G_IS_DIR_SEPARATOR (tmp[len - 1])) {
-    tmp[len - 1] = '\0';
-    len--;
-  }
-
-  while (tmp) {
-    char *dirname, *basename;
-    len = strlen (tmp);
-
-    if (g_strcmp0 (tmp, ".") == 0)
-      break;
-    if (g_strcmp0 (tmp, "/") == 0)
-      break;
-#if defined(G_OS_WIN32)
-    /* g_path_get_dirname() may return something of the form 'C:.', where C is
-     * a drive letter */
-    if (len == 3 && g_ascii_isalpha (tmp[0]) && tmp[1] == ':' && tmp[2] == '.')
-      break;
-#endif
-
-    basename = g_path_get_basename (tmp);
-    dirname = g_path_get_dirname (tmp);
-
-    if (g_strcmp0 (basename, "..") == 0) {
-      i--;
-    } else if (g_strcmp0 (basename, ".") == 0) {
-      /* nothing to do */
-    } else {
-      i++;
-    }
-
-    g_clear_pointer (&basename, g_free);
-    g_clear_pointer (&tmp, g_free);
-    tmp = dirname;
-  }
-
-  g_clear_pointer (&tmp, g_free);
-
-  if (i < 0) {
-    g_critical ("path counting resulted in a negative directory count!");
-    return 0;
-  }
-
-  return i;
-}
-
 static gboolean
 gst_plugin_loader_spawn (GstPluginLoader * loader)
 {
@@ -564,17 +477,11 @@ gst_plugin_loader_spawn (GstPluginLoader * loader)
     /* use the installed version */
     GST_LOG ("Trying installed plugin scanner");
 
-#ifdef G_OS_WIN32
-#define EXESUFFIX ".exe"
-#else
-#define EXESUFFIX
-#endif
-
 #define MAX_PATH_DEPTH 64
 
     relocated_libgstreamer = priv_gst_get_relocated_libgstreamer ();
     if (relocated_libgstreamer) {
-      int plugin_subdir_depth = count_directories (GST_PLUGIN_SUBDIR);
+      int plugin_subdir_depth = priv_gst_count_directories (GST_PLUGIN_SUBDIR);
 
       GST_DEBUG ("found libgstreamer-" GST_API_VERSION " library "
           "at %s", relocated_libgstreamer);
@@ -588,7 +495,7 @@ gst_plugin_loader_spawn (GstPluginLoader * loader)
           filenamev[i++] = "..";
         filenamev[i++] = GST_PLUGIN_SCANNER_SUBDIR;
         filenamev[i++] = "gstreamer-" GST_API_VERSION;
-        filenamev[i++] = "gst-plugin-scanner" EXESUFFIX;
+        filenamev[i++] = "gst-plugin-scanner";
         filenamev[i++] = NULL;
         g_assert (i <= MAX_PATH_DEPTH + 5);
 
@@ -606,6 +513,8 @@ gst_plugin_loader_spawn (GstPluginLoader * loader)
       helper_bin = g_strdup (GST_PLUGIN_SCANNER_INSTALLED);
     }
 
+#undef MAX_PATH_DEPTH
+
     GST_DEBUG ("using system plugin scanner at %s", helper_bin);
 
     res = gst_plugin_loader_try_helper (loader, helper_bin);
@@ -632,22 +541,19 @@ plugin_loader_cleanup_child (GstPluginLoader * l)
   close (l->fd_w.fd);
   close (l->fd_r.fd);
 
-#ifndef G_OS_WIN32
   GST_LOG ("waiting for child process to exit");
   waitpid (l->child_pid, NULL, 0);
-#else
-  g_warning ("FIXME: Implement child process shutdown for Win32");
-#endif
   g_spawn_close_pid (l->child_pid);
 
   l->child_running = FALSE;
 }
 
 gboolean
-_gst_plugin_loader_client_run (void)
+_gst_plugin_loader_client_run (const gchar * pipe_name)
 {
   gboolean res = TRUE;
   GstPluginLoader *l;
+  int dup_fd;
 
   l = plugin_loader_new (NULL);
   if (l == NULL)
@@ -656,37 +562,27 @@ _gst_plugin_loader_client_run (void)
   /* On entry, the inward pipe is STDIN, and outward is STDOUT.
    * Dup those somewhere better so that plugins printing things
    * won't interfere with anything */
-#ifndef G_OS_WIN32
-  {
-    int dup_fd;
-
-    dup_fd = dup (0);           /* STDIN */
-    if (dup_fd == -1) {
-      GST_ERROR ("Failed to start. Could not dup STDIN, errno %d", errno);
-      res = FALSE;
-      goto beach;
-    }
-    l->fd_r.fd = dup_fd;
-    close (0);
-
-    dup_fd = dup (1);           /* STDOUT */
-    if (dup_fd == -1) {
-      GST_ERROR ("Failed to start. Could not dup STDOUT, errno %d", errno);
-      res = FALSE;
-      goto beach;
-    }
-    l->fd_w.fd = dup_fd;
-    close (1);
-
-    /* Dup stderr down to stdout so things that plugins print are visible,
-     * but don't care if it fails */
-    dup2 (2, 1);
+  dup_fd = dup (0);             /* STDIN */
+  if (dup_fd == -1) {
+    GST_ERROR ("Failed to start. Could not dup STDIN, errno %d", errno);
+    res = FALSE;
+    goto beach;
   }
-#else
-  /* FIXME: Use DuplicateHandle and friends on win32 */
-  l->fd_w.fd = 1;               /* STDOUT */
-  l->fd_r.fd = 0;               /* STDIN */
-#endif
+  l->fd_r.fd = dup_fd;
+  close (0);
+
+  dup_fd = dup (1);             /* STDOUT */
+  if (dup_fd == -1) {
+    GST_ERROR ("Failed to start. Could not dup STDOUT, errno %d", errno);
+    res = FALSE;
+    goto beach;
+  }
+  l->fd_w.fd = dup_fd;
+  close (1);
+
+  /* Dup stderr down to stdout so things that plugins print are visible,
+   * but don't care if it fails */
+  dup2 (2, 1);
 
   gst_poll_add_fd (l->fdset, &l->fd_w);
   gst_poll_add_fd (l->fdset, &l->fd_r);
@@ -699,10 +595,7 @@ _gst_plugin_loader_client_run (void)
   /* Loop, listening for incoming packets on the fd and writing responses */
   while (!l->rx_done && exchange_packets (l));
 
-#ifndef G_OS_WIN32
 beach:
-#endif
-
   plugin_loader_free (l);
 
   return res;
@@ -982,7 +875,7 @@ handle_rx_packet (GstPluginLoader * l,
         } else {
           cur = g_list_delete_link (cur, cur);
           g_free (e->filename);
-          g_slice_free (PendingPluginEntry, e);
+          g_free (e);
         }
       }
 
@@ -1016,7 +909,7 @@ handle_rx_packet (GstPluginLoader * l,
 
       if (entry != NULL) {
         g_free (entry->filename);
-        g_slice_free (PendingPluginEntry, entry);
+        g_free (entry);
       }
 
       /* Remove the plugin entry we just loaded */
diff --git a/gst/gstpoll.c b/gst/gstpoll.c
index f5f10bc..b6e72a9 100644
--- a/gst/gstpoll.c
+++ b/gst/gstpoll.c
@@ -677,7 +677,7 @@ gst_poll_new (gboolean controllable)
 {
   GstPoll *nset;
 
-  nset = g_slice_new0 (GstPoll);
+  nset = g_new0 (GstPoll, 1);
   GST_DEBUG ("%p: new controllable : %d", nset, controllable);
   g_mutex_init (&nset->lock);
 #ifndef G_OS_WIN32
@@ -794,7 +794,7 @@ gst_poll_free (GstPoll * set)
   g_array_free (set->active_fds, TRUE);
   g_array_free (set->fds, TRUE);
   g_mutex_clear (&set->lock);
-  g_slice_free (GstPoll, set);
+  g_free (set);
 }
 
 /**
diff --git a/gst/gstpromise.c b/gst/gstpromise.c
index 322d603..6e0e3eb 100644
--- a/gst/gstpromise.c
+++ b/gst/gstpromise.c
@@ -174,10 +174,9 @@ gst_promise_reply (GstPromise * promise, GstStructure * s)
   g_mutex_lock (GST_PROMISE_LOCK (promise));
   if (GST_PROMISE_RESULT (promise) != GST_PROMISE_RESULT_PENDING &&
       GST_PROMISE_RESULT (promise) != GST_PROMISE_RESULT_INTERRUPTED) {
-    GstPromiseResult result = GST_PROMISE_RESULT (promise);
+    g_warning ("Promise result isn't PENDING or INTERRUPTED");
     g_mutex_unlock (GST_PROMISE_LOCK (promise));
-    g_return_if_fail (result == GST_PROMISE_RESULT_PENDING ||
-        result == GST_PROMISE_RESULT_INTERRUPTED);
+    return;
   }
 
   /* XXX: is this necessary and valid? */
@@ -232,9 +231,9 @@ gst_promise_get_reply (GstPromise * promise)
 
   g_mutex_lock (GST_PROMISE_LOCK (promise));
   if (GST_PROMISE_RESULT (promise) != GST_PROMISE_RESULT_REPLIED) {
-    GstPromiseResult result = GST_PROMISE_RESULT (promise);
+    g_warning ("Promise result isn't REPLIED");
     g_mutex_unlock (GST_PROMISE_LOCK (promise));
-    g_return_val_if_fail (result == GST_PROMISE_RESULT_REPLIED, NULL);
+    return NULL;
   }
 
   g_mutex_unlock (GST_PROMISE_LOCK (promise));
@@ -263,10 +262,9 @@ gst_promise_interrupt (GstPromise * promise)
   g_mutex_lock (GST_PROMISE_LOCK (promise));
   if (GST_PROMISE_RESULT (promise) != GST_PROMISE_RESULT_PENDING &&
       GST_PROMISE_RESULT (promise) != GST_PROMISE_RESULT_REPLIED) {
-    GstPromiseResult result = GST_PROMISE_RESULT (promise);
+    g_warning ("Promise result isn't PENDING or REPLIED");
     g_mutex_unlock (GST_PROMISE_LOCK (promise));
-    g_return_if_fail (result == GST_PROMISE_RESULT_PENDING ||
-        result == GST_PROMISE_RESULT_REPLIED);
+    return;
   }
   /* only interrupt if we are currently in pending */
   if (GST_PROMISE_RESULT (promise) == GST_PROMISE_RESULT_PENDING) {
@@ -440,3 +438,22 @@ gst_promise_unref (GstPromise * promise)
 {
   gst_mini_object_unref (GST_MINI_OBJECT_CAST (promise));
 }
+
+/**
+ * gst_clear_promise: (skip)
+ * @promise_ptr: a pointer to a #GstPromise reference
+ *
+ * Clears a reference to a #GstPromise.
+ *
+ * @promise_ptr must not be `NULL`.
+ *
+ * If the reference is `NULL` then this function does nothing. Otherwise, the
+ * reference count of the promise is decreased and the pointer is set to `NULL`.
+ *
+ * Since: 1.24
+ */
+void
+gst_clear_promise (GstPromise ** promise_ptr)
+{
+  gst_clear_mini_object ((GstMiniObject **) promise_ptr);
+}
diff --git a/gst/gstpromise.h b/gst/gstpromise.h
index b9ea6ba..b205adc 100644
--- a/gst/gstpromise.h
+++ b/gst/gstpromise.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 GST_API
 GType gst_promise_get_type(void);
 #define GST_TYPE_PROMISE            (gst_promise_get_type())
+#define GST_IS_PROMISE(obj)         (GST_IS_MINI_OBJECT_TYPE (obj, GST_TYPE_PROMISE))
 #define GST_PROMISE(obj)            ((GstPromise *) obj)
 
 typedef struct _GstPromise GstPromise;
@@ -105,12 +106,21 @@ gst_promise_unref (GstPromise * promise)
 {
   gst_mini_object_unref (GST_MINI_OBJECT_CAST (promise));
 }
+
+static inline void
+gst_clear_promise (GstPromise ** promise_ptr)
+{
+  gst_clear_mini_object ((GstMiniObject **) promise_ptr);
+}
 #else /* GST_DISABLE_MINIOBJECT_INLINE_FUNCTIONS */
 GST_API
 GstPromise *  gst_promise_ref (GstPromise * promise);
 
 GST_API
 void          gst_promise_unref (GstPromise * promise);
+
+GST_API
+void          gst_clear_promise (GstPromise ** promise_ptr);
 #endif /* GST_DISABLE_MINIOBJECT_INLINE_FUNCTIONS */
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstPromise, gst_promise_unref)
diff --git a/gst/gstprotection.c b/gst/gstprotection.c
index 73deed8..f174da6 100644
--- a/gst/gstprotection.c
+++ b/gst/gstprotection.c
@@ -35,6 +35,15 @@
  * used by a downstream decrypter element to recover the original unencrypted
  * frame.
  *
+ * In addition to the #GstProtectionMeta demuxers signal encrypted streams with
+ * specific caps. The caps #GstStructure name will usually depend on the
+ * encryption scheme, for instance Common Encryption will be signaled with
+ * `application/x-cenc`. To prevent loss of information the media type of the
+ * decrypted stream will be stored in a `original-media-type` string field.
+ * Downstream elements can re-use that information, for instance decryptors can
+ * set their source pad caps according to the `original-media-type` received on
+ * their sink pad.
+ *
  * Since: 1.6
  */
 
diff --git a/gst/gstquery.c b/gst/gstquery.c
index 106c450..3c2490f 100644
--- a/gst/gstquery.c
+++ b/gst/gstquery.c
@@ -106,6 +106,7 @@ static GstQueryQuarks query_quarks[] = {
   {GST_QUERY_DRAIN, "drain", 0},
   {GST_QUERY_CONTEXT, "context", 0},
   {GST_QUERY_BITRATE, "bitrate", 0},
+  {GST_QUERY_SELECTABLE, "selectable", 0},
 
   {0, NULL, 0}
 };
@@ -200,7 +201,7 @@ _gst_query_free (GstQuery * query)
   memset (query, 0xff, sizeof (GstQueryImpl));
 #endif
 
-  g_slice_free1 (sizeof (GstQueryImpl), query);
+  g_free (query);
 }
 
 static GstQuery *
@@ -674,7 +675,7 @@ gst_query_new_custom (GstQueryType type, GstStructure * structure)
 {
   GstQueryImpl *query;
 
-  query = g_slice_new0 (GstQueryImpl);
+  query = g_new0 (GstQueryImpl, 1);
 
   GST_DEBUG ("creating new query %p %s", query, gst_query_type_get_name (type));
 
@@ -697,7 +698,7 @@ gst_query_new_custom (GstQueryType type, GstStructure * structure)
   /* ERRORS */
 had_parent:
   {
-    g_slice_free1 (sizeof (GstQueryImpl), query);
+    g_free (query);
     g_warning ("structure is already owned by another object");
     return NULL;
   }
diff --git a/gst/gstregistry.c b/gst/gstregistry.c
index 34f4529..2226d18 100644
--- a/gst/gstregistry.c
+++ b/gst/gstregistry.c
@@ -1154,12 +1154,6 @@ gst_registry_scan_plugin_file (GstRegistryScanContext * context,
   gboolean changed = FALSE;
   GstPlugin *newplugin = NULL;
 
-#ifdef G_OS_WIN32
-  /* Disable external plugin loader on Windows until it is ported properly. */
-  context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
-#endif
-
-
   /* Have a plugin to load - see if the scan-helper needs starting */
   if (context->helper_state == REGISTRY_SCAN_HELPER_NOT_STARTED) {
     GST_DEBUG ("Starting plugin scanner for file %s", filename);
@@ -1605,6 +1599,8 @@ priv_gst_get_relocated_libgstreamer (void)
 #elif defined(HAVE_DLADDR)
   {
     Dl_info info;
+    char *real_fname = NULL;
+    long path_max = 0;
 
     GST_DEBUG ("attempting to retrieve libgstreamer-1.0 location using "
         "dladdr()");
@@ -1615,8 +1611,25 @@ priv_gst_get_relocated_libgstreamer (void)
       if (!info.dli_fname) {
         return NULL;
       }
+#ifdef PATH_MAX
+      path_max = PATH_MAX;
+#else
+      path_max = pathconf (info.dli_fname, _PC_PATH_MAX);
+      if (path_max <= 0)
+        path_max = 4096;
+#endif
+
+      real_fname = g_malloc (path_max);
+      if (realpath (info.dli_fname, real_fname)) {
+        dir = g_path_get_dirname (real_fname);
+        GST_DEBUG ("real directory location: %s", dir);
+      } else {
+        GST_ERROR ("could not canonicalize path %s: %s", info.dli_fname,
+            g_strerror (errno));
+        dir = g_path_get_dirname (info.dli_fname);
+      }
+      g_free (real_fname);
 
-      dir = g_path_get_dirname (info.dli_fname);
     } else {
       GST_LOG ("dladdr() failed");
       return NULL;
@@ -1632,6 +1645,75 @@ priv_gst_get_relocated_libgstreamer (void)
   return dir;
 }
 
+int
+priv_gst_count_directories (const char *filepath)
+{
+  int i = 0;
+  char *tmp;
+  gsize len;
+
+  g_return_val_if_fail (!g_path_is_absolute (filepath), 0);
+
+  tmp = g_strdup (filepath);
+  len = strlen (tmp);
+
+  /* ignore UNC share paths entirely */
+  if (len >= 3 && G_IS_DIR_SEPARATOR (tmp[0]) && G_IS_DIR_SEPARATOR (tmp[1])
+      && !G_IS_DIR_SEPARATOR (tmp[2])) {
+    GST_WARNING ("found a UNC share path, ignoring");
+    g_clear_pointer (&tmp, g_free);
+    return 0;
+  }
+
+  /* remove trailing slashes if they exist */
+  while (
+      /* don't remove the trailing slash for C:\.
+       * UNC paths are at least \\s\s */
+      len > 3 && G_IS_DIR_SEPARATOR (tmp[len - 1])) {
+    tmp[len - 1] = '\0';
+    len--;
+  }
+
+  while (tmp) {
+    char *dirname, *basename;
+    len = strlen (tmp);
+
+    if (g_strcmp0 (tmp, ".") == 0)
+      break;
+    if (g_strcmp0 (tmp, "/") == 0)
+      break;
+
+    /* g_path_get_dirname() may return something of the form 'C:.', where C is
+     * a drive letter */
+    if (len == 3 && g_ascii_isalpha (tmp[0]) && tmp[1] == ':' && tmp[2] == '.')
+      break;
+
+    basename = g_path_get_basename (tmp);
+    dirname = g_path_get_dirname (tmp);
+
+    if (g_strcmp0 (basename, "..") == 0) {
+      i--;
+    } else if (g_strcmp0 (basename, ".") == 0) {
+      /* nothing to do */
+    } else {
+      i++;
+    }
+
+    g_clear_pointer (&basename, g_free);
+    g_clear_pointer (&tmp, g_free);
+    tmp = dirname;
+  }
+
+  g_clear_pointer (&tmp, g_free);
+
+  if (i < 0) {
+    g_critical ("path counting resulted in a negative directory count!");
+    return 0;
+  }
+
+  return i;
+}
+
 #ifndef GST_DISABLE_REGISTRY
 /* Unref all plugins marked 'cached', to clear old plugins that no
  * longer exist. Returns %TRUE if any plugins were removed */
diff --git a/gst/gstregistrybinary.c b/gst/gstregistrybinary.c
index 1e86464..e672716 100644
--- a/gst/gstregistrybinary.c
+++ b/gst/gstregistrybinary.c
@@ -103,7 +103,7 @@ typedef struct BinaryRegistryCache
 static BinaryRegistryCache *
 gst_registry_binary_cache_init (GstRegistry * registry, const char *location)
 {
-  BinaryRegistryCache *cache = g_slice_new0 (BinaryRegistryCache);
+  BinaryRegistryCache *cache = g_new0 (BinaryRegistryCache, 1);
   cache->location = location;
   return cache;
 }
@@ -157,7 +157,7 @@ gst_registry_binary_cache_finish (BinaryRegistryCache * cache, gboolean success)
   }
 
   g_free (cache->mem);
-  g_slice_free (BinaryRegistryCache, cache);
+  g_free (cache);
   return ret;
 }
 
@@ -173,7 +173,7 @@ typedef struct BinaryRegistryCache
 static BinaryRegistryCache *
 gst_registry_binary_cache_init (GstRegistry * registry, const char *location)
 {
-  BinaryRegistryCache *cache = g_slice_new0 (BinaryRegistryCache);
+  BinaryRegistryCache *cache = g_new0 (BinaryRegistryCache, 1);
   int fd;
 
   cache->location = location;
@@ -203,7 +203,7 @@ gst_registry_binary_cache_init (GstRegistry * registry, const char *location)
     if (fd == -1) {
       GST_DEBUG ("g_mkstemp() failed: %s", g_strerror (errno));
       g_free (cache->tmp_location);
-      g_slice_free (BinaryRegistryCache, cache);
+      g_free (cache);
       return NULL;
     }
 
@@ -218,7 +218,7 @@ gst_registry_binary_cache_init (GstRegistry * registry, const char *location)
     GST_DEBUG ("fdopen() failed: %s", g_strerror (errno));
     close (fd);
     g_free (cache->tmp_location);
-    g_slice_free (BinaryRegistryCache, cache);
+    g_free (cache);
     return NULL;
   }
 
@@ -310,7 +310,7 @@ gst_registry_binary_cache_finish (BinaryRegistryCache * cache, gboolean success)
   }
 
   g_free (cache->tmp_location);
-  g_slice_free (BinaryRegistryCache, cache);
+  g_free (cache);
   GST_INFO ("Wrote binary registry cache");
   return TRUE;
 
@@ -324,7 +324,7 @@ fail_after_fclose:
   {
     g_unlink (cache->tmp_location);
     g_free (cache->tmp_location);
-    g_slice_free (BinaryRegistryCache, cache);
+    g_free (cache);
     return FALSE;
   }
 fflush_failed:
diff --git a/gst/gstregistrybinary.h b/gst/gstregistrybinary.h
index 22e56d1..6bf712c 100644
--- a/gst/gstregistrybinary.h
+++ b/gst/gstregistrybinary.h
@@ -55,7 +55,7 @@ G_BEGIN_DECLS
  * This _must_ be updated whenever the registry format changes,
  * we currently use the core version where this change happened.
  */
-#define GST_MAGIC_BINARY_VERSION_STR "1.3.0"
+#define GST_MAGIC_BINARY_VERSION_STR "1.23.90"
 
 /*
  * GST_MAGIC_BINARY_VERSION_LEN:
diff --git a/gst/gstregistrychunks.c b/gst/gstregistrychunks.c
index 80d0d4f..7c1aa96 100644
--- a/gst/gstregistrychunks.c
+++ b/gst/gstregistrychunks.c
@@ -116,12 +116,9 @@ void
 _priv_gst_registry_chunk_free (GstRegistryChunk * chunk)
 {
   if (!(chunk->flags & GST_REGISTRY_CHUNK_FLAG_CONST)) {
-    if ((chunk->flags & GST_REGISTRY_CHUNK_FLAG_MALLOC))
-      g_free (chunk->data);
-    else
-      g_slice_free1 (chunk->size, chunk->data);
+    g_free (chunk->data);
   }
-  g_slice_free (GstRegistryChunk, chunk);
+  g_free (chunk);
 }
 
 /*
@@ -141,7 +138,7 @@ gst_registry_chunks_save_const_string (GList ** list, const gchar * str)
     str = "";
   }
 
-  chunk = g_slice_new (GstRegistryChunk);
+  chunk = g_new (GstRegistryChunk, 1);
   chunk->data = (gpointer) str;
   chunk->size = strlen ((gchar *) chunk->data) + 1;
   chunk->flags = GST_REGISTRY_CHUNK_FLAG_CONST;
@@ -162,10 +159,10 @@ gst_registry_chunks_save_string (GList ** list, gchar * str)
 {
   GstRegistryChunk *chunk;
 
-  chunk = g_slice_new (GstRegistryChunk);
+  chunk = g_new (GstRegistryChunk, 1);
   chunk->data = str;
   chunk->size = strlen ((gchar *) chunk->data) + 1;
-  chunk->flags = GST_REGISTRY_CHUNK_FLAG_MALLOC;
+  chunk->flags = GST_REGISTRY_CHUNK_FLAG_NONE;
   chunk->align = FALSE;
   *list = g_list_prepend (*list, chunk);
   return TRUE;
@@ -183,7 +180,7 @@ gst_registry_chunks_make_data (gpointer data, gulong size)
 {
   GstRegistryChunk *chunk;
 
-  chunk = g_slice_new (GstRegistryChunk);
+  chunk = g_new (GstRegistryChunk, 1);
   chunk->data = data;
   chunk->size = size;
   chunk->flags = GST_REGISTRY_CHUNK_FLAG_NONE;
@@ -206,7 +203,7 @@ gst_registry_chunks_save_pad_template (GList ** list,
   GstRegistryChunkPadTemplate *pt;
   GstRegistryChunk *chk;
 
-  pt = g_slice_new (GstRegistryChunkPadTemplate);
+  pt = g_new (GstRegistryChunkPadTemplate, 1);
   chk =
       gst_registry_chunks_make_data (pt, sizeof (GstRegistryChunkPadTemplate));
 
@@ -251,7 +248,7 @@ gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
     /* Initialize with zeroes because of struct padding and
      * valgrind complaining about copying uninitialized memory
      */
-    ef = g_slice_new0 (GstRegistryChunkElementFactory);
+    ef = g_new0 (GstRegistryChunkElementFactory, 1);
     pf_size = sizeof (GstRegistryChunkElementFactory);
     chk = gst_registry_chunks_make_data (ef, pf_size);
     ef->npadtemplates = ef->ninterfaces = ef->nuriprotocols = 0;
@@ -311,7 +308,7 @@ gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
     /* Initialize with zeroes because of struct padding and
      * valgrind complaining about copying uninitialized memory
      */
-    tff = g_slice_new0 (GstRegistryChunkTypeFindFactory);
+    tff = g_new0 (GstRegistryChunkTypeFindFactory, 1);
     pf_size = sizeof (GstRegistryChunkTypeFindFactory);
     chk = gst_registry_chunks_make_data (tff, pf_size);
     tff->nextensions = 0;
@@ -345,7 +342,7 @@ gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
     /* Initialize with zeroes because of struct padding and
      * valgrind complaining about copying uninitialized memory
      */
-    tff = g_slice_new0 (GstRegistryChunkDeviceProviderFactory);
+    tff = g_new0 (GstRegistryChunkDeviceProviderFactory, 1);
     chk =
         gst_registry_chunks_make_data (tff,
         sizeof (GstRegistryChunkDeviceProviderFactory));
@@ -359,13 +356,13 @@ gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
     /* Initialize with zeroes because of struct padding and
      * valgrind complaining about copying uninitialized memory
      */
-    pf = g_slice_new0 (GstRegistryChunkPluginFeature);
+    pf = g_new0 (GstRegistryChunkPluginFeature, 1);
     pf_size = sizeof (GstRegistryChunkPluginFeature);
     chk = gst_registry_chunks_make_data (pf, pf_size);
   } else if (GST_IS_DYNAMIC_TYPE_FACTORY (feature)) {
     GstRegistryChunkDynamicTypeFactory *tmp;
 
-    tmp = g_slice_new0 (GstRegistryChunkDynamicTypeFactory);
+    tmp = g_new0 (GstRegistryChunkDynamicTypeFactory, 1);
     chk =
         gst_registry_chunks_make_data (tmp,
         sizeof (GstRegistryChunkDynamicTypeFactory));
@@ -387,8 +384,8 @@ gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
 
   /* Errors */
 fail:
-  g_slice_free (GstRegistryChunk, chk);
-  g_slice_free1 (pf_size, pf);
+  g_free (chk);
+  g_free (pf);
   return FALSE;
 }
 
@@ -399,7 +396,7 @@ gst_registry_chunks_save_plugin_dep (GList ** list, GstPluginDep * dep)
   GstRegistryChunk *chk;
   gchar **s;
 
-  ed = g_slice_new (GstRegistryChunkDep);
+  ed = g_new (GstRegistryChunkDep, 1);
   chk = gst_registry_chunks_make_data (ed, sizeof (GstRegistryChunkDep));
 
   ed->flags = dep->flags;
@@ -441,7 +438,7 @@ _priv_gst_registry_chunks_save_plugin (GList ** list, GstRegistry * registry,
   GList *plugin_features = NULL;
   GList *walk;
 
-  pe = g_slice_new (GstRegistryChunkPluginElement);
+  pe = g_new (GstRegistryChunkPluginElement, 1);
   chk =
       gst_registry_chunks_make_data (pe,
       sizeof (GstRegistryChunkPluginElement));
@@ -481,6 +478,14 @@ _priv_gst_registry_chunks_save_plugin (GList ** list, GstRegistry * registry,
     gst_registry_chunks_save_const_string (list, "");
   }
 
+  /* pack status info */
+  if (plugin->priv->status_info) {
+    gchar *status_str = gst_structure_to_string (plugin->priv->status_info);
+    gst_registry_chunks_save_string (list, status_str);
+  } else {
+    gst_registry_chunks_save_const_string (list, "");
+  }
+
   /* pack plugin element strings */
   gst_registry_chunks_save_const_string (list,
       (plugin->desc.release_datetime) ? plugin->desc.release_datetime : "");
@@ -502,8 +507,8 @@ _priv_gst_registry_chunks_save_plugin (GList ** list, GstRegistry * registry,
   /* Errors */
 fail:
   gst_plugin_feature_list_free (plugin_features);
-  g_slice_free (GstRegistryChunk, chk);
-  g_slice_free (GstRegistryChunkPluginElement, pe);
+  g_free (chk);
+  g_free (pe);
   return FALSE;
 }
 
@@ -527,7 +532,7 @@ gst_registry_chunks_load_pad_template (GstElementFactory * factory, gchar ** in,
       *in);
   unpack_element (*in, pt, GstRegistryChunkPadTemplate, end, fail);
 
-  template = g_slice_new (GstStaticPadTemplate);
+  template = g_new (GstStaticPadTemplate, 1);
   template->presence = pt->presence;
   template->direction = (GstPadDirection) pt->direction;
   template->static_caps.caps = NULL;
@@ -543,7 +548,7 @@ gst_registry_chunks_load_pad_template (GstElementFactory * factory, gchar ** in,
 fail:
   GST_INFO ("Reading pad template failed");
   if (template)
-    g_slice_free (GstStaticPadTemplate, template);
+    g_free (template);
   return FALSE;
 }
 
@@ -784,7 +789,7 @@ gst_registry_chunks_load_plugin_dep (GstPlugin * plugin, gchar ** in,
   GST_LOG_OBJECT (plugin, "Unpacking GstRegistryChunkDep from %p", *in);
   unpack_element (*in, d, GstRegistryChunkDep, end, fail);
 
-  dep = g_slice_new (GstPluginDep);
+  dep = g_new (GstPluginDep, 1);
 
   dep->env_hash = d->env_hash;
   dep->stat_hash = d->stat_hash;
@@ -829,6 +834,7 @@ _priv_gst_registry_chunks_load_plugin (GstRegistry * registry, gchar ** in,
   gchar *start = *in;
 #endif
   GstRegistryChunkPluginElement *pe;
+  const gchar *status_str = NULL;
   const gchar *cache_str = NULL;
   GstPlugin *plugin = NULL;
   guint i, n;
@@ -869,6 +875,11 @@ _priv_gst_registry_chunks_load_plugin (GstRegistry * registry, gchar ** in,
   if (plugin->desc.release_datetime[0] == '\0')
     plugin->desc.release_datetime = NULL;
 
+  /* unpack status info */
+  unpack_string_nocopy (*in, status_str, end, fail);
+  if (status_str != NULL && *status_str != '\0')
+    plugin->priv->status_info = gst_structure_from_string (status_str, NULL);
+
   /* unpack cache data */
   unpack_string_nocopy (*in, cache_str, end, fail);
   if (cache_str != NULL && *cache_str != '\0')
@@ -926,7 +937,7 @@ _priv_gst_registry_chunks_save_global_header (GList ** list,
   GstRegistryChunkGlobalHeader *hdr;
   GstRegistryChunk *chk;
 
-  hdr = g_slice_new (GstRegistryChunkGlobalHeader);
+  hdr = g_new (GstRegistryChunkGlobalHeader, 1);
   chk = gst_registry_chunks_make_data (hdr,
       sizeof (GstRegistryChunkGlobalHeader));
 
diff --git a/gst/gstregistrychunks.h b/gst/gstregistrychunks.h
index e7b77b3..9121e5f 100644
--- a/gst/gstregistrychunks.h
+++ b/gst/gstregistrychunks.h
@@ -28,13 +28,11 @@
 
 /*
  * we reference strings directly from the plugins and in this case set CONST to
- * avoid freeing them. If g_free() should be used, the MALLOC flag is set,
- * otherwise g_slice_free1() will be used!
+ * avoid freeing them.
  */
 enum {
   GST_REGISTRY_CHUNK_FLAG_NONE = 0,
   GST_REGISTRY_CHUNK_FLAG_CONST = 1,
-  GST_REGISTRY_CHUNK_FLAG_MALLOC = 2,
 };
 
 /*
diff --git a/gst/gstsample.c b/gst/gstsample.c
index 57a3285..09e3f03 100644
--- a/gst/gstsample.c
+++ b/gst/gstsample.c
@@ -106,7 +106,7 @@ _gst_sample_free (GstSample * sample)
   memset (sample, 0xff, sizeof (GstSample));
 #endif
 
-  g_slice_free1 (sizeof (GstSample), sample);
+  g_free (sample);
 }
 
 /**
@@ -129,7 +129,7 @@ gst_sample_new (GstBuffer * buffer, GstCaps * caps, const GstSegment * segment,
 {
   GstSample *sample;
 
-  sample = g_slice_new0 (GstSample);
+  sample = g_new0 (GstSample, 1);
 
   GST_LOG ("new %p", sample);
 
@@ -463,18 +463,38 @@ gst_sample_unref (GstSample * sample)
 
 /**
  * gst_sample_copy: (skip)
- * @buf: a #GstSample.
+ * @sample: a #GstSample.
  *
  * Create a copy of the given sample. This will also make a newly allocated
  * copy of the data the source sample contains.
  *
- * Returns: (transfer full): a new copy of @buf.
+ * Returns: (transfer full): a new copy of @sample.
  *
  * Since: 1.2
  */
 GstSample *
-gst_sample_copy (const GstSample * buf)
+gst_sample_copy (const GstSample * sample)
 {
   return
-      GST_SAMPLE_CAST (gst_mini_object_copy (GST_MINI_OBJECT_CONST_CAST (buf)));
+      GST_SAMPLE_CAST (gst_mini_object_copy (GST_MINI_OBJECT_CONST_CAST
+          (sample)));
+}
+
+/**
+ * gst_clear_sample: (skip)
+ * @sample_ptr: a pointer to a #GstSample reference
+ *
+ * Clears a reference to a #GstSample
+ *
+ * @sample_ptr must not be %NULL.
+ *
+ * If the reference is %NULL then this function does nothing. Otherwise, the
+ * reference count of the sample is decreased and the pointer is set to %NULL.
+ *
+ * Since: 1.24
+ */
+void
+gst_clear_sample (GstSample ** sample_ptr)
+{
+  gst_clear_mini_object ((GstMiniObject **) sample_ptr);
 }
diff --git a/gst/gstsample.h b/gst/gstsample.h
index e3023b0..da59ff9 100644
--- a/gst/gstsample.h
+++ b/gst/gstsample.h
@@ -150,13 +150,22 @@ void        gst_sample_unref  (GstSample * sample);
 #ifndef GST_DISABLE_MINIOBJECT_INLINE_FUNCTIONS
 /* copy sample */
 static inline GstSample *
-gst_sample_copy (const GstSample * buf)
+gst_sample_copy (const GstSample * sample)
 {
-  return GST_SAMPLE_CAST (gst_mini_object_copy (GST_MINI_OBJECT_CONST_CAST (buf)));
+  return GST_SAMPLE_CAST (gst_mini_object_copy (GST_MINI_OBJECT_CONST_CAST (sample)));
+}
+
+static inline void
+gst_clear_sample (GstSample ** sample_ptr)
+{
+  gst_clear_mini_object ((GstMiniObject **) sample_ptr);
 }
 #else /* GST_DISABLE_MINIOBJECT_INLINE_FUNCTIONS */
 GST_API
-GstSample *   gst_sample_copy(const GstSample * buf);
+GstSample *   gst_sample_copy (const GstSample * sample);
+
+GST_API
+void          gst_clear_sample (GstSample ** sample_ptr);
 #endif /* GST_DISABLE_MINIOBJECT_INLINE_FUNCTIONS */
 
 /**
diff --git a/gst/gstsegment.c b/gst/gstsegment.c
index f397707..e2ec99a 100644
--- a/gst/gstsegment.c
+++ b/gst/gstsegment.c
@@ -20,6 +20,7 @@
  */
 
 #include "gst_private.h"
+#include "glib-compat-private.h"
 
 #include <math.h>
 
@@ -103,7 +104,7 @@ gst_segment_copy (const GstSegment * segment)
   GstSegment *result = NULL;
 
   if (segment) {
-    result = (GstSegment *) g_slice_copy (sizeof (GstSegment), segment);
+    result = (GstSegment *) g_memdup2 (segment, sizeof (GstSegment));
   }
   return result;
 }
@@ -139,7 +140,7 @@ gst_segment_new (void)
 {
   GstSegment *result;
 
-  result = g_slice_new0 (GstSegment);
+  result = g_new0 (GstSegment, 1);
   gst_segment_init (result, GST_FORMAT_UNDEFINED);
 
   return result;
@@ -154,7 +155,7 @@ gst_segment_new (void)
 void
 gst_segment_free (GstSegment * segment)
 {
-  g_slice_free (GstSegment, segment);
+  g_free (segment);
 }
 
 /**
@@ -769,8 +770,8 @@ gst_segment_to_running_time_full (const GstSegment * segment, GstFormat format,
       stop = segment->start + segment->duration;
 
     /* cannot continue if no stop position set or invalid offset */
-    g_return_val_if_fail (stop != -1, 0);
-    g_return_val_if_fail (stop >= offset, 0);
+    if (stop == -1 || stop < offset)
+      return 0;
 
     stop -= offset;
 
diff --git a/gst/gststreamcollection.c b/gst/gststreamcollection.c
index 6ec7935..87218ef 100644
--- a/gst/gststreamcollection.c
+++ b/gst/gststreamcollection.c
@@ -97,7 +97,7 @@ gst_stream_collection_class_init (GstStreamCollectionClass * klass)
   gobject_class->get_property = gst_stream_collection_get_property;
 
   /**
-   * GstStream:upstream-id:
+   * GstStreamCollection:upstream-id:
    *
    * stream-id
    */
@@ -108,7 +108,7 @@ gst_stream_collection_class_init (GstStreamCollectionClass * klass)
           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
 
   /**
-   * GstStream::stream-notify:
+   * GstStreamCollection::stream-notify:
    * @collection: a #GstStreamCollection
    * @prop_stream: the #GstStream that originated the signal
    * @prop: the property that changed
@@ -189,6 +189,7 @@ gst_stream_collection_set_upstream_id (GstStreamCollection * collection,
 {
   g_return_if_fail (collection->upstream_id == NULL);
 
+  GST_OBJECT_LOCK (collection);
   /* Upstream ID should only be set once on construction, but let's
    * not leak in case someone does something silly */
   if (collection->upstream_id)
@@ -196,6 +197,15 @@ gst_stream_collection_set_upstream_id (GstStreamCollection * collection,
 
   if (upstream_id)
     collection->upstream_id = g_strdup (upstream_id);
+
+  /* We hold the object lock, replace directly */
+  g_free (GST_OBJECT_NAME (collection));
+  if (upstream_id)
+    GST_OBJECT_NAME (collection) = g_strdup (upstream_id);
+  else
+    GST_OBJECT_NAME (collection) = g_strdup ("unparented");
+
+  GST_OBJECT_UNLOCK (collection);
 }
 
 /**
diff --git a/gst/gststructure.c b/gst/gststructure.c
index c8228c4..9055ddf 100644
--- a/gst/gststructure.c
+++ b/gst/gststructure.c
@@ -127,7 +127,7 @@
  * ```
  *
  * > *note*: gst_structure_to_string() won't use that syntax for backward
- * > compatibility reason, gst_structure_serialize() has been added for
+ * > compatibility reason, gst_structure_serialize_full() has been added for
  * > that purpose.
  */
 
@@ -2033,6 +2033,7 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
   guint i, len;
   gboolean nested_structs_brackets =
       !(flags & GST_SERIALIZE_FLAG_BACKWARD_COMPAT);
+  gboolean strict = (flags & GST_SERIALIZE_FLAG_STRICT) != 0;
 
   g_return_val_if_fail (s != NULL, FALSE);
 
@@ -2069,7 +2070,8 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
 
       g_string_append_c (s, '[');
       g_string_append (s, g_quark_to_string (substruct->name));
-      priv_gst_structure_append_to_gstring (substruct, s, flags);
+      if (!priv_gst_structure_append_to_gstring (substruct, s, flags))
+        return FALSE;
       g_string_append_c (s, ']');
     } else if (nested_structs_brackets
         && G_VALUE_TYPE (&field->value) == GST_TYPE_CAPS) {
@@ -2081,9 +2083,13 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
     } else if (t) {
       g_string_append (s, t);
       g_free (t);
+      if (strict && G_VALUE_HOLDS_OBJECT (&field->value))
+        return FALSE;
     } else if (G_TYPE_CHECK_VALUE_TYPE (&field->value, G_TYPE_POINTER)) {
       gpointer ptr = g_value_get_pointer (&field->value);
 
+      if (strict)
+        return FALSE;
       if (!ptr)
         g_string_append (s, "NULL");
       else
@@ -2093,6 +2099,8 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
         GST_WARNING ("No value transform to serialize field '%s' of type '%s'",
             g_quark_to_string (field->name),
             _priv_gst_value_gtype_to_abbr (type));
+      if (strict)
+        return FALSE;
       /* TODO(ensonic): don't print NULL if field->value is not empty */
       g_string_append (s, "NULL");
     }
@@ -2168,7 +2176,10 @@ structure_serialize (const GstStructure * structure, GstSerializeFlags flags)
    * avoid unnecessary reallocs within GString */
   s = g_string_sized_new (STRUCTURE_ESTIMATED_STRING_LEN (structure));
   g_string_append (s, g_quark_to_string (structure->name));
-  priv_gst_structure_append_to_gstring (structure, s, flags);
+  if (!priv_gst_structure_append_to_gstring (structure, s, flags)) {
+    g_string_free (s, TRUE);
+    return NULL;
+  }
   return g_string_free (s, FALSE);
 
 }
@@ -2186,7 +2197,7 @@ structure_serialize (const GstStructure * structure, GstSerializeFlags flags)
  *
  * This function will lead to unexpected results when there are nested #GstCaps
  * / #GstStructure deeper than one level, you should user
- * gst_structure_serialize() instead for those cases.
+ * gst_structure_serialize_full() instead for those cases.
  *
  * Free-function: g_free
  *
@@ -2211,16 +2222,42 @@ gst_structure_to_string (const GstStructure * structure)
  * GStreamer prior to 1.20 unless #GST_SERIALIZE_FLAG_BACKWARD_COMPAT is passed
  * as @flag.
  *
+ * %GST_SERIALIZE_FLAG_STRICT flags is not allowed because it would make this
+ * function nullable which is an API break for bindings.
+ * Use gst_structure_serialize_full() instead.
+ *
  * Free-function: g_free
  *
  * Returns: (transfer full): a pointer to string allocated by g_malloc().
  *     g_free() after usage.
  *
  * Since: 1.20
+ * Deprecated: Use gst_structure_serialize_full() instead.
  */
 gchar *
 gst_structure_serialize (const GstStructure * structure,
     GstSerializeFlags flags)
+{
+  g_return_val_if_fail ((flags & GST_SERIALIZE_FLAG_STRICT) == 0, NULL);
+  return structure_serialize (structure, flags);
+}
+
+/**
+ * gst_structure_serialize_full:
+ * @structure: a #GstStructure
+ * @flags: The flags to use to serialize structure
+ *
+ * Alias for gst_structure_serialize() but with nullable annotation because it
+ * can return %NULL when %GST_SERIALIZE_FLAG_STRICT flag is set.
+ *
+ * Returns: (transfer full) (nullable): a pointer to string allocated by g_malloc().
+ *     g_free() after usage.
+ *
+ * Since: 1.24
+ */
+gchar *
+gst_structure_serialize_full (const GstStructure * structure,
+    GstSerializeFlags flags)
 {
   return structure_serialize (structure, flags);
 }
diff --git a/gst/gststructure.h b/gst/gststructure.h
index 64fec16..d86dedc 100644
--- a/gst/gststructure.h
+++ b/gst/gststructure.h
@@ -32,11 +32,23 @@ GST_API GType _gst_structure_type;
 
 typedef struct _GstStructure GstStructure;
 
+/**
+ * GST_SERIALIZE_FLAG_STRICT:
+ *
+ * Serialization fails if a value cannot be serialized instead of using
+ * placeholder "NULL" value (e.g. pointers, objects).
+ *
+ * Since: 1.24
+ */
+
 /**
  * GstSerializeFlags:
  * @GST_SERIALIZE_FLAG_NONE: No special flags specified.
  * @GST_SERIALIZE_FLAG_BACKWARD_COMPAT: Serialize using the old format for
  *                                      nested structures.
+ * @GST_SERIALIZE_FLAG_STRICT: Serialization fails if a value cannot be
+ *  serialized instead of using placeholder "NULL" value (e.g. pointers,
+ *  objects). (Since 1.24)
  *
  * Since: 1.20
  */
@@ -44,6 +56,7 @@ typedef enum
 {
   GST_SERIALIZE_FLAG_NONE = 0,
   GST_SERIALIZE_FLAG_BACKWARD_COMPAT = (1 << 0),
+  GST_SERIALIZE_FLAG_STRICT = (1 << 1),
 } GstSerializeFlags;
 
 #define GST_TYPE_STRUCTURE             (_gst_structure_type)
@@ -351,9 +364,12 @@ gboolean              gst_structure_get_flags            (const GstStructure  *
 
 GST_API
 gchar *               gst_structure_to_string            (const GstStructure * structure) G_GNUC_MALLOC;
-GST_API
+GST_DEPRECATED_FOR(gst_structure_serialize_full)
 gchar *               gst_structure_serialize            (const GstStructure * structure,
                                                           GstSerializeFlags flags) G_GNUC_MALLOC;
+GST_API
+gchar *               gst_structure_serialize_full       (const GstStructure * structure,
+                                                          GstSerializeFlags flags) G_GNUC_MALLOC;
 
 GST_API
 GstStructure *        gst_structure_from_string  (const gchar * string,
diff --git a/gst/gstsystemclock.c b/gst/gstsystemclock.c
index 7d8efb1..72c3912 100644
--- a/gst/gstsystemclock.c
+++ b/gst/gstsystemclock.c
@@ -60,6 +60,129 @@
 #include <mach/mach_time.h>
 #endif
 
+#if defined __APPLE__
+static struct mach_timebase_info mach_timebase;
+#endif
+
+#if defined G_OS_WIN32
+static LARGE_INTEGER performance_counter_frequency;
+#endif
+
+/* Small helper to make the atomics below cheaper.
+ *
+ * GLib always uses SEQ_CST atomic ops while here it's more than enough to use
+ * ACQUIRE/RELEASE atomic ops. On x86 / x86-64 the ACQUIRE load is compiling
+ * to a simple memory read.
+ */
+#if defined __APPLE__ || defined G_OS_WIN32
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
+#include <stdatomic.h>
+
+typedef atomic_int gst_atomic_int;
+
+static inline int
+gst_atomic_int_get_acquire (gst_atomic_int * x)
+{
+  return atomic_load_explicit (x, memory_order_acquire);
+}
+
+static inline void
+gst_atomic_int_set_release (gst_atomic_int * x, gint val)
+{
+  atomic_store_explicit (x, val, memory_order_release);
+}
+#elif defined G_OS_WIN32
+/* MSVC's C11 atomic might require special cflags
+ * https://devblogs.microsoft.com/cppblog/c11-atomics-in-visual-studio-2022-version-17-5-preview-2/
+ *
+ * Can remove this code once below GLib MR is merged
+ * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3436
+ */
+
+typedef LONG gst_atomic_int;
+
+static inline int
+gst_atomic_int_get_acquire (gst_atomic_int * x)
+{
+  return InterlockedAndAcquire (x, 1);
+}
+
+static inline void
+gst_atomic_int_set_release (gst_atomic_int * x, gint val)
+{
+  InterlockedOrRelease (x, 1);
+}
+#else /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) */
+typedef int gst_atomic_int;
+#define gst_atomic_int_get_acquire(x) g_atomic_int_get(x)
+#define gst_atomic_int_set_release(x, val) g_atomic_int_set(x, val)
+#endif /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) */
+#endif /* defined __APPLE__ || defined G_OS_WIN32 */
+
+/* priv_gst_clock_init:
+ *
+ * Initialize internal state of the clock. This is safe to call multiple
+ * times.
+ */
+void
+priv_gst_clock_init (void)
+{
+#if defined __APPLE__
+  static gst_atomic_int inited = FALSE;
+
+  if (!gst_atomic_int_get_acquire (&inited)) {
+    mach_timebase_info (&mach_timebase);
+    gst_atomic_int_set_release (&inited, TRUE);
+  }
+#endif
+
+#if defined G_OS_WIN32
+  static gst_atomic_int inited = FALSE;
+
+  if (!gst_atomic_int_get_acquire (&inited)) {
+    QueryPerformanceFrequency (&performance_counter_frequency);
+    gst_atomic_int_set_release (&inited, TRUE);
+  }
+#endif
+}
+
+GstClockTime
+priv_gst_get_monotonic_time (void)
+{
+#if defined __APPLE__
+  guint64 mach_t = mach_absolute_time ();
+  return gst_util_uint64_scale (mach_t, mach_timebase.numer,
+      mach_timebase.denom);
+#elif defined G_OS_WIN32
+  LARGE_INTEGER now;
+  QueryPerformanceCounter (&now);
+
+  return gst_util_uint64_scale (now.QuadPart, GST_SECOND,
+      performance_counter_frequency.QuadPart);
+#elif defined (HAVE_POSIX_TIMERS) && defined(HAVE_MONOTONIC_CLOCK) &&\
+    defined (HAVE_CLOCK_GETTIME)
+  struct timespec now;
+
+  clock_gettime (CLOCK_MONOTONIC, &now);
+  return GST_TIMESPEC_TO_TIME (now);
+#else
+  return g_get_monotonic_time () * 1000;
+#endif
+}
+
+GstClockTime
+priv_gst_get_real_time (void)
+{
+#if defined (HAVE_POSIX_TIMERS) && defined (HAVE_CLOCK_GETTIME)
+  struct timespec now;
+
+  clock_gettime (CLOCK_REALTIME, &now);
+  return GST_TIMESPEC_TO_TIME (now);
+#else
+  return g_get_real_time () * 1000;
+#endif
+}
+
 /* Define this to get some extra debug about jitter from each clock_wait */
 #undef WAIT_DEBUGGING
 
@@ -127,8 +250,12 @@ gst_futex_cond_broadcast (guint * cond_val)
 {
   g_atomic_int_inc (cond_val);
 
-#if defined(__NR_futex_time64)
+#if defined(HAVE_FUTEX_TIME64)
+#if defined(__BIONIC__)
+  if (__builtin_available (android 30, *)) {
+#else
   {
+#endif
     int res;
     res = syscall (__NR_futex_time64, cond_val, (gsize) FUTEX_WAKE_PRIVATE,
         (gsize) INT_MAX, NULL);
@@ -137,7 +264,7 @@ gst_futex_cond_broadcast (guint * cond_val)
      * normal `futex` syscall. This can happen if newer kernel headers are
      * used than the kernel that is actually running.
      */
-#ifdef __NR_futex
+#if defined(HAVE_FUTEX)
     if (res >= 0 || errno != ENOSYS) {
 #else
     {
@@ -147,7 +274,7 @@ gst_futex_cond_broadcast (guint * cond_val)
   }
 #endif
 
-#if defined(__NR_futex)
+#if defined(HAVE_FUTEX)
   syscall (__NR_futex, cond_val, (gsize) FUTEX_WAKE_PRIVATE, (gsize) INT_MAX,
       NULL);
 #endif
@@ -185,8 +312,12 @@ gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time)
    * define `__NR_futex_time64`.
    */
 
-#ifdef __NR_futex_time64
+#if defined(HAVE_FUTEX_TIME64)
+#if defined(__BIONIC__)
+  if (__builtin_available (android 30, *)) {
+#else
   {
+#endif
     struct
     {
       gint64 tv_sec;
@@ -206,7 +337,7 @@ gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time)
      * normal `futex` syscall. This can happen if newer kernel headers are
      * used than the kernel that is actually running.
      */
-#ifdef __NR_futex
+#if defined(HAVE_FUTEX)
     if (res >= 0 || errno != ENOSYS) {
 #else
     {
@@ -219,7 +350,7 @@ gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time)
   }
 #endif
 
-#ifdef __NR_futex
+#if defined(HAVE_FUTEX)
   {
     struct
     {
@@ -300,7 +431,7 @@ gst_pthread_cond_wait_until (pthread_cond_t * cond, pthread_mutex_t * lock,
    * Since this pthreads wants the relative time, convert it back again.
    */
   {
-    gint64 now = g_get_monotonic_time () * 1000;
+    gint64 now = priv_gst_get_monotonic_time ();
     gint64 relative;
 
     if (end_time <= now)
@@ -440,19 +571,13 @@ ensure_entry_initialized (GstClockEntryImpl * entry_impl)
 struct _GstSystemClockPrivate
 {
   GThread *thread;              /* thread for async notify */
+  gboolean starting;
   gboolean stopping;
 
   GList *entries;
   GCond entries_changed;
 
   GstClockType clock_type;
-
-#ifdef G_OS_WIN32
-  LARGE_INTEGER frequency;
-#endif                          /* G_OS_WIN32 */
-#ifdef __APPLE__
-  struct mach_timebase_info mach_timebase;
-#endif
 };
 
 #ifdef HAVE_POSIX_TIMERS
@@ -483,10 +608,6 @@ static void gst_system_clock_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
 static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
-#if !defined HAVE_POSIX_TIMERS || !defined HAVE_CLOCK_GETTIME
-static GstClockTime gst_system_clock_get_mono_time (GstSystemClock * clock);
-static GstClockTime gst_system_clock_get_real_time ();
-#endif
 static guint64 gst_system_clock_get_resolution (GstClock * clock);
 static GstClockReturn gst_system_clock_id_wait_jitter (GstClock * clock,
     GstClockEntry * entry, GstClockTimeDiff * jitter);
@@ -551,14 +672,6 @@ gst_system_clock_init (GstSystemClock * clock)
   priv->entries = NULL;
   g_cond_init (&priv->entries_changed);
 
-#ifdef G_OS_WIN32
-  QueryPerformanceFrequency (&priv->frequency);
-#endif /* G_OS_WIN32 */
-
-#ifdef __APPLE__
-  mach_timebase_info (&priv->mach_timebase);
-#endif
-
 #if 0
   /* Uncomment this to start the async clock thread straight away */
   GST_SYSTEM_CLOCK_LOCK (clock);
@@ -758,11 +871,11 @@ gst_system_clock_async_thread (GstClock * clock)
   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
   GstSystemClockPrivate *priv = sysclock->priv;
   GstClockReturn status;
-  gboolean entry_needs_unlock = FALSE;
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "enter system clock thread");
   GST_SYSTEM_CLOCK_LOCK (clock);
   /* signal spinup */
+  priv->starting = FALSE;
   GST_SYSTEM_CLOCK_BROADCAST (clock);
   /* now enter our (almost) infinite loop */
   while (!priv->stopping) {
@@ -790,7 +903,6 @@ gst_system_clock_async_thread (GstClock * clock)
 
     /* unlocked before the next loop iteration at latest */
     GST_SYSTEM_CLOCK_ENTRY_LOCK ((GstClockEntryImpl *) entry);
-    entry_needs_unlock = TRUE;
 
     /* set entry status to busy before we release the clock lock */
     status = GST_CLOCK_ENTRY_STATUS (entry);
@@ -801,7 +913,7 @@ gst_system_clock_async_thread (GstClock * clock)
       GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
           "async entry %p unscheduled", entry);
       GST_SYSTEM_CLOCK_UNLOCK (clock);
-      goto next_entry;
+      goto unlock_entry_and_next_entry;
     }
 
     /* for periodic timers, status can be EARLY from a previous run */
@@ -832,12 +944,11 @@ gst_system_clock_async_thread (GstClock * clock)
         /* entry was unscheduled, move to the next */
         GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock,
             "async entry %p unscheduled", entry);
-        goto next_entry;
+        goto unlock_entry_and_next_entry;
       case GST_CLOCK_OK:
       case GST_CLOCK_EARLY:
       {
         GST_SYSTEM_CLOCK_ENTRY_UNLOCK ((GstClockEntryImpl *) entry);
-        entry_needs_unlock = FALSE;
         /* entry timed out normally, fire the callback and move to the next
          * entry */
         GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "async entry %p timed out",
@@ -875,8 +986,7 @@ gst_system_clock_async_thread (GstClock * clock)
          * _unschedule() code can see if an entry is currently being waited
          * on (when its state is BUSY). */
         GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_OK;
-        if (entry_needs_unlock)
-          GST_SYSTEM_CLOCK_ENTRY_UNLOCK ((GstClockEntryImpl *) entry);
+        GST_SYSTEM_CLOCK_ENTRY_UNLOCK ((GstClockEntryImpl *) entry);
         GST_SYSTEM_CLOCK_LOCK (clock);
         continue;
       default:
@@ -884,11 +994,11 @@ gst_system_clock_async_thread (GstClock * clock)
             "strange result %d waiting for %p, skipping", res, entry);
         g_warning ("%s: strange result %d waiting for %p, skipping",
             GST_OBJECT_NAME (clock), res, entry);
-        goto next_entry;
+        goto unlock_entry_and_next_entry;
     }
+  unlock_entry_and_next_entry:
+    GST_SYSTEM_CLOCK_ENTRY_UNLOCK ((GstClockEntryImpl *) entry);
   next_entry:
-    if (entry_needs_unlock)
-      GST_SYSTEM_CLOCK_ENTRY_UNLOCK ((GstClockEntryImpl *) entry);
     GST_SYSTEM_CLOCK_LOCK (clock);
 
     /* we remove the current entry and unref it */
@@ -909,7 +1019,6 @@ clock_type_to_posix_id (GstClockType clock_type)
 #ifdef HAVE_MONOTONIC_CLOCK
   if (clock_type == GST_CLOCK_TYPE_MONOTONIC)
     return CLOCK_MONOTONIC;
-  else
 #endif
   if (clock_type == GST_CLOCK_TYPE_TAI)
 #ifdef CLOCK_TAI
@@ -927,6 +1036,16 @@ static GstClockTime
 gst_system_clock_get_internal_time (GstClock * clock)
 {
   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
+
+  /* For the monotonic and realtime clock, always directly call the specific
+   * helper functions above */
+  if (sysclock->priv->clock_type == GST_CLOCK_TYPE_MONOTONIC)
+    return priv_gst_get_monotonic_time ();
+  else if (sysclock->priv->clock_type == GST_CLOCK_TYPE_REALTIME)
+    return priv_gst_get_real_time ();
+
+  /* If POSIX timers are available, use those for any other clock,
+   * or otherwise return the monotonic time */
 #if defined HAVE_POSIX_TIMERS && defined HAVE_CLOCK_GETTIME
   // BSD and Linux' Posix timers and clock_gettime cover all of the different clock types
   // without need for special handling so we'll use those.
@@ -939,90 +1058,49 @@ gst_system_clock_get_internal_time (GstClock * clock)
     return GST_CLOCK_TIME_NONE;
 
   return GST_TIMESPEC_TO_TIME (ts);
-#else
-  if (sysclock->priv->clock_type == GST_CLOCK_TYPE_REALTIME) {
-    return gst_system_clock_get_real_time ();
-  } else {
-    return gst_system_clock_get_mono_time (sysclock);
-  }
+#else /* !HAVE_POSIX_TIMERS || !HAVE_CLOCK_GETTIME */
+  return priv_gst_get_monotonic_time ();
 #endif /* !HAVE_POSIX_TIMERS || !HAVE_CLOCK_GETTIME */
 }
 
-#if !defined HAVE_POSIX_TIMERS || !defined HAVE_CLOCK_GETTIME
-static GstClockTime
-gst_system_clock_get_real_time ()
-{
-  gint64 rt_micros = g_get_real_time ();
-  // g_get_real_time returns microseconds but we need nanos, so we'll multiply by 1000
-  return ((guint64) rt_micros) * 1000;
-}
-
-static GstClockTime
-gst_system_clock_get_mono_time (GstSystemClock * sysclock)
-{
-#if defined __APPLE__
-  uint64_t mach_t = mach_absolute_time ();
-  return gst_util_uint64_scale (mach_t, sysclock->priv->mach_timebase.numer,
-      sysclock->priv->mach_timebase.denom);
-#else
-#if defined G_OS_WIN32
-  if (sysclock->priv->frequency.QuadPart != 0) {
-    LARGE_INTEGER now;
-
-    /* we prefer the highly accurate performance counters on windows */
-    QueryPerformanceCounter (&now);
-
-    return gst_util_uint64_scale (now.QuadPart,
-        GST_SECOND, sysclock->priv->frequency.QuadPart);
-  } else
-#endif /* G_OS_WIN32 */
-  {
-    gint64 monotime;
-
-    monotime = g_get_monotonic_time ();
-
-    return monotime * 1000;
-  }
-#endif /* __APPLE__ */
-}
-#endif /* !HAVE_POSIX_TIMERS || !HAVE_CLOCK_GETTIME */
-
 static guint64
 gst_system_clock_get_resolution (GstClock * clock)
 {
   GstSystemClock *sysclock = GST_SYSTEM_CLOCK_CAST (clock);
-#if defined __APPLE__ || defined G_OS_WIN32
+
+#if defined G_OS_WIN32
   if (sysclock->priv->clock_type == GST_CLOCK_TYPE_REALTIME) {
     return 1 * GST_USECOND;
-  } else
+  } else {
+    return GST_SECOND / performance_counter_frequency.QuadPart;
+  }
 #endif
+
 #if defined __APPLE__
-  {
+  // On Apple platforms we want to use mach_absolute_time() unconditionally
+  // for the monotonic clock even if clock_gettime() support is available.
+  // Only use the latter for other clock types there.
+  if (sysclock->priv->clock_type == GST_CLOCK_TYPE_MONOTONIC) {
     return gst_util_uint64_scale (GST_NSECOND,
-        sysclock->priv->mach_timebase.numer,
-        sysclock->priv->mach_timebase.denom);
+        mach_timebase.numer, mach_timebase.denom);
   }
-#elif defined G_OS_WIN32
+#endif
+
+#if defined(HAVE_POSIX_TIMERS) && defined(HAVE_CLOCK_GETTIME)
   {
-    if (sysclock->priv->frequency.QuadPart != 0) {
-      return GST_SECOND / sysclock->priv->frequency.QuadPart;
-    } else {
-      return 1 * GST_USECOND;
-    }
-  }
-#elif defined(HAVE_POSIX_TIMERS) && defined(HAVE_CLOCK_GETTIME)
     clockid_t ptype;
-  struct timespec ts;
+    struct timespec ts;
 
-  ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
+    ptype = clock_type_to_posix_id (sysclock->priv->clock_type);
 
-  if (G_UNLIKELY (clock_getres (ptype, &ts)))
-    return GST_CLOCK_TIME_NONE;
+    if (G_UNLIKELY (clock_getres (ptype, &ts)))
+      return GST_CLOCK_TIME_NONE;
 
-  return GST_TIMESPEC_TO_TIME (ts);
-#else
-    return 1 * GST_USECOND;
-#endif /* __APPLE__ */
+    return GST_TIMESPEC_TO_TIME (ts);
+  }
+#endif /* HAVE_POSIX_TIMERS && HAVE_CLOCK_GETTIME */
+
+  return 1 * GST_USECOND;
 }
 
 /* synchronously wait on the given GstClockEntry.
@@ -1048,16 +1126,26 @@ gst_system_clock_id_wait_jitter_unlocked (GstClock * clock,
   GstClockReturn status;
   gint64 mono_ts;
 
-  status = GST_CLOCK_ENTRY_STATUS (entry);
-  if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
-    return GST_CLOCK_UNSCHEDULED;
-  }
+  /* Getting the time from the clock locks the clock, so without unlocking the
+   * entry we would have a lock order violation here that can lead to deadlocks.
+   *
+   * It's not a problem to take the mutex again after getting the times (which
+   * might block for a moment) as waiting happens based on the absolute time.
+   */
+  GST_SYSTEM_CLOCK_ENTRY_UNLOCK ((GstClockEntryImpl *) entry);
 
   /* need to call the overridden method because we want to sync against the time
    * of the clock, whatever the subclass uses as a clock. */
   now = gst_clock_get_time (clock);
   mono_ts = g_get_monotonic_time ();
 
+  GST_SYSTEM_CLOCK_ENTRY_LOCK ((GstClockEntryImpl *) entry);
+  /* Might have been unscheduled in the meantime */
+  status = GST_CLOCK_ENTRY_STATUS (entry);
+  if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
+    return GST_CLOCK_UNSCHEDULED;
+  }
+
   /* get the time of the entry */
   entryt = GST_CLOCK_ENTRY_TIME (entry);
 
@@ -1145,10 +1233,20 @@ gst_system_clock_id_wait_jitter_unlocked (GstClock * clock,
               "entry %p unlocked after timeout", entry);
         }
 
+        GST_SYSTEM_CLOCK_ENTRY_UNLOCK ((GstClockEntryImpl *) entry);
+
         /* reschedule if gst_cond_wait_until returned early or we have to reschedule after
          * an unlock*/
-        mono_ts = g_get_monotonic_time ();
         now = gst_clock_get_time (clock);
+        mono_ts = g_get_monotonic_time ();
+
+        GST_SYSTEM_CLOCK_ENTRY_LOCK ((GstClockEntryImpl *) entry);
+        /* Might have been unscheduled in the meantime */
+        status = GST_CLOCK_ENTRY_STATUS (entry);
+        if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
+          goto done;
+        }
+
         diff = GST_CLOCK_DIFF (now, entryt);
 
         if (diff <= CLOCK_MIN_WAIT_TIME) {
@@ -1236,6 +1334,7 @@ gst_system_clock_start_async (GstSystemClock * clock)
   if (G_LIKELY (priv->thread != NULL))
     return TRUE;                /* Thread already running. Nothing to do */
 
+  priv->starting = TRUE;
   priv->thread = g_thread_try_new ("GstSystemClock",
       (GThreadFunc) gst_system_clock_async_thread, clock, &error);
 
@@ -1243,13 +1342,15 @@ gst_system_clock_start_async (GstSystemClock * clock)
     goto no_thread;
 
   /* wait for it to spin up */
-  GST_SYSTEM_CLOCK_WAIT (clock);
+  while (priv->starting)
+    GST_SYSTEM_CLOCK_WAIT (clock);
 
   return TRUE;
 
   /* ERRORS */
 no_thread:
   {
+    priv->starting = FALSE;
     g_warning ("could not create async clock thread: %s", error->message);
     g_error_free (error);
   }
diff --git a/gst/gsttaglist.c b/gst/gsttaglist.c
index 07519fe..222c350 100644
--- a/gst/gsttaglist.c
+++ b/gst/gsttaglist.c
@@ -410,7 +410,9 @@ _priv_gst_tag_initialize (void)
   gst_tag_register_static (GST_TAG_PRIVATE_DATA, GST_TAG_FLAG_META,
       GST_TYPE_SAMPLE,
       _("private-data"), _("Private data"), gst_tag_merge_use_first);
-
+  gst_tag_register_static (GST_TAG_CONTAINER_SPECIFIC_TRACK_ID,
+      GST_TAG_FLAG_META, G_TYPE_STRING,
+      _("container-specific-track-id"), _("Container-specific Track ID"), NULL);
 }
 
 /**
@@ -455,8 +457,7 @@ gst_tag_merge_strings_with_comma (GValue * dest, const GValue * src)
   }
 
   g_value_init (dest, G_TYPE_STRING);
-  g_value_take_string (dest, str->str);
-  g_string_free (str, FALSE);
+  g_value_take_string (dest, g_string_free (str, FALSE));
 }
 
 static GstTagInfo *
@@ -549,7 +550,7 @@ gst_tag_register_static (const gchar * name, GstTagFlag flag, GType type,
     return;
   }
 
-  info = g_slice_new (GstTagInfo);
+  info = g_new (GstTagInfo, 1);
   info->flag = flag;
   info->type = type;
   info->name_quark = g_quark_from_static_string (name);
@@ -693,7 +694,7 @@ gst_tag_list_new_internal (GstStructure * s, GstTagScope scope)
 
   g_assert (s != NULL);
 
-  tag_list = (GstTagList *) g_slice_new (GstTagListImpl);
+  tag_list = (GstTagList *) g_new (GstTagListImpl, 1);
 
   gst_mini_object_init (GST_MINI_OBJECT_CAST (tag_list), 0, GST_TYPE_TAG_LIST,
       (GstMiniObjectCopyFunction) __gst_tag_list_copy, NULL,
@@ -724,7 +725,7 @@ __gst_tag_list_free (GstTagList * list)
   memset (list, 0xff, sizeof (GstTagListImpl));
 #endif
 
-  g_slice_free1 (sizeof (GstTagListImpl), list);
+  g_free (list);
 }
 
 static GstTagList *
diff --git a/gst/gsttaglist.h b/gst/gsttaglist.h
index c15ea2d..1bd01de 100644
--- a/gst/gsttaglist.h
+++ b/gst/gsttaglist.h
@@ -1115,6 +1115,18 @@ gboolean  gst_tag_list_take    (GstTagList ** old_taglist,
  */
 #define GST_TAG_PRIVATE_DATA                         "private-data"
 
+/**
+ * GST_TAG_CONTAINER_SPECIFIC_TRACK_ID:
+ *
+ * Unique identifier for the audio, video or text track this tag is associated
+ * with. The mappings for several container formats are defined in the [Sourcing
+ * In-band Media Resource Tracks from Media Containers into HTML
+ * specification](https://dev.w3.org/html5/html-sourcing-inband-tracks/).
+ *
+ * Since: 1.24
+ */
+#define GST_TAG_CONTAINER_SPECIFIC_TRACK_ID "container-specific-track-id"
+
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstTagList, gst_tag_list_unref)
 
 G_END_DECLS
diff --git a/gst/gsttagsetter.c b/gst/gsttagsetter.c
index ea54c35..71c73d2 100644
--- a/gst/gsttagsetter.c
+++ b/gst/gsttagsetter.c
@@ -108,7 +108,7 @@ gst_tag_data_free (gpointer p)
 
   g_mutex_clear (&data->lock);
 
-  g_slice_free (GstTagData, data);
+  g_free (data);
 }
 
 static GstTagData *
@@ -125,7 +125,7 @@ gst_tag_setter_get_data (GstTagSetter * setter)
 
     data = g_object_get_qdata (G_OBJECT (setter), gst_tag_key);
     if (!data) {
-      data = g_slice_new (GstTagData);
+      data = g_new (GstTagData, 1);
       g_mutex_init (&data->lock);
       data->list = NULL;
       data->mode = GST_TAG_MERGE_KEEP;
diff --git a/gst/gsttask.c b/gst/gsttask.c
index da81820..c135645 100644
--- a/gst/gsttask.c
+++ b/gst/gsttask.c
@@ -89,6 +89,21 @@ GST_DEBUG_CATEGORY_STATIC (task_debug);
 #define SET_TASK_STATE(t,s) (g_atomic_int_set (&GST_TASK_STATE(t), (s)))
 #define GET_TASK_STATE(t)   ((GstTaskState) g_atomic_int_get (&GST_TASK_STATE(t)))
 
+static const char *
+task_state_to_string (GstTaskState state)
+{
+  switch (state) {
+    case GST_TASK_STARTED:
+      return "started";
+    case GST_TASK_PAUSED:
+      return "paused";
+    case GST_TASK_STOPPED:
+      return "stopped";
+    default:
+      return "(unknown)";
+  }
+}
+
 struct _GstTaskPrivate
 {
   /* callbacks for managing the thread of this task */
@@ -162,7 +177,7 @@ gst_task_win32_load_library (void)
   }
 #endif
 
-  return ! !SetThreadDescriptionFunc;
+  return !!SetThreadDescriptionFunc;
 }
 
 static gboolean
@@ -726,7 +741,8 @@ gst_task_set_state_unlocked (GstTask * task, GstTaskState state)
   GstTaskState old;
   gboolean res = TRUE;
 
-  GST_DEBUG_OBJECT (task, "Changing task %p to state %d", task, state);
+  GST_DEBUG_OBJECT (task, "Changing task %p to state %s", task,
+      task_state_to_string (state));
 
   if (state != GST_TASK_STOPPED)
     if (G_UNLIKELY (GST_TASK_GET_LOCK (task) == NULL))
@@ -759,8 +775,10 @@ gst_task_set_state_unlocked (GstTask * task, GstTaskState state)
   /* ERRORS */
 no_lock:
   {
-    GST_WARNING_OBJECT (task, "state %d set on task without a lock", state);
-    g_warning ("task without a lock can't be set to state %d", state);
+    GST_WARNING_OBJECT (task, "state %s set on task without a lock",
+        task_state_to_string (state));
+    g_warning ("task without a lock can't be set to state %s",
+        task_state_to_string (state));
     return FALSE;
   }
 }
diff --git a/gst/gsttaskpool.c b/gst/gsttaskpool.c
index 3116cc7..020a1d2 100644
--- a/gst/gsttaskpool.c
+++ b/gst/gsttaskpool.c
@@ -65,7 +65,7 @@ default_func (TaskData * tdata, GstTaskPool * pool)
 
   func = tdata->func;
   user_data = tdata->user_data;
-  g_slice_free (TaskData, tdata);
+  g_free (tdata);
 
   func (user_data);
 }
@@ -102,7 +102,7 @@ default_push (GstTaskPool * pool, GstTaskPoolFunction func,
 {
   TaskData *tdata;
 
-  tdata = g_slice_new (TaskData);
+  tdata = g_new (TaskData, 1);
   tdata->func = func;
   tdata->user_data = user_data;
 
@@ -110,10 +110,9 @@ default_push (GstTaskPool * pool, GstTaskPoolFunction func,
   if (pool->pool)
     g_thread_pool_push (pool->pool, tdata, error);
   else {
-    g_slice_free (TaskData, tdata);
+    g_free (tdata);
     g_set_error_literal (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
         "No thread pool");
-
   }
   GST_OBJECT_UNLOCK (pool);
 
@@ -349,7 +348,7 @@ shared_task_data_unref (SharedTaskData * tdata)
   if (g_atomic_int_dec_and_test (&tdata->refcount)) {
     g_mutex_clear (&tdata->done_lock);
     g_cond_clear (&tdata->done_cond);
-    g_slice_free (SharedTaskData, tdata);
+    g_free (tdata);
   }
 }
 
@@ -389,7 +388,7 @@ shared_push (GstTaskPool * pool, GstTaskPoolFunction func,
     goto done;
   }
 
-  ret = g_slice_new (SharedTaskData);
+  ret = g_new (SharedTaskData, 1);
 
   ret->done = FALSE;
   ret->func = func;
diff --git a/gst/gsttoc.c b/gst/gsttoc.c
index 7e8ba17..bee3224 100644
--- a/gst/gsttoc.c
+++ b/gst/gsttoc.c
@@ -140,7 +140,7 @@ gst_toc_new (GstTocScope scope)
   g_return_val_if_fail (scope == GST_TOC_SCOPE_GLOBAL ||
       scope == GST_TOC_SCOPE_CURRENT, NULL);
 
-  toc = g_slice_new0 (GstToc);
+  toc = g_new0 (GstToc, 1);
 
   gst_mini_object_init (GST_MINI_OBJECT_CAST (toc), 0, GST_TYPE_TOC,
       (GstMiniObjectCopyFunction) gst_toc_copy, NULL,
@@ -269,7 +269,7 @@ gst_toc_entry_new_internal (GstTocEntryType type, const gchar * uid)
 {
   GstTocEntry *entry;
 
-  entry = g_slice_new0 (GstTocEntry);
+  entry = g_new0 (GstTocEntry, 1);
 
   gst_mini_object_init (GST_MINI_OBJECT_CAST (entry), 0, GST_TYPE_TOC_ENTRY,
       (GstMiniObjectCopyFunction) gst_toc_entry_copy, NULL,
@@ -313,7 +313,7 @@ gst_toc_free (GstToc * toc)
   memset (toc, 0xff, sizeof (GstToc));
 #endif
 
-  g_slice_free (GstToc, toc);
+  g_free (toc);
 }
 
 static void
@@ -333,7 +333,7 @@ gst_toc_entry_free (GstTocEntry * entry)
   memset (entry, 0xff, sizeof (GstTocEntry));
 #endif
 
-  g_slice_free (GstTocEntry, entry);
+  g_free (entry);
 }
 
 static GstTocEntry *
diff --git a/gst/gsttocsetter.c b/gst/gsttocsetter.c
index c746f23..5be2a0b 100644
--- a/gst/gsttocsetter.c
+++ b/gst/gsttocsetter.c
@@ -78,7 +78,7 @@ gst_toc_data_free (gpointer p)
 
   g_mutex_clear (&data->lock);
 
-  g_slice_free (GstTocData, data);
+  g_free (data);
 }
 
 static GstTocData *
@@ -94,7 +94,7 @@ gst_toc_setter_get_data (GstTocSetter * setter)
     g_mutex_lock (&create_mutex);
     data = g_object_get_qdata (G_OBJECT (setter), gst_toc_key);
     if (!data) {
-      data = g_slice_new (GstTocData);
+      data = g_new (GstTocData, 1);
       g_mutex_init (&data->lock);
       data->toc = NULL;
       g_object_set_qdata_full (G_OBJECT (setter), gst_toc_key, data,
diff --git a/gst/gsttracerutils.c b/gst/gsttracerutils.c
index 07f7490..eccf660 100644
--- a/gst/gsttracerutils.c
+++ b/gst/gsttracerutils.c
@@ -100,7 +100,21 @@ _priv_gst_tracing_init (void)
     while (t[i]) {
       // check t[i] for params
       if ((params = strchr (t[i], '('))) {
-        gchar *end = strchr (&params[1], ')');
+        // params can contain multiple '(' when using this kind of parameter: 'max-buffer-size=(uint)5'
+        guint n_par = 1, j;
+        gchar *end = NULL;
+
+        for (j = 1; params[j] != '\0'; j++) {
+          if (params[j] == '(')
+            n_par++;
+          else if (params[j] == ')') {
+            n_par--;
+            if (n_par == 0) {
+              end = &params[j];
+              break;
+            }
+          }
+        }
         *params = '\0';
         params++;
         if (end)
@@ -155,7 +169,7 @@ _priv_gst_tracing_deinit (void)
     for (t_node = h_node->data; t_node; t_node = g_list_next (t_node)) {
       hook = (GstTracerHook *) t_node->data;
       gst_object_unref (hook->tracer);
-      g_slice_free (GstTracerHook, hook);
+      g_free (hook);
     }
     g_list_free (h_node->data);
   }
@@ -169,7 +183,7 @@ gst_tracing_register_hook_id (GstTracer * tracer, GQuark detail, GCallback func)
 {
   gpointer key = GINT_TO_POINTER (detail);
   GList *list = g_hash_table_lookup (_priv_tracers, key);
-  GstTracerHook *hook = g_slice_new0 (GstTracerHook);
+  GstTracerHook *hook = g_new0 (GstTracerHook, 1);
   hook->tracer = gst_object_ref (tracer);
   hook->func = func;
 
diff --git a/gst/gsttypefind.c b/gst/gsttypefind.c
index bd48bf2..3ec16a6 100644
--- a/gst/gsttypefind.c
+++ b/gst/gsttypefind.c
@@ -115,7 +115,7 @@ gst_type_find_register (GstPlugin * plugin, const gchar * name, guint rank,
  * the stream. The returned memory is valid until the typefinding function
  * returns and must not be freed.
  *
- * Returns: (transfer none) (array length=size) (nullable): the
+ * Returns: (transfer none) (nullable): the
  *     requested data, or %NULL if that data is not available.
  */
 const guint8 *
diff --git a/gst/gsturi.c b/gst/gsturi.c
index ae1fb72..b071de7 100644
--- a/gst/gsturi.c
+++ b/gst/gsturi.c
@@ -564,8 +564,12 @@ search_by_entry (GstPluginFeature * feature, gpointer search_entry)
 static gint
 sort_by_rank (GstPluginFeature * first, GstPluginFeature * second)
 {
-  return gst_plugin_feature_get_rank (second) -
+  int diff = gst_plugin_feature_get_rank (second) -
       gst_plugin_feature_get_rank (first);
+  if (diff == 0)
+    diff = g_strcmp0 (gst_plugin_feature_get_name (first),
+        gst_plugin_feature_get_name (second));
+  return diff;
 }
 
 static GList *
@@ -1004,7 +1008,7 @@ _gst_uri_new (void)
 
   g_return_val_if_fail (gst_is_initialized (), NULL);
 
-  uri = GST_URI_CAST (g_slice_new0 (GstUri));
+  uri = g_new0 (GstUri, 1);
 
   if (uri)
     gst_mini_object_init (GST_MINI_OBJECT_CAST (uri), 0, gst_uri_get_type (),
@@ -1031,7 +1035,7 @@ _gst_uri_free (GstUri * uri)
   memset (uri, 0xff, sizeof (*uri));
 #endif
 
-  g_slice_free1 (sizeof (*uri), uri);
+  g_free (uri);
 }
 
 static GHashTable *
@@ -1994,10 +1998,13 @@ gst_uri_make_writable (GstUri * uri)
 }
 
 /**
- * gst_uri_to_string:
- * @uri: This #GstUri to convert to a string.
+ * gst_uri_to_string_with_keys:
+ * @uri: (nullable): This #GstUri to convert to a string.
+ * @keys: (transfer none) (nullable) (element-type utf8): A GList containing
+ *   the query argument key strings.
  *
- * Convert the URI to a string.
+ * Convert the URI to a string, with the query arguments in a specific order.
+ * Only the keys in the @keys list will be added to the resulting string.
  *
  * Returns the URI as held in this object as a #gchar* nul-terminated string.
  * The caller should g_free() the string once they are finished with it.
@@ -2005,10 +2012,10 @@ gst_uri_make_writable (GstUri * uri)
  *
  * Returns: (transfer full): The string version of the URI.
  *
- * Since: 1.6
+ * Since: 1.24
  */
 gchar *
-gst_uri_to_string (const GstUri * uri)
+gst_uri_to_string_with_keys (const GstUri * uri, const GList * keys)
 {
   GString *uri_str;
   gchar *escaped;
@@ -2052,10 +2059,15 @@ gst_uri_to_string (const GstUri * uri)
   }
 
   if (uri->query) {
-    g_string_append (uri_str, "?");
-    escaped = gst_uri_get_query_string (uri);
-    g_string_append (uri_str, escaped);
-    g_free (escaped);
+    if (keys != NULL)
+      escaped = gst_uri_get_query_string_ordered (uri, keys);
+    else
+      escaped = gst_uri_get_query_string (uri);
+    if (escaped) {
+      g_string_append (uri_str, "?");
+      g_string_append (uri_str, escaped);
+      g_free (escaped);
+    }
   }
 
   if (uri->fragment != NULL) {
@@ -2067,6 +2079,26 @@ gst_uri_to_string (const GstUri * uri)
   return g_string_free (uri_str, FALSE);
 }
 
+/**
+ * gst_uri_to_string:
+ * @uri: This #GstUri to convert to a string.
+ *
+ * Convert the URI to a string.
+ *
+ * Returns the URI as held in this object as a #gchar* nul-terminated string.
+ * The caller should g_free() the string once they are finished with it.
+ * The string is put together as described in RFC 3986.
+ *
+ * Returns: (transfer full): The string version of the URI.
+ *
+ * Since: 1.6
+ */
+gchar *
+gst_uri_to_string (const GstUri * uri)
+{
+  return gst_uri_to_string_with_keys (uri, NULL);
+}
+
 /**
  * gst_uri_is_normalized:
  * @uri: (nullable): The #GstUri to test to see if it is normalized.
@@ -2636,6 +2668,67 @@ gst_uri_set_query_string (GstUri * uri, const gchar * query)
   return TRUE;
 }
 
+/**
+ * gst_uri_get_query_string_ordered:
+ * @uri: (nullable): The #GstUri to get the query string from.
+ * @keys: (transfer none) (nullable) (element-type utf8): A GList containing the
+ *   query argument key strings.
+ *
+ * Get a percent encoded URI query string from the @uri, with query parameters
+ * in the order provided by the @keys list. Only parameter keys in the list will
+ * be added to the resulting URI string. This method can be used by retrieving
+ * the keys with gst_uri_get_query_keys() and then sorting the list, for
+ * example.
+ *
+ * Returns: (transfer full) (nullable): A percent encoded query string. Use
+ * g_free() when no longer needed.
+ *
+ * Since: 1.24
+ */
+gchar *
+gst_uri_get_query_string_ordered (const GstUri * uri, const GList * keys)
+{
+  const gchar *sep = "";
+  gchar *escaped;
+  GString *ret = NULL;
+  const GList *key;
+
+  if (!uri)
+    return NULL;
+  g_return_val_if_fail (GST_IS_URI (uri), NULL);
+  if (!uri->query)
+    return NULL;
+
+  for (key = keys; key; key = key->next) {
+    const gchar *query_key = key->data;
+    const gchar *arg;
+
+    /* Key isn't present, skip */
+    if (!g_hash_table_contains (uri->query, query_key))
+      continue;
+
+    if (ret == NULL)
+      ret = g_string_new (NULL);
+
+    /* Append the key */
+    g_string_append (ret, sep);
+    escaped = _gst_uri_escape_http_query_element (query_key);
+    g_string_append (ret, escaped);
+    g_free (escaped);
+
+    if ((arg = g_hash_table_lookup (uri->query, query_key))) {
+      /* Append the argument */
+      escaped = _gst_uri_escape_http_query_element (arg);
+      g_string_append_printf (ret, "=%s", escaped);
+      g_free (escaped);
+    }
+    sep = "&";
+  }
+
+  /* If no keys were seen, return NULL string instead of empty string */
+  return ret ? g_string_free (ret, FALSE) : NULL;
+}
+
 /**
  * gst_uri_get_query_table:
  * @uri: (nullable): The #GstUri to get the query table from.
diff --git a/gst/gsturi.h b/gst/gsturi.h
index 8c5881b..543718d 100644
--- a/gst/gsturi.h
+++ b/gst/gsturi.h
@@ -259,6 +259,9 @@ GstUri * gst_uri_make_writable         (GstUri * uri) G_GNUC_WARN_UNUSED_RESULT;
 GST_API
 gchar *  gst_uri_to_string             (const GstUri * uri) G_GNUC_MALLOC;
 
+GST_API
+gchar * gst_uri_to_string_with_keys    (const GstUri * uri, const GList *keys);
+
 GST_API
 gboolean gst_uri_is_normalized         (const GstUri * uri);
 
@@ -316,6 +319,9 @@ gboolean gst_uri_append_path_segment   (GstUri * uri,
 GST_API
 gchar * gst_uri_get_query_string       (const GstUri * uri);
 
+GST_API
+gchar * gst_uri_get_query_string_ordered (const GstUri * uri, const GList *keys);
+
 GST_API
 gboolean gst_uri_set_query_string      (GstUri * uri, const gchar * query);
 
diff --git a/gst/gstutils.c b/gst/gstutils.c
index 2ea7f33..99e95dd 100644
--- a/gst/gstutils.c
+++ b/gst/gstutils.c
@@ -199,7 +199,8 @@ gst_util_set_object_arg (GObject * object, const gchar * name,
 
   value_type = pspec->value_type;
 
-  GST_DEBUG ("pspec->flags is %d, pspec->value_type is %s",
+  GST_CAT_DEBUG_OBJECT (GST_CAT_PARAMS, object,
+      "pspec->flags is %d, pspec->value_type is %s",
       pspec->flags, g_type_name (value_type));
 
   if (!(pspec->flags & G_PARAM_WRITABLE))
@@ -1145,9 +1146,8 @@ gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
-  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
-      "finding pad in %s compatible with %s:%s",
-      GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad));
+  GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+      "finding pad compatible with %s:%s", GST_DEBUG_PAD_NAME (pad));
 
   g_return_val_if_fail (GST_PAD_PEER (pad) == NULL, NULL);
 
@@ -1173,8 +1173,8 @@ gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
 
         current = g_value_get_object (&padptr);
 
-        GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examining pad %s:%s",
-            GST_DEBUG_PAD_NAME (current));
+        GST_CAT_LOG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+            "examining pad %s:%s", GST_DEBUG_PAD_NAME (current));
 
         if (GST_PAD_IS_SRC (current)) {
           srcpad = current;
@@ -1204,7 +1204,7 @@ gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
           gst_caps_unref (intersection);
 
           if (compatible) {
-            GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
+            GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
                 "found existing unlinked compatible pad %s:%s",
                 GST_DEBUG_PAD_NAME (current));
             gst_iterator_free (pads);
@@ -1218,7 +1218,8 @@ gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
           }
         } else {
           GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
-              "already linked or cannot be linked (peer = %p)", peer);
+              "already linked or cannot be linked (peer = %" GST_PTR_FORMAT ")",
+              peer);
         }
         GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unreffing pads");
 
@@ -1262,7 +1263,7 @@ gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
   gst_object_unref (templ);
 
   if (foundpad) {
-    GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
+    GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
         "found existing request pad %s:%s", GST_DEBUG_PAD_NAME (foundpad));
     return foundpad;
   }
@@ -1618,13 +1619,15 @@ prepare_link_maybe_ghosting (GstPad ** src, GstPad ** sink,
   e2 = GST_OBJECT_PARENT (*sink);
 
   if (G_UNLIKELY (e1 == NULL)) {
-    GST_WARNING ("Trying to ghost a pad that doesn't have a parent: %"
-        GST_PTR_FORMAT, *src);
+    GST_CAT_WARNING (GST_CAT_ELEMENT_PADS,
+        "Trying to ghost a pad that doesn't have a parent: %" GST_PTR_FORMAT,
+        *src);
     return FALSE;
   }
   if (G_UNLIKELY (e2 == NULL)) {
-    GST_WARNING ("Trying to ghost a pad that doesn't have a parent: %"
-        GST_PTR_FORMAT, *sink);
+    GST_CAT_WARNING (GST_CAT_ELEMENT_PADS,
+        "Trying to ghost a pad that doesn't have a parent: %" GST_PTR_FORMAT,
+        *sink);
     return FALSE;
   }
 
@@ -2158,7 +2161,7 @@ gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
 
     capsfilter = gst_element_factory_make ("capsfilter", NULL);
     if (!capsfilter) {
-      GST_ERROR ("Could not make a capsfilter");
+      GST_CAT_ERROR (GST_CAT_ELEMENT_PADS, "Could not make a capsfilter");
       return FALSE;
     }
 
@@ -2168,7 +2171,7 @@ gst_element_link_pads_filtered (GstElement * src, const gchar * srcpadname,
     gst_element_get_state (GST_ELEMENT_CAST (parent), &state, &pending, 0);
 
     if (!gst_bin_add (GST_BIN (parent), capsfilter)) {
-      GST_ERROR ("Could not add capsfilter");
+      GST_CAT_ERROR (GST_CAT_ELEMENT_PADS, "Could not add capsfilter");
       gst_object_unref (parent);
       return FALSE;
     }
@@ -2327,15 +2330,16 @@ gst_element_unlink_pads (GstElement * src, const gchar * srcpadname,
     if ((srcpad = gst_element_request_pad_simple (src, srcpadname)))
       srcrequest = TRUE;
   if (srcpad == NULL) {
-    GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname);
+    GST_CAT_WARNING_OBJECT (GST_CAT_ELEMENT_PADS, src,
+        "source element has no pad \"%s\"", srcpadname);
     return;
   }
   if (!(destpad = gst_element_get_static_pad (dest, destpadname)))
     if ((destpad = gst_element_request_pad_simple (dest, destpadname)))
       destrequest = TRUE;
   if (destpad == NULL) {
-    GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"",
-        destpadname);
+    GST_CAT_WARNING_OBJECT (GST_CAT_ELEMENT_PADS, dest,
+        "destination element has no pad \"%s\"", destpadname);
     goto free_src;
   }
 
@@ -2813,9 +2817,11 @@ query_caps_func (GstPad * pad, QueryCapsData * data)
     GstCaps *peercaps, *intersection;
 
     gst_query_parse_caps_result (data->query, &peercaps);
-    GST_DEBUG_OBJECT (pad, "intersect with result %" GST_PTR_FORMAT, peercaps);
+    GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+        "intersect with result %" GST_PTR_FORMAT, peercaps);
     intersection = gst_caps_intersect (data->ret, peercaps);
-    GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, intersection);
+    GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+        "intersected %" GST_PTR_FORMAT, intersection);
 
     gst_caps_unref (data->ret);
     data->ret = intersection;
@@ -3194,7 +3200,7 @@ gst_pad_query_accept_caps (GstPad * pad, GstCaps * caps)
   query = gst_query_new_accept_caps (caps);
   if (gst_pad_query (pad, query)) {
     gst_query_parse_accept_caps_result (query, &res);
-    GST_DEBUG_OBJECT (pad, "query returned %d", res);
+    GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "query returned %d", res);
   }
   gst_query_unref (query);
 
@@ -3223,7 +3229,7 @@ gst_pad_peer_query_accept_caps (GstPad * pad, GstCaps * caps)
   query = gst_query_new_accept_caps (caps);
   if (gst_pad_peer_query (pad, query)) {
     gst_query_parse_accept_caps_result (query, &res);
-    GST_DEBUG_OBJECT (pad, "query returned %d", res);
+    GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "query returned %d", res);
   }
   gst_query_unref (query);
 
@@ -3256,14 +3262,14 @@ element_find_unlinked_pad (GstElement * element, GstPadDirection direction)
         GstPad *peer;
         GstPad *pad = g_value_get_object (&data);
 
-        GST_CAT_LOG (GST_CAT_ELEMENT_PADS, "examining pad %s:%s",
-            GST_DEBUG_PAD_NAME (pad));
+        GST_CAT_LOG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+            "examining pad %s:%s", GST_DEBUG_PAD_NAME (pad));
 
         peer = gst_pad_get_peer (pad);
         if (peer == NULL) {
           unlinked_pad = gst_object_ref (pad);
           done = TRUE;
-          GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,
+          GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
               "found existing unlinked pad %s:%s",
               GST_DEBUG_PAD_NAME (unlinked_pad));
         } else {
@@ -3523,15 +3529,12 @@ gst_parse_bin_from_description_full (const gchar * bin_description,
 GstClockTime
 gst_util_get_timestamp (void)
 {
-#if defined (HAVE_POSIX_TIMERS) && defined(HAVE_MONOTONIC_CLOCK) &&\
-    defined (HAVE_CLOCK_GETTIME)
-  struct timespec now;
-
-  clock_gettime (CLOCK_MONOTONIC, &now);
-  return GST_TIMESPEC_TO_TIME (now);
+#if defined(G_OS_WIN32) && !defined(GST_STATIC_COMPILATION)
+  /* priv_gst_clock_init() is called in DllMain */
 #else
-  return g_get_monotonic_time () * 1000;
+  priv_gst_clock_init ();
 #endif
+  return priv_gst_get_monotonic_time ();
 }
 
 /**
@@ -3671,6 +3674,73 @@ gst_util_greatest_common_divisor_int64 (gint64 a, gint64 b)
   return ABS (a);
 }
 
+/**
+ * gst_util_simplify_fraction:
+ * @numerator: First value as #gint
+ * @denominator: Second value as #gint
+ * @n_terms: non-significative terms (typical value: 8)
+ * @threshold: threshold (typical value: 333)
+ *
+ * Calculates the simpler representation of @numerator and @denominator and
+ * update both values with the resulting simplified fraction.
+ *
+ * Simplify a fraction using a simple continued fraction decomposition.
+ * The idea here is to convert fractions such as 333333/10000000 to 1/30
+ * using 32 bit arithmetic only. The algorithm is not perfect and relies
+ * upon two arbitrary parameters to remove non-significative terms from
+ * the simple continued fraction decomposition. Using 8 and 333 for
+ * @n_terms and @threshold respectively seems to give nice results.
+ *
+ * Since: 1.24
+ */
+void
+gst_util_simplify_fraction (gint * numerator, gint * denominator,
+    guint n_terms, guint threshold)
+{
+  guint *an;
+  guint x, y, r;
+  guint i, n;
+
+  an = g_malloc_n (n_terms, sizeof (*an));
+  if (an == NULL)
+    return;
+
+  /*
+   * Convert the fraction to a simple continued fraction. See
+   * https://en.wikipedia.org/wiki/Continued_fraction
+   * Stop if the current term is bigger than or equal to the given
+   * threshold.
+   */
+  x = *numerator;
+  y = *denominator;
+
+  for (n = 0; n < n_terms && y != 0; ++n) {
+    an[n] = x / y;
+    if (an[n] >= threshold) {
+      if (n < 2)
+        n++;
+      break;
+    }
+
+    r = x - an[n] * y;
+    x = y;
+    y = r;
+  }
+
+  /* Expand the simple continued fraction back to an integer fraction. */
+  x = 0;
+  y = 1;
+
+  for (i = n; i > 0; --i) {
+    r = y;
+    y = an[i - 1] * y + x;
+    x = r;
+  }
+
+  *numerator = y;
+  *denominator = x;
+  g_free (an);
+}
 
 /**
  * gst_util_fraction_to_double:
@@ -3968,28 +4038,16 @@ gst_util_fraction_compare (gint a_n, gint a_d, gint b_n, gint b_d)
 }
 
 static gchar *
-gst_pad_create_stream_id_internal (GstPad * pad, GstElement * parent,
+gst_element_decorate_stream_id_internal (GstElement * element,
     const gchar * stream_id)
 {
   GstEvent *upstream_event;
   gchar *upstream_stream_id = NULL, *new_stream_id;
   GstPad *sinkpad;
 
-  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
-  g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
-  g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
-
-  g_return_val_if_fail (parent->numsinkpads <= 1, NULL);
-
-  /* If the element has multiple source pads it must
-   * provide a stream-id for every source pad, otherwise
-   * all source pads will have the same and are not
-   * distinguishable */
-  g_return_val_if_fail (parent->numsrcpads <= 1 || stream_id, NULL);
-
   /* First try to get the upstream stream-start stream-id from the sinkpad.
    * This will only work for non-source elements */
-  sinkpad = gst_element_get_static_pad (parent, "sink");
+  sinkpad = gst_element_get_static_pad (element, "sink");
   if (sinkpad) {
     upstream_event =
         gst_pad_get_sticky_event (sinkpad, GST_EVENT_STREAM_START, 0);
@@ -4013,7 +4071,7 @@ gst_pad_create_stream_id_internal (GstPad * pad, GstElement * parent,
     /* Try to generate one from the URI query and
      * if it fails take a random number instead */
     query = gst_query_new_uri ();
-    if (gst_element_query (parent, query)) {
+    if (gst_element_query (element, query)) {
       gst_query_parse_uri (query, &uri);
     }
 
@@ -4028,7 +4086,7 @@ gst_pad_create_stream_id_internal (GstPad * pad, GstElement * parent,
       g_checksum_free (cs);
     } else {
       /* Just get some random number if the URI query fails */
-      GST_FIXME_OBJECT (pad, "Creating random stream-id, consider "
+      GST_FIXME_OBJECT (element, "Creating random stream-id, consider "
           "implementing a deterministic way of creating a stream-id");
       upstream_stream_id =
           g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
@@ -4049,6 +4107,139 @@ gst_pad_create_stream_id_internal (GstPad * pad, GstElement * parent,
   return new_stream_id;
 }
 
+/**
+ * gst_element_decorate_stream_id_printf_valist:
+ * @element: The  #GstElement to create a stream-id for
+ * @format: (not nullable): The stream-id
+ * @var_args: parameters for the @format string
+ *
+ * Creates a stream-id for @element by combining the upstream information with
+ * the @format.
+ *
+ * This function generates an unique stream-id by getting the upstream
+ * stream-start event stream ID and appending @format to it. If the element
+ * has no sinkpad it will generate an upstream stream-id by doing an URI query
+ * on the element and in the worst case just uses a random number. Source
+ * elements that don't implement the URI handler interface should ideally
+ * generate a unique, deterministic stream-id manually instead.
+ *
+ * Since stream IDs are sorted alphabetically, any numbers in the stream ID
+ * should be printed with a fixed number of characters, preceded by 0's, such as
+ * by using the format \%03u instead of \%u.
+ *
+ * Returns: (transfer full): A stream-id for @element.
+ *
+ * Since: 1.24
+ */
+gchar *
+gst_element_decorate_stream_id_printf_valist (GstElement * element,
+    const gchar * format, va_list var_args)
+{
+  gchar *stream_id, *res;
+
+  g_return_val_if_fail (format, NULL);
+
+  stream_id = g_strdup_vprintf (format, var_args);
+
+  res = gst_element_decorate_stream_id_internal (element, stream_id);
+
+  g_free (stream_id);
+
+  return res;
+}
+
+/**
+ * gst_element_decorate_stream_id_printf:
+ * @element: The  #GstElement to create a stream-id for
+ * @format: (not nullable): The stream-id
+ *
+ * Creates a stream-id for @element by combining the upstream information with
+ * the @format.
+ *
+ * This function generates an unique stream-id by getting the upstream
+ * stream-start event stream ID and appending the stream-id to it. If the element
+ * has no sinkpad it will generate an upstream stream-id by doing an URI query
+ * on the element and in the worst case just uses a random number. Source
+ * elements that don't implement the URI handler interface should ideally
+ * generate a unique, deterministic stream-id manually instead.
+ *
+ * Since stream IDs are sorted alphabetically, any numbers in the stream ID
+ * should be printed with a fixed number of characters, preceded by 0's, such as
+ * by using the format \%03u instead of \%u.
+ *
+ * Returns: (transfer full): A stream-id for @element.
+ *
+ * Since: 1.24
+ */
+gchar *
+gst_element_decorate_stream_id_printf (GstElement * element,
+    const gchar * format, ...)
+{
+  gchar *res;
+  va_list var_args;
+
+  g_return_val_if_fail (format, NULL);
+
+  va_start (var_args, format);
+  res =
+      gst_element_decorate_stream_id_printf_valist (element, format, var_args);
+  va_end (var_args);
+
+  return res;
+}
+
+
+/**
+ * gst_element_decorate_stream_id:
+ * @element: The  #GstElement to create a stream-id for
+ * @stream_id: (not nullable): The stream-id
+ *
+ * Creates a stream-id for @element by combining the upstream information with
+ * the @stream_id.
+ *
+ * This function generates an unique stream-id by getting the upstream
+ * stream-start event stream ID and appending @stream_id to it. If the element
+ * has no sinkpad it will generate an upstream stream-id by doing an URI query
+ * on the element and in the worst case just uses a random number. Source
+ * elements that don't implement the URI handler interface should ideally
+ * generate a unique, deterministic stream-id manually instead.
+ *
+ * Since stream IDs are sorted alphabetically, any numbers in the stream ID
+ * should be printed with a fixed number of characters, preceded by 0's, such as
+ * by using the format \%03u instead of \%u.
+ *
+ * Returns: (transfer full): A stream-id for @element.
+ *
+ * Since: 1.24
+ */
+gchar *
+gst_element_decorate_stream_id (GstElement * element, const gchar * stream_id)
+{
+  g_return_val_if_fail (stream_id, NULL);
+  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+
+  return gst_element_decorate_stream_id_internal (element, stream_id);
+}
+
+static gchar *
+gst_pad_create_stream_id_internal (GstPad * pad, GstElement * parent,
+    const gchar * stream_id)
+{
+  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+  g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
+  g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
+
+  g_return_val_if_fail (parent->numsinkpads <= 1, NULL);
+
+  /* If the element has multiple source pads it must
+   * provide a stream-id for every source pad, otherwise
+   * all source pads will have the same and are not
+   * distinguishable */
+  g_return_val_if_fail (parent->numsrcpads <= 1 || stream_id, NULL);
+
+  return gst_element_decorate_stream_id_internal (parent, stream_id);
+}
+
 /**
  * gst_pad_create_stream_id_printf_valist:
  * @pad: A source #GstPad
@@ -4192,9 +4383,10 @@ gst_pad_get_stream_id (GstPad * pad)
     gst_event_parse_stream_start (event, &stream_id);
     ret = g_strdup (stream_id);
     gst_event_unref (event);
-    GST_LOG_OBJECT (pad, "pad has stream-id '%s'", ret);
+    GST_CAT_LOG_OBJECT (GST_CAT_PADS, pad, "pad has stream-id '%s'", ret);
   } else {
-    GST_DEBUG_OBJECT (pad, "pad has not received a stream-start event yet");
+    GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+        "pad has not received a stream-start event yet");
   }
 
   return ret;
@@ -4227,9 +4419,10 @@ gst_pad_get_stream (GstPad * pad)
   if (event != NULL) {
     gst_event_parse_stream (event, &stream);
     gst_event_unref (event);
-    GST_LOG_OBJECT (pad, "pad has stream object %p", stream);
+    GST_CAT_LOG_OBJECT (GST_CAT_PADS, pad, "pad has stream object %p", stream);
   } else {
-    GST_DEBUG_OBJECT (pad, "pad has not received a stream-start event yet");
+    GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+        "pad has not received a stream-start event yet");
   }
 
   return stream;
@@ -4261,10 +4454,15 @@ gst_util_group_id_next (void)
   return ret;
 }
 
-/* Compute log2 of the passed 64-bit number by finding the highest set bit */
+/* Compute the number of bits needed at least to store `in` */
 static guint
-gst_log2 (GstClockTime in)
+gst_bit_storage_uint64 (guint64 in)
 {
+#if defined(__GNUC__) && __GNUC__ >= 4
+  return in ? 64 - __builtin_clzll (in) : 1;
+#else
+  /* integer log2(v) from:
+     <http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog> */
   const guint64 b[] =
       { 0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000LL };
   const guint64 S[] = { 1, 2, 4, 8, 16, 32 };
@@ -4278,7 +4476,46 @@ gst_log2 (GstClockTime in)
     }
   }
 
-  return count;
+  return count + 1;             // + 1 to get the number of storage bits needed
+#endif
+}
+
+/**
+ * gst_util_ceil_log2:
+ * @v: a #guint32 value.
+ *
+ * Returns smallest integral value not less than log2(v).
+ *
+ * Returns: a computed #guint val.
+ *
+ * Since: 1.24
+ */
+guint
+gst_util_ceil_log2 (guint32 v)
+{
+  static const unsigned int t[6] = {
+    0x00000000ull,
+    0xFFFF0000ull,
+    0x0000FF00ull,
+    0x000000F0ull,
+    0x0000000Cull,
+    0x000000002ull
+  };
+
+  g_return_val_if_fail (v != 0, -1);
+
+  int y = (((v & (v - 1)) == 0) ? 0 : 1);
+  int j = 32;
+  int i;
+
+  for (i = 0; i < 6; i++) {
+    int k = (((v & t[i]) == 0) ? 0 : j);
+    y += k;
+    v >>= k;
+    j >>= 1;
+  }
+
+  return y;
 }
 
 /**
@@ -4411,10 +4648,20 @@ gst_calculate_linear_regression (const GstClockTime * xy,
    */
 
   /* Guess how many bits we might need for the usual distribution of input,
-   * with a fallback loop that drops precision if things go pear-shaped */
-  max_bits = gst_log2 (MAX (xmax - xmin, ymax - ymin)) * 7 / 8 + gst_log2 (n);
-  if (max_bits > 64)
-    pshift = max_bits - 64;
+   * with a fallback loop that drops precision if things go pear-shaped.
+   *
+   * Each calculation of tmp during the iteration is multiplying two numbers and
+   * then adding them together, or adding them together and then multiplying
+   * them. The second case is worse and means we need at least twice
+   * (multiplication) as many bits as the biggest number needs, plus another bit
+   * (addition). At most 63 bits (signed 64 bit integer) are available.
+   *
+   * That means that each number must require at most (63 - 1) / 2 bits = 31
+   * bits of storage.
+   */
+  max_bits = gst_bit_storage_uint64 (MAX (1, MAX (xmax - xmin, ymax - ymin)));
+  if (max_bits > 31)
+    pshift = max_bits - 31;
 
   i = 0;
   do {
@@ -4566,7 +4813,7 @@ gboolean
 gst_type_is_plugin_api (GType type, GstPluginAPIFlags * flags)
 {
   gboolean ret =
-      ! !GPOINTER_TO_INT (g_type_get_qdata (type, GST_QUARK (PLUGIN_API)));
+      !!GPOINTER_TO_INT (g_type_get_qdata (type, GST_QUARK (PLUGIN_API)));
 
   if (ret && flags) {
     *flags =
@@ -4575,3 +4822,39 @@ gst_type_is_plugin_api (GType type, GstPluginAPIFlags * flags)
 
   return ret;
 }
+
+/**
+ * gst_util_filename_compare:
+ * @a: (type filename): a filename to compare with @b
+ * @b: (type filename): a filename to compare with @a
+ *
+ * Compares the given filenames using natural ordering.
+ *
+ * Since: 1.24
+ */
+gint
+gst_util_filename_compare (const gchar * a, const gchar * b)
+{
+  gchar *a_utf8, *b_utf8;
+  gchar *a1, *b1;
+  gint ret;
+
+  /* Filenames in GLib are only guaranteed to be UTF-8 on Windows */
+  a_utf8 = g_filename_to_utf8 (a, -1, NULL, NULL, NULL);
+  b_utf8 = g_filename_to_utf8 (b, -1, NULL, NULL, NULL);
+
+  if (a_utf8 == NULL || b_utf8 == NULL) {
+    return strcmp (a, b);
+  }
+
+  a1 = g_utf8_collate_key_for_filename (a_utf8, -1);
+  b1 = g_utf8_collate_key_for_filename (b_utf8, -1);
+  ret = strcmp (a1, b1);
+  g_free (a1);
+  g_free (b1);
+
+  g_free (a_utf8);
+  g_free (b_utf8);
+
+  return ret;
+}
diff --git a/gst/gstutils.h b/gst/gstutils.h
index 2957569..f42dab8 100644
--- a/gst/gstutils.h
+++ b/gst/gstutils.h
@@ -1034,6 +1034,17 @@ gboolean                gst_element_seek_simple         (GstElement   *element,
                                                          GstSeekFlags  seek_flags,
                                                          gint64        seek_pos);
 
+GST_API
+gchar *                 gst_element_decorate_stream_id  (GstElement   *element,
+                                                         const gchar  *stream_id);
+GST_API
+gchar *   gst_element_decorate_stream_id_printf_valist  (GstElement * element,
+                                                         const gchar * format,
+                                                         va_list var_args) G_GNUC_PRINTF (2, 0) G_GNUC_MALLOC;
+GST_API
+gchar *          gst_element_decorate_stream_id_printf  (GstElement * element,
+                                                         const gchar * format,
+                                                         ...) G_GNUC_PRINTF (2, 3) G_GNUC_MALLOC;
 /* util elementfactory functions */
 
 GST_API
@@ -1197,6 +1208,10 @@ gint          gst_util_greatest_common_divisor  (gint a, gint b);
 GST_API
 gint64        gst_util_greatest_common_divisor_int64 (gint64 a, gint64 b);
 
+GST_API
+void          gst_util_simplify_fraction        (gint *numerator, gint *denominator,
+                                                 guint n_terms, guint threshold);
+
 GST_API
 void          gst_util_fraction_to_double       (gint src_n, gint src_d, gdouble *dest);
 
@@ -1225,6 +1240,12 @@ void          gst_type_mark_as_plugin_api       (GType type, GstPluginAPIFlags f
 GST_API
 gboolean      gst_type_is_plugin_api            (GType type, GstPluginAPIFlags *flags);
 
+GST_API
+guint         gst_util_ceil_log2                (guint32 v);
+
+GST_API
+gint          gst_util_filename_compare        (const gchar *a, const gchar *b);
+
 G_END_DECLS
 
 #endif /* __GST_UTILS_H__ */
diff --git a/gst/gstvalue.c b/gst/gstvalue.c
index cf256fc..315bcfb 100644
--- a/gst/gstvalue.c
+++ b/gst/gstvalue.c
@@ -369,7 +369,8 @@ _priv_gst_value_serialize_any_list (const GValue * value, const gchar * begin,
       s_val = gst_value_serialize (v);
     } else {
       if (GST_VALUE_HOLDS_STRUCTURE (v))
-        s_val = gst_structure_serialize (gst_value_get_structure (v), flags);
+        s_val =
+            gst_structure_serialize_full (gst_value_get_structure (v), flags);
       else if (GST_VALUE_HOLDS_CAPS (v))
         s_val = gst_caps_serialize (gst_value_get_caps (v), flags);
     }
@@ -1527,7 +1528,7 @@ gst_value_deserialize_int_range (GValue * dest, const gchar * s)
 static void
 gst_value_init_int64_range (GValue * value)
 {
-  gint64 *vals = g_slice_alloc0 (3 * sizeof (gint64));
+  gint64 *vals = g_malloc0 (3 * sizeof (gint64));
   value->data[0].v_pointer = vals;
   INT64_RANGE_MIN (value) = 0;
   INT64_RANGE_MAX (value) = 0;
@@ -1538,7 +1539,7 @@ static void
 gst_value_free_int64_range (GValue * value)
 {
   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
-  g_slice_free1 (3 * sizeof (gint64), value->data[0].v_pointer);
+  g_free (value->data[0].v_pointer);
   value->data[0].v_pointer = NULL;
 }
 
@@ -1913,7 +1914,7 @@ gst_value_init_fraction_range (GValue * value)
 
   ftype = GST_TYPE_FRACTION;
 
-  value->data[0].v_pointer = vals = g_slice_alloc0 (2 * sizeof (GValue));
+  value->data[0].v_pointer = vals = g_malloc0 (2 * sizeof (GValue));
   g_value_init (&vals[0], ftype);
   g_value_init (&vals[1], ftype);
 }
@@ -1927,7 +1928,7 @@ gst_value_free_fraction_range (GValue * value)
     /* we know the two values contain fractions without internal allocs */
     /* g_value_unset (&vals[0]); */
     /* g_value_unset (&vals[1]); */
-    g_slice_free1 (2 * sizeof (GValue), vals);
+    g_free (vals);
     value->data[0].v_pointer = NULL;
   }
 }
@@ -4808,6 +4809,104 @@ out:
   return ret;
 }
 
+static gboolean
+gst_value_union_fraction_fraction_range (GValue * dest, const GValue * src1,
+    const GValue * src2)
+{
+  GValue *vals;
+  int f_n, f_d, fr_start_n, fr_start_d, fr_end_n, fr_end_d;
+
+  g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (src1), FALSE);
+  g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (src2), FALSE);
+
+  /* Fraction */
+  f_n = src1->data[0].v_int;
+  f_d = src1->data[1].v_int;
+
+  vals = src2->data[0].v_pointer;
+  /* Fraction range start */
+  fr_start_n = vals[0].data[0].v_int;
+  fr_start_d = vals[0].data[1].v_int;
+  /* Fraction range end */
+  fr_end_n = vals[1].data[0].v_int;
+  fr_end_d = vals[1].data[1].v_int;
+
+  /* Check if it's already in the range. This is the only case in which we can
+   * successfully perform a union. */
+  if (gst_util_fraction_compare (f_n, f_d, fr_start_n, fr_start_d) >= 0 &&
+      gst_util_fraction_compare (f_n, f_d, fr_end_n, fr_end_d) <= 0) {
+    if (dest)
+      gst_value_init_and_copy (dest, src2);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+gst_value_union_fraction_range_fraction_range (GValue * dest,
+    const GValue * src1, const GValue * src2)
+{
+  GValue *vals1, *vals2;
+  int fr1_start_n, fr1_start_d, fr1_end_n, fr1_end_d;
+  int fr2_start_n, fr2_start_d, fr2_end_n, fr2_end_d;
+  int fr_start_n, fr_start_d, fr_end_n, fr_end_d;
+
+  g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (src1), FALSE);
+  g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (src2), FALSE);
+
+  vals1 = src1->data[0].v_pointer;
+  g_return_val_if_fail (vals1 != NULL, FALSE);
+
+  fr1_start_n = vals1[0].data[0].v_int;
+  fr1_start_d = vals1[0].data[1].v_int;
+  fr1_end_n = vals1[1].data[0].v_int;
+  fr1_end_d = vals1[1].data[1].v_int;
+
+  vals2 = src2->data[0].v_pointer;
+  g_return_val_if_fail (vals2 != NULL, FALSE);
+
+  fr2_start_n = vals2[0].data[0].v_int;
+  fr2_start_d = vals2[0].data[1].v_int;
+  fr2_end_n = vals2[1].data[0].v_int;
+  fr2_end_d = vals2[1].data[1].v_int;
+
+  /* Ranges are completely disjoint: end of one range is less than the start of
+   * other range */
+  if (gst_util_fraction_compare (fr2_end_n, fr2_end_d, fr1_start_n,
+          fr1_start_d) < 0
+      || gst_util_fraction_compare (fr1_end_n, fr1_end_d, fr2_start_n,
+          fr2_start_d) < 0)
+    return FALSE;
+
+  /* Ranges overlap, union is trivial */
+  if (!dest)
+    return TRUE;
+
+  if (gst_util_fraction_compare (fr1_start_n, fr1_start_d, fr2_start_n,
+          fr2_start_d) < 0) {
+    fr_start_n = fr1_start_n;
+    fr_start_d = fr1_start_d;
+  } else {
+    fr_start_n = fr2_start_n;
+    fr_start_d = fr2_start_d;
+  }
+
+  if (gst_util_fraction_compare (fr1_end_n, fr1_end_d, fr2_end_n,
+          fr2_end_d) > 0) {
+    fr_end_n = fr1_end_n;
+    fr_end_d = fr1_end_d;
+  } else {
+    fr_end_n = fr2_end_n;
+    fr_end_d = fr2_end_d;
+  }
+
+  g_value_init (dest, GST_TYPE_FRACTION_RANGE);
+  gst_value_set_fraction_range_full (dest, fr_start_n, fr_start_d, fr_end_n,
+      fr_end_d);
+  return TRUE;
+}
+
 /****************
  * intersection *
  ****************/
@@ -7802,6 +7901,16 @@ gst_value_deserialize_flagset (GValue * dest, const gchar * s)
   if (G_UNLIKELY ((mask == 0 && errno == EINVAL) || cur == next))
     goto try_as_flags_string;
 
+  if (g_str_has_prefix (cur, "0x") || g_str_has_prefix (cur, "0X"))
+    cur += 2;
+
+  /* Flagsets are 32 bits hex numbers, so do not accept any number that has more
+   * then 8 characters. strtoul() accepts unlimited number of leading zeros and
+   * 64bit numbers on 64bit platforms.
+   */
+  if ((next - cur) > 8)
+    return FALSE;
+
   /* Next char should be NULL terminator, or a ':'. If ':', we need the flag string after */
   if (G_UNLIKELY (next[0] == 0)) {
     res = TRUE;
@@ -8342,6 +8451,10 @@ _priv_gst_value_initialize (void)
       gst_value_union_flagset_flagset);
   gst_value_register_union_func (GST_TYPE_STRUCTURE, GST_TYPE_STRUCTURE,
       gst_value_union_structure_structure);
+  gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
+      gst_value_union_fraction_fraction_range);
+  gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
+      GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
 
 #if GST_VERSION_NANO == 1
   /* If building from git master, check starting array sizes matched actual size
@@ -8367,14 +8480,6 @@ _priv_gst_value_initialize (void)
         gst_value_subtract_funcs->len);
   }
 #endif
-
-#if 0
-  /* Implement these if needed */
-  gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
-      gst_value_union_fraction_fraction_range);
-  gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
-      GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
-#endif
 }
 
 static void
diff --git a/gst/meson.build b/gst/meson.build
index 4293c78..7ed2a35 100644
--- a/gst/meson.build
+++ b/gst/meson.build
@@ -40,7 +40,6 @@ gst_sources = files(
   'gstpipeline.c',
   'gstplugin.c',
   'gstpluginfeature.c',
-  'gstpluginloader.c',
   'gstpoll.c',
   'gstpreset.c',
   'gstprotection.c',
@@ -83,6 +82,7 @@ gst_headers = files(
   'gstbufferlist.h',
   'gstbufferpool.h',
   'gstbus.h',
+  'gstbytearrayinterface.h',
   'gstcaps.h',
   'gstcapsfeatures.h',
   'gstchildproxy.h',
@@ -155,6 +155,12 @@ endif
 
 install_headers(gst_headers, subdir : 'gstreamer-1.0/gst')
 
+if host_system == 'windows'
+  gst_sources += files('gstpluginloader-win32.c')
+else
+  gst_sources += files('gstpluginloader.c')
+endif
+
 extra_deps = []
 if host_system == 'android'
   gst_sources += 'gstandroid.c'
@@ -247,6 +253,10 @@ if not tracer_hooks
   libgst_c_args += ['-DGST_DISABLE_GST_TRACER_HOOKS']
 endif
 
+if get_option('gstreamer-static-full')
+  libgst_c_args += ['-DGST_FULL_STATIC_COMPILATION']
+endif
+
 # Make sure that subproject building gir files work
 gst_incdirs = [configinc]
 gst_gen_sources = [gstenum_h]
@@ -262,9 +272,14 @@ libgst = library('gstreamer-1.0', gst_sources,
   link_with : printf_lib,
   install : true,
   dependencies : [gobject_dep, gmodule_dep, glib_dep, mathlib, dl_dep,
-                  backtrace_deps, platform_deps, extra_deps],
+                  backtrace_deps, platform_deps, network_deps, extra_deps],
 )
 
+gst_compile_args = []
+if static_build
+  gst_compile_args += ['-DGST_STATIC_COMPILATION']
+endif
+
 pkg_name = 'gstreamer-1.0'
 library_def = {'lib': libgst}
 pkgconfig.generate(libgst,
@@ -274,6 +289,7 @@ pkgconfig.generate(libgst,
   subdirs : pkgconfig_subdirs,
   name : pkg_name,
   description : 'Streaming media framework',
+  extra_cflags: gst_compile_args,
 )
 
 if build_gir
@@ -308,15 +324,13 @@ if build_gir
   # creating another gir which links against gst-full.
   if not static_build
     gst_gir = gnome.generate_gir(libgst, kwargs: gir)
+    library_def += {'gir_targets':  library_def.get('gir_targets', []) + [gst_gir]}
     gst_gen_sources += gst_gir
   endif
 endif
 gst_libraries += [[pkg_name, library_def]]
 
-gst_compile_args = []
-if get_option('default_library') == 'static'
-  gst_compile_args += ['-DGST_STATIC_COMPILATION']
-endif
+
 
 gst_dep = declare_dependency(link_with : libgst,
   compile_args : gst_compile_args,
diff --git a/gst/parse/grammar.y.in b/gst/parse/grammar.y.in
index d1ed805..fbc36f1 100644
--- a/gst/parse/grammar.y.in
+++ b/gst/parse/grammar.y.in
@@ -65,7 +65,7 @@ link_t *__gst_parse_link_new (void)
 {
   link_t *ret;
   __links++;
-  ret = g_slice_new0 (link_t);
+  ret = g_new0 (link_t, 1);
   /* g_print ("ALLOCATED LINK  (%3u): %p\n", __links, ret); */
   return ret;
 }
@@ -74,7 +74,7 @@ __gst_parse_link_free (link_t *data)
 {
   if (data) {
     /* g_print ("FREEING LINK    (%3u): %p\n", __links - 1, data); */
-    g_slice_free (link_t, data);
+    g_free (data);
     g_return_if_fail (__links > 0);
     __links--;
   }
@@ -84,7 +84,7 @@ __gst_parse_chain_new (void)
 {
   chain_t *ret;
   __chains++;
-  ret = g_slice_new0 (chain_t);
+  ret = g_new0 (chain_t, 1);
   /* g_print ("@%p: ALLOCATED CHAIN (%3u):\n", ret, __chains); */
   return ret;
 }
@@ -92,7 +92,7 @@ void
 __gst_parse_chain_free (chain_t *data)
 {
   /* g_print ("@%p: FREEING CHAIN   (%3u):\n", data, __chains - 1); */
-  g_slice_free (chain_t, data);
+  g_free (data);
   g_return_if_fail (__chains > 0);
   __chains--;
 }
@@ -102,7 +102,7 @@ __gst_parse_element_new (void)
 {
   element_t *ret;
   __elements++;
-  ret = g_slice_new0 (element_t);
+  ret = g_new0 (element_t, 1);
   /* g_print ("@%p: ALLOCATED ELEMENT (%3u):\n", ret, __elements); */
   return ret;
 }
@@ -110,7 +110,7 @@ void
 __gst_parse_element_free (element_t *data)
 {
   /* g_print ("@%p: FREEING ELEMENT   (%3u):\n", data, __elements - 1); */
-  g_slice_free (element_t, data);
+  g_free (data);
   g_return_if_fail (__elements > 0);
   __elements--;
 }
@@ -225,6 +225,66 @@ static void  add_missing_element(graph_t *graph,gchar *name){
     }
 }
 
+static gchar *
+str_unwrap (const gchar * s)
+{
+  gchar *ret;
+  gchar *read, *write;
+
+  /* NULL string returns NULL */
+  if (s == NULL)
+    return NULL;
+
+  /* make copy of original string to hold the result. This
+   * string will always be smaller than the original */
+  ret = g_strdup (s);
+  read = ret;
+  write = ret;
+
+  while (*read) {
+    if (GST_ASCII_IS_STRING (*read)) {
+      /* normal chars are just copied */
+      *write++ = *read++;
+    } else if (*read == '\\') {
+      /* got an escape char, move to next position to read a tripplet
+       * of octal numbers */
+      read++;
+      /* is the next char a possible first octal number? */
+      if (*read >= '0' && *read <= '3') {
+        /* parse other 2 numbers, if one of them is not in the range of
+         * an octal number, we error. We also catch the case where a zero
+         * byte is found here. */
+        if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
+          goto beach;
+
+        /* now convert the octal number to a byte again. */
+        *write++ = ((read[0] - '0') << 6) +
+            ((read[1] - '0') << 3) + (read[2] - '0');
+
+        read += 3;
+      } else {
+        /* if we run into a \0 here, we definitely won't get a quote later */
+        if (*read == 0)
+          goto beach;
+        /* else copy \X sequence */
+        *write++ = *read++;
+      }
+    } else if (*read == '\0') {
+      goto beach;
+    } else {
+      *write++ = *read++;
+    }
+  }
+
+  /* null terminate result string and return */
+  *write = '\0';
+  return ret;
+
+beach:
+  g_free (ret);
+  return NULL;
+}
+
 
 /*******************************************************************************************
 *** helpers for pipeline-setup
@@ -282,49 +342,53 @@ static void gst_parse_free_delayed_set (DelayedSet *set)
 {
   g_free(set->name);
   g_free(set->value_str);
-  g_slice_free(DelayedSet, set);
+  g_free(set);
 }
 
-static void gst_parse_new_child(GstChildProxy *child_proxy, GObject *object,
+static void gst_parse_new_child (GstChildProxy *child_proxy, GObject *object,
     const gchar * name, gpointer data);
 
-static void gst_parse_add_delayed_set (GstElement *element, gchar *name, gchar *value_str)
+static void gst_parse_add_delayed_set (GstChildProxy *proxy, gchar *name, gchar *value_str)
 {
-  DelayedSet *data = g_slice_new0 (DelayedSet);
+  DelayedSet *data = g_new0 (DelayedSet, 1);
+  gchar **names, **current;
+  GObject *parent, *child;
 
-  GST_CAT_LOG_OBJECT (GST_CAT_PIPELINE, element, "delaying property set %s to %s",
+  GST_CAT_LOG_OBJECT (GST_CAT_PIPELINE, proxy, "delaying property set %s to %s",
     name, value_str);
 
-  data->name = g_strdup(name);
-  data->value_str = g_strdup(value_str);
-  data->signal_id = g_signal_connect_data(element, "child-added",
+  data->name = g_strdup (name);
+  data->value_str = g_strdup (value_str);
+  data->signal_id = g_signal_connect_data (proxy, "child-added",
       G_CALLBACK (gst_parse_new_child), data, (GClosureNotify)
       gst_parse_free_delayed_set, (GConnectFlags) 0);
 
-  /* FIXME: we would need to listen on all intermediate bins too */
-  if (GST_IS_BIN (element)) {
-    gchar **names, **current;
-    GstElement *parent, *child;
+  current = names = g_strsplit (name, "::", -1);
+  parent = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (proxy), current[0]);
+  current++;
 
-    current = names = g_strsplit (name, "::", -1);
-    parent = gst_bin_get_by_name (GST_BIN_CAST (element), current[0]);
-    current++;
-    while (parent && current[0]) {
-      child = gst_bin_get_by_name (GST_BIN (parent), current[0]);
-      if (!child && current[1]) {
-        char *sub_name = g_strjoinv ("::", &current[0]);
+  while (parent && current[0]) {
+    if (!GST_IS_CHILD_PROXY (parent)) {
+      GST_INFO ("Not recursing into non-proxy child %p", parent);
+      break;
+    }
 
-        gst_parse_add_delayed_set(parent, sub_name, value_str);
-        g_free (sub_name);
-      }
-      gst_object_unref (parent);
-      parent = child;
-      current++;
+    child = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (parent), current[0]);
+    if (!child && current[1]) {
+      char *sub_name = g_strjoinv ("::", &current[0]);
+
+      gst_parse_add_delayed_set (GST_CHILD_PROXY (parent), sub_name, value_str);
+      g_free (sub_name);
     }
-    if (parent)
-      gst_object_unref (parent);
-    g_strfreev (names);
+
+    gst_object_unref (parent);
+    parent = child;
+    current++;
   }
+
+  if (parent)
+    gst_object_unref (parent);
+  g_strfreev (names);
 }
 
 static gboolean
@@ -391,8 +455,7 @@ static void gst_parse_new_child(GstChildProxy *child_proxy, GObject *object,
       goto error;
     g_object_set_property (target, pspec->name, &v);
   } else {
-    const gchar *obj_name = GST_OBJECT_NAME(object);
-    gint len = strlen (obj_name);
+    gint len = strlen (name);
 
     /*
      * We've been notified that a new child has beed added, but the
@@ -412,15 +475,15 @@ static void gst_parse_new_child(GstChildProxy *child_proxy, GObject *object,
      */
 
     /* Cases 1,2: The child just added corresponds to this delayed set */
-    if ((strlen (set->name) > (len+2)) && !strncmp (set->name, obj_name, len)
-	&& !strncmp (&set->name[len], "::", 2)) {
+    if ((strlen (set->name) > (len+2)) && !strncmp (set->name, name, len)
+        && !strncmp (&set->name[len], "::", 2)) {
       gchar *children = NULL;
       gchar *prop = NULL;
       GObject *child = NULL;
 
       if (!gst_parse_separate_prop_from_children (set->name, &children, &prop)) {
-	/* Malformed property name, ignore */
-	return;
+        /* Malformed property name, ignore */
+        return;
       }
 
       child = gst_child_proxy_get_child_by_name_recurse (child_proxy, children);
@@ -429,14 +492,14 @@ static void gst_parse_new_child(GstChildProxy *child_proxy, GObject *object,
 
       /* Case 1: A child in the hierarchy does not exist yet, add a new delayed set */
       if (NULL == child) {
-	gst_parse_add_delayed_set (GST_ELEMENT (child_proxy), set->name, set->value_str);
+        gst_parse_add_delayed_set (child_proxy, set->name, set->value_str);
       }
       /* Case 2: The target child exists already but there's no such property */
       else {
-	gst_object_unref (child);
-	GST_ELEMENT_WARNING(GST_ELEMENT (child_proxy), PARSE, NO_SUCH_PROPERTY,
-          (_("No such property.")), (_("no property \"%s\" in element \"%s\""),
-        set->name, GST_ELEMENT_NAME(child_proxy)));
+        gst_object_unref (child);
+        GST_ELEMENT_WARNING(GST_ELEMENT (child_proxy), PARSE, NO_SUCH_PROPERTY,
+            (_("No such property.")), (_("no property \"%s\" in element \"%s\""),
+              set->name, GST_ELEMENT_NAME(child_proxy)));
       }
     }
     /* Case 3: The child just added does not correspond to this delayed set, just ignore
@@ -531,13 +594,13 @@ out:
 not_a_preset:
   SET_ERROR (graph->error, GST_PARSE_ERROR_COULD_NOT_SET_PROPERTY,
          _("Element \"%s\" is not a GstPreset"),
-	 GST_ELEMENT_NAME (element));
+         GST_ELEMENT_NAME (element));
   goto out;
 
 error:
   SET_ERROR (graph->error, GST_PARSE_ERROR_COULD_NOT_SET_PROPERTY,
          _("could not set preset \"%s\" in element \"%s\""),
-	 value, GST_ELEMENT_NAME (element));
+         value, GST_ELEMENT_NAME (element));
   goto out;
 }
 
@@ -549,7 +612,7 @@ typedef struct
 
 static void
 proxied_property_free (proxied_property_t *pp) {
-  g_slice_free (proxied_property_t, pp);
+  g_free (pp);
 }
 
 static GstElement * gst_parse_element_make (graph_t *graph, element_t *data) {
@@ -567,7 +630,7 @@ static GstElement * gst_parse_element_make (graph_t *graph, element_t *data) {
   GstElement *ret = NULL;
 
   if (!factory) {
-		SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, _("no element \"%s\""), data->factory_name);
+    SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_ELEMENT, _("no element \"%s\""), data->factory_name);
     return NULL;
   }
 
@@ -589,7 +652,7 @@ static GstElement * gst_parse_element_make (graph_t *graph, element_t *data) {
     gchar *value = gst_parse_split_assignment (tmp->data);
 
     if (is_proxy && strstr (name, "::") != NULL) {
-      proxied_property_t *pp = g_slice_new (proxied_property_t);
+      proxied_property_t *pp = g_new (proxied_property_t, 1);
       pp->name = name;
       pp->value = value;
       proxied = g_slist_prepend (proxied, pp);
@@ -642,8 +705,8 @@ static GstElement * gst_parse_element_make (graph_t *graph, element_t *data) {
       gchar *children = NULL;
       gchar *property = NULL;
       if (!gst_parse_separate_prop_from_children (pp->name, &children, &property)) {
-	/* malformed childproxy path, skip */
-	continue;
+        /* malformed childproxy path, skip */
+        continue;
       }
 
       target = gst_child_proxy_get_child_by_name_recurse (GST_CHILD_PROXY (ret), children);
@@ -651,13 +714,13 @@ static GstElement * gst_parse_element_make (graph_t *graph, element_t *data) {
       g_free (property);
 
       if (target == NULL) {
-	gst_parse_add_delayed_set (ret, pp->name, pp->value);
+        gst_parse_add_delayed_set (GST_CHILD_PROXY (ret), pp->name, pp->value);
       } else {
-	gst_object_unref (target);
-	SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_PROPERTY,	\
-          _("no property \"%s\" in element \"%s\""), pp->name, \
-          GST_ELEMENT_NAME (ret));
-	goto done;
+        gst_object_unref (target);
+        SET_ERROR (graph->error, GST_PARSE_ERROR_NO_SUCH_PROPERTY, \
+            _("no property \"%s\" in element \"%s\""), pp->name, \
+            GST_ELEMENT_NAME (ret));
+        goto done;
       }
     } else {
       GValue v = { 0, };
@@ -672,6 +735,8 @@ static GstElement * gst_parse_element_make (graph_t *graph, element_t *data) {
         g_object_set_property (target, pspec->name, &v);
         g_value_unset (&v);
       }
+
+      gst_object_unref (target);
     }
   }
 
@@ -755,9 +820,9 @@ static void gst_parse_element_set (gchar *value, GstElement *element, graph_t *g
          the child was found, we fail since the property doesn't exist.
       */
       if (!gst_parse_child_proxy_find_child (GST_CHILD_PROXY (element), value)) {
-	gst_parse_add_delayed_set (element, value, pos);
+        gst_parse_add_delayed_set (GST_CHILD_PROXY (element), value, pos);
       } else {
-	goto error;
+        goto error;
       }
     }
   } else {
@@ -791,7 +856,7 @@ out:
 error:
   SET_ERROR (graph->error, GST_PARSE_ERROR_COULD_NOT_SET_PROPERTY,
          _("could not set property \"%s\" in element \"%s\" to \"%s\""),
-	 value, GST_ELEMENT_NAME (element), pos);
+         value, GST_ELEMENT_NAME (element), pos);
   goto out;
 }
 
@@ -835,7 +900,7 @@ static void gst_parse_free_delayed_link (DelayedLink *link)
   g_free (link->src_pad);
   g_free (link->sink_pad);
   if (link->caps) gst_caps_unref (link->caps);
-  g_slice_free (DelayedLink, link);
+  g_free (link);
 }
 
 #define PRETTY_PAD_NAME_FMT "%s %s of %s named %s"
@@ -866,7 +931,7 @@ static void gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
 
   GST_CAT_INFO (GST_CAT_PIPELINE,
                 "trying delayed linking %s " PRETTY_PAD_NAME_FMT " to " PRETTY_PAD_NAME_FMT,
-		            link->all_pads ? "all pads" : "one pad",
+                link->all_pads ? "all pads" : "one pad",
                 PRETTY_PAD_NAME_ARGS (src, link->src_pad),
                 PRETTY_PAD_NAME_ARGS (link->sink, link->sink_pad));
 
@@ -876,8 +941,8 @@ static void gst_parse_found_pad (GstElement *src, GstPad *pad, gpointer data)
      * unlocking states */
     GST_CAT_DEBUG (GST_CAT_PIPELINE,
                    "delayed linking %s " PRETTY_PAD_NAME_FMT " to " PRETTY_PAD_NAME_FMT " worked",
-		               link->all_pads ? "all pads" : "one pad",
-               	   PRETTY_PAD_NAME_ARGS (src, link->src_pad),
+                   link->all_pads ? "all pads" : "one pad",
+                   PRETTY_PAD_NAME_ARGS (src, link->src_pad),
                    PRETTY_PAD_NAME_ARGS (link->sink, link->sink_pad));
     /* releases 'link' */
     if (!link->all_pads) {
@@ -901,7 +966,7 @@ gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
     if ((GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) &&
         (GST_PAD_TEMPLATE_PRESENCE(templ) == GST_PAD_SOMETIMES))
     {
-      DelayedLink *data = g_slice_new (DelayedLink);
+      DelayedLink *data = g_new (DelayedLink, 1);
 
       data->all_pads = all_pads;
 
@@ -916,9 +981,9 @@ gst_parse_perform_delayed_link (GstElement *src, const gchar *src_pad,
       data->sink = sink;
       data->sink_pad = g_strdup (sink_pad);
       if (caps) {
-      	data->caps = gst_caps_copy (caps);
+        data->caps = gst_caps_copy (caps);
       } else {
-      	data->caps = NULL;
+        data->caps = NULL;
       }
       data->pad_added_signal_id = g_signal_connect_data (src, "pad-added",
           G_CALLBACK (gst_parse_found_pad), data,
@@ -1020,7 +1085,7 @@ gst_parse_perform_link (link_t *link, graph_t *graph)
     if (gst_parse_perform_delayed_link (src,
           srcs ? (const gchar *) srcs->data : NULL,
           sink, sinks ? (const gchar *) sinks->data : NULL, link->caps,
-	  link->all_pads) || link->all_pads) {
+          link->all_pads) || link->all_pads) {
       goto success;
     } else {
       goto error;
@@ -1040,8 +1105,8 @@ gst_parse_perform_link (link_t *link, graph_t *graph)
     } else {
       if (gst_parse_perform_delayed_link (src, src_pad,
                                           sink, sink_pad,
-					  link->caps, link->all_pads)) {
-	continue;
+                                          link->caps, link->all_pads)) {
+        continue;
       } else {
         goto error;
       }
@@ -1161,6 +1226,9 @@ static int yyerror (void *scanner, graph_t *graph, const char *s);
 element: IDENTIFIER              {
             $$ = gst_parse_element_new();
             $$->factory_name = $1;
+
+            /* silence unused but set warnings/errors */
+            (void) yynerrs;
                                               }
   | element PRESET	          {
             $$->presets = g_slist_append ($$->presets, $2);
@@ -1271,7 +1339,9 @@ openchain:
 link:	LINK				      { $$ = gst_parse_link_new ();
 						$$->all_pads = FALSE;
 						if ($1) {
-						  $$->caps = gst_caps_from_string ($1);
+						  gchar *str = str_unwrap ($1);
+						  $$->caps = gst_caps_from_string (str);
+						  g_free (str);
 						  if ($$->caps == NULL)
 						    SET_ERROR (graph->error, GST_PARSE_ERROR_LINK, _("could not parse caps \"%s\""), $1);
 						  gst_parse_strfree ($1);
@@ -1280,7 +1350,9 @@ link:	LINK				      { $$ = gst_parse_link_new ();
 	| LINK_ALL		              { $$ = gst_parse_link_new ();
 						$$->all_pads = TRUE;
 						if ($1) {
-						  $$->caps = gst_caps_from_string ($1);
+						  gchar *str = str_unwrap ($1);
+						  $$->caps = gst_caps_from_string (str);
+						  g_free (str);
 						  if ($$->caps == NULL)
 						    SET_ERROR (graph->error, GST_PARSE_ERROR_LINK, _("could not parse caps \"%s\""), $1);
 						  gst_parse_strfree ($1);
diff --git a/gst/parse/types.h b/gst/parse/types.h
index 961af7e..7aa4d51 100644
--- a/gst/parse/types.h
+++ b/gst/parse/types.h
@@ -75,12 +75,12 @@ G_GNUC_INTERNAL  void	__gst_parse_element_free (element_t *data);
 #else /* __GST_PARSE_TRACE */
 #  define gst_parse_strdup g_strdup
 #  define gst_parse_strfree g_free
-#  define gst_parse_link_new() g_slice_new0 (link_t)
-#  define gst_parse_link_free(l) g_slice_free (link_t, l)
-#  define gst_parse_chain_new() g_slice_new0 (chain_t)
-#  define gst_parse_chain_free(c) g_slice_free (chain_t, c)
-#  define gst_parse_element_new() g_slice_new0 (element_t)
-#  define gst_parse_element_free(e) g_slice_free (element_t, e)
+#  define gst_parse_link_new() g_new0 (link_t, 1)
+#  define gst_parse_link_free(l) g_free (l)
+#  define gst_parse_chain_new() g_new0 (chain_t, 1)
+#  define gst_parse_chain_free(c) g_free (c)
+#  define gst_parse_element_new() g_new0 (element_t, 1)
+#  define gst_parse_element_free(e) g_free (e)
 #endif /* __GST_PARSE_TRACE */
 
 static inline void
diff --git a/gst/printf/asnprintf.c b/gst/printf/asnprintf.c
index d606d38..dd721fe 100644
--- a/gst/printf/asnprintf.c
+++ b/gst/printf/asnprintf.c
@@ -28,7 +28,7 @@
 #include <stdarg.h>
 
 char *
-asnprintf (char *resultbuf, size_t * lengthp, const char *format, ...)
+asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
 {
   va_list args;
   char *result;
diff --git a/gst/printf/vasnprintf.c b/gst/printf/vasnprintf.c
index a97404c..b202c62 100644
--- a/gst/printf/vasnprintf.c
+++ b/gst/printf/vasnprintf.c
@@ -54,7 +54,7 @@
 #  ifndef local_wcslen_defined
 #   define local_wcslen_defined 1
 static size_t
-local_wcslen (const wchar_t * s)
+local_wcslen (const wchar_t *s)
 {
   const wchar_t *ptr;
 
@@ -261,7 +261,7 @@ printf_postprocess_args (char_directives * directives, arguments * arguments)
 }
 
 char *
-vasnprintf (char *resultbuf, size_t * lengthp, const char *format, va_list args)
+vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args)
 {
   char_directives d;
   arguments a;
diff --git a/gstreamer.doap b/gstreamer.doap
index ceb4273..66d4c32 100644
--- a/gstreamer.doap
+++ b/gstreamer.doap
@@ -38,6 +38,166 @@ hierarchy, and a set of media-agnostic core elements.
    </GitRepository>
  </repository>
 
+ <release>
+  <Version>
+   <revision>1.24.12</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2025-01-29</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.12.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.11</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2025-01-06</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.11.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.10</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-12-03</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.10.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.9</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-10-30</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.9.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.8</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-09-19</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.8.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.7</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-08-21</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.7.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.6</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-07-29</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.6.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.5</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-06-20</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.5.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.4</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-05-29</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.4.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.3</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-04-30</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.3.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.2</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-04-09</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.1</revision>
+   <branch>1.24</branch>
+   <name></name>
+   <created>2024-03-21</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.24.0</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2024-03-04</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.24.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.23.90</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2024-02-23</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.23.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.23.2</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2024-02-15</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.23.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.23.1</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2024-02-06</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.23.1.tar.xz" />
+  </Version>
+ </release>
+
  <release>
   <Version>
    <revision>1.22.0</revision>
diff --git a/libs/gst/base/gstadapter.c b/libs/gst/base/gstadapter.c
index 89f2e71..12d7569 100644
--- a/libs/gst/base/gstadapter.c
+++ b/libs/gst/base/gstadapter.c
@@ -581,7 +581,7 @@ gst_adapter_unmap (GstAdapter * adapter)
  * @dest: (out caller-allocates) (array length=size) (element-type guint8):
  *     the memory to copy into
  * @offset: the bytes offset in the adapter to start from
- * @size: the number of bytes to copy
+ * @size: (in): the number of bytes to copy
  *
  * Copies @size bytes of data starting at @offset out of the buffers
  * contained in #GstAdapter into an array @dest provided by the caller.
diff --git a/libs/gst/base/gstaggregator.c b/libs/gst/base/gstaggregator.c
index abd7110..c93feef 100644
--- a/libs/gst/base/gstaggregator.c
+++ b/libs/gst/base/gstaggregator.c
@@ -264,6 +264,12 @@ struct _GstAggregatorPadPrivate
   guint num_buffers;
   GstBuffer *peeked_buffer;
 
+  /* TRUE if the serialized query is in the proccess of handling at some
+   * exact moment. This will obligate the sinkpad streaming thread wait
+   * until the handling finishes.
+   * Always protected by the PAD_LOCK. */
+  gboolean query_in_proccess;
+
   /* used to track fill state of queues, only used with live-src and when
    * latency property is set to > 0 */
   GstClockTime head_position;
@@ -277,6 +283,9 @@ struct _GstAggregatorPadPrivate
 
   gboolean eos;
 
+  /* number of queued stream-start */
+  gboolean stream_start_pending;
+
   GMutex lock;
   GCond event_cond;
   /* This lock prevents a flush start processing happening while
@@ -305,6 +314,7 @@ gst_aggregator_pad_reset_unlocked (GstAggregatorPad * aggpad)
   aggpad->priv->time_level = 0;
   aggpad->priv->first_buffer = TRUE;
   aggpad->priv->waited_once = FALSE;
+  aggpad->priv->stream_start_pending = FALSE;
 }
 
 static gboolean
@@ -856,6 +866,25 @@ gst_aggregator_wait_and_check (GstAggregator * self, gboolean * timeout)
     return FALSE;
   }
 
+  if (self->priv->force_live && self->priv->first_buffer
+      && self->priv->start_time_selection ==
+      GST_AGGREGATOR_START_TIME_SELECTION_FIRST) {
+    GstClockTime start_time;
+    GstAggregatorPad *srcpad = GST_AGGREGATOR_PAD (self->srcpad);
+    start_time = gst_element_get_current_running_time (GST_ELEMENT (self));
+
+    if (GST_CLOCK_TIME_IS_VALID (start_time)) {
+      if (srcpad->segment.position == -1)
+        srcpad->segment.position = start_time;
+      else
+        srcpad->segment.position = MIN (start_time, srcpad->segment.position);
+
+      GST_DEBUG_OBJECT (self, "Selecting start time %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (start_time));
+      self->priv->first_buffer = FALSE;
+    }
+  }
+
   start = gst_aggregator_get_next_time (self);
 
   /* If we're not live, or if we use the running time
@@ -971,8 +1000,10 @@ gst_aggregator_do_events_and_queries (GstElement * self, GstPad * epad,
         !GST_IS_BUFFER (g_queue_peek_tail (&pad->priv->data))) {
       if (GST_IS_EVENT (g_queue_peek_tail (&pad->priv->data)))
         event = gst_event_ref (g_queue_peek_tail (&pad->priv->data));
-      if (GST_IS_QUERY (g_queue_peek_tail (&pad->priv->data)))
+      if (GST_IS_QUERY (g_queue_peek_tail (&pad->priv->data))) {
         query = g_queue_peek_tail (&pad->priv->data);
+        pad->priv->query_in_proccess = TRUE;
+      }
     }
     PAD_UNLOCK (pad);
     if (event || query) {
@@ -1007,6 +1038,8 @@ gst_aggregator_do_events_and_queries (GstElement * self, GstPad * epad,
               NULL);
           g_queue_pop_tail (&pad->priv->data);
         }
+
+        pad->priv->query_in_proccess = FALSE;
       }
 
       PAD_BROADCAST_EVENT (pad);
@@ -1100,6 +1133,7 @@ gst_aggregator_pad_set_flushing (GstAggregatorPad * aggpad,
     item = next;
   }
   aggpad->priv->num_buffers = 0;
+  aggpad->priv->stream_start_pending = FALSE;
   gst_buffer_replace (&aggpad->priv->clipped_buffer, NULL);
 
   PAD_BROADCAST_EVENT (aggpad);
@@ -1375,21 +1409,42 @@ gst_aggregator_negotiate (GstAggregator * self)
   return ret;
 }
 
-static void
-gst_aggregator_aggregate_func (GstAggregator * self)
+static gboolean
+gst_aggregator_check_pending_new_stream (GstElement * self, GstPad * pad,
+    gboolean * have_new_stream)
+{
+  GstAggregatorPad *aggpad = (GstAggregatorPad *) pad;
+  gboolean new_stream = FALSE;
+
+  PAD_LOCK (aggpad);
+  if (aggpad->priv->stream_start_pending)
+    new_stream = TRUE;
+  PAD_UNLOCK (aggpad);
+
+  if (new_stream) {
+    *have_new_stream = TRUE;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_aggregator_loop (GstAggregator * self)
 {
   GstAggregatorPrivate *priv = self->priv;
   GstAggregatorClass *klass = GST_AGGREGATOR_GET_CLASS (self);
   gboolean timeout = FALSE;
+  GstFlowReturn flow_return = GST_FLOW_OK;
 
   if (self->priv->running == FALSE) {
     GST_DEBUG_OBJECT (self, "Not running anymore");
-    return;
+    return GST_FLOW_OK;
   }
 
   GST_LOG_OBJECT (self, "Checking aggregate");
   while (priv->send_eos && priv->running) {
-    GstFlowReturn flow_return = GST_FLOW_OK;
+    flow_return = GST_FLOW_OK;
     DoHandleEventsAndQueriesData events_query_data = { FALSE, GST_FLOW_OK };
 
     gst_element_foreach_sink_pad (GST_ELEMENT_CAST (self),
@@ -1402,10 +1457,14 @@ gst_aggregator_aggregate_func (GstAggregator * self)
       gst_element_foreach_sink_pad (GST_ELEMENT_CAST (self),
           gst_aggregator_pad_skip_buffers, NULL);
 
+    SRC_LOCK (self);
     if (self->priv->got_eos_event) {
+      self->priv->got_eos_event = FALSE;
+      SRC_UNLOCK (self);
       gst_aggregator_push_eos (self);
       continue;
     }
+    SRC_UNLOCK (self);
 
     /* Ensure we have buffers ready (either in clipped_buffer or at the head of
      * the queue */
@@ -1449,7 +1508,7 @@ gst_aggregator_aggregate_func (GstAggregator * self)
       /* We don't want to set the pads to flushing, but we want to
        * stop the thread, so just break here */
       GST_OBJECT_UNLOCK (self);
-      break;
+      return GST_FLOW_FLUSHING;
     }
     GST_OBJECT_UNLOCK (self);
 
@@ -1460,6 +1519,11 @@ gst_aggregator_aggregate_func (GstAggregator * self)
   handle_error:
     GST_LOG_OBJECT (self, "flow return is %s", gst_flow_get_name (flow_return));
 
+    /* Don't flush buffer/event/queries on EOS. We may do restart pad task
+     * on new stream-start */
+    if (flow_return == GST_FLOW_EOS)
+      return GST_FLOW_EOS;
+
     if (flow_return != GST_FLOW_OK) {
       GList *item;
 
@@ -1474,6 +1538,37 @@ gst_aggregator_aggregate_func (GstAggregator * self)
     }
   }
 
+  return flow_return;
+}
+
+static void
+gst_aggregator_aggregate_func (GstAggregator * self)
+{
+  GstAggregatorPrivate *priv = self->priv;
+
+  while (1) {
+    GstFlowReturn ret;
+    gboolean pending_new_stream = FALSE;
+
+    ret = gst_aggregator_loop (self);
+
+    SRC_LOCK (self);
+    if (ret != GST_FLOW_EOS)
+      break;
+
+    gst_element_foreach_sink_pad (GST_ELEMENT_CAST (self),
+        (GstElementForeachPadFunc) gst_aggregator_check_pending_new_stream,
+        &pending_new_stream);
+
+    if (!pending_new_stream)
+      break;
+
+    GST_INFO_OBJECT (self, "Have pending new stream, keep aggregate");
+    gst_aggregator_reset_flow_values (self);
+    priv->send_eos = TRUE;
+    SRC_UNLOCK (self);
+  };
+
   /* Pause the task here, the only ways to get here are:
    * 1) We're stopping, in which case the task is stopped anyway
    * 2) We got a flow error above, in which case it might take
@@ -1482,6 +1577,7 @@ gst_aggregator_aggregate_func (GstAggregator * self)
    *    again without doing anything
    */
   gst_pad_pause_task (self->srcpad);
+  SRC_UNLOCK (self);
 }
 
 static gboolean
@@ -1636,7 +1732,7 @@ gst_aggregator_flush_start (GstAggregator * self, GstAggregatorPad * aggpad,
   PAD_FLUSH_UNLOCK (aggpad);
 }
 
-/* Must be called with the the PAD_LOCK held */
+/* Must be called with the PAD_LOCK and OBJECT_LOCK held */
 static void
 update_time_level (GstAggregatorPad * aggpad, gboolean head)
 {
@@ -1761,9 +1857,14 @@ gst_aggregator_default_sink_event (GstAggregator * self,
     }
     case GST_EVENT_STREAM_START:
     {
+      SRC_LOCK (self);
       PAD_LOCK (aggpad);
+      GST_DEBUG_OBJECT (aggpad, "Clear EOS on STREAM-START");
       aggpad->priv->eos = FALSE;
+      aggpad->priv->stream_start_pending = FALSE;
       PAD_UNLOCK (aggpad);
+      SRC_BROADCAST (self);
+      SRC_UNLOCK (self);
       goto eat;
     }
     case GST_EVENT_GAP:
@@ -1847,13 +1948,31 @@ static GstFlowReturn
 gst_aggregator_default_sink_event_pre_queue (GstAggregator * self,
     GstAggregatorPad * aggpad, GstEvent * event)
 {
+  GstAggregatorPrivate *priv = self->priv;
   GstFlowReturn ret = GST_FLOW_OK;
+  GstEventType event_type = GST_EVENT_TYPE (event);
 
-  if (GST_EVENT_IS_SERIALIZED (event)
-      && GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_STOP) {
+  if (GST_EVENT_IS_SERIALIZED (event) && event_type != GST_EVENT_FLUSH_STOP) {
     SRC_LOCK (self);
     PAD_LOCK (aggpad);
 
+    if (event_type == GST_EVENT_STREAM_START && priv->running) {
+      GstTaskState task_state;
+      aggpad->priv->flow_return = GST_FLOW_OK;
+
+      aggpad->priv->stream_start_pending = TRUE;
+
+      task_state = gst_pad_get_task_state (self->srcpad);
+      if (task_state == GST_TASK_PAUSED) {
+        GST_DEBUG_OBJECT (aggpad, "Resuming pad task");
+        priv->send_eos = TRUE;
+        gst_aggregator_reset_flow_values (self);
+        gst_aggregator_start_srcpad_task (self);
+      } else {
+        GST_DEBUG_OBJECT (aggpad, "Pad task function is running already");
+      }
+    }
+
     if (aggpad->priv->flow_return != GST_FLOW_OK)
       goto flushing;
 
@@ -2032,7 +2151,10 @@ gst_aggregator_release_pad (GstElement * element, GstPad * pad)
 
   SRC_LOCK (self);
   gst_aggregator_pad_set_flushing (aggpad, GST_FLOW_FLUSHING, TRUE);
+  PAD_LOCK (aggpad);
   gst_buffer_replace (&aggpad->priv->peeked_buffer, NULL);
+  gst_buffer_replace (&aggpad->priv->clipped_buffer, NULL);
+  PAD_UNLOCK (aggpad);
   gst_element_remove_pad (element, pad);
 
   self->priv->has_peer_latency = FALSE;
@@ -2048,6 +2170,8 @@ gst_aggregator_default_create_new_pad (GstAggregator * self,
   GstAggregatorPrivate *priv = self->priv;
   gint serial = 0;
   gchar *name = NULL;
+  gchar *percent_str;
+
   GType pad_type =
       GST_PAD_TEMPLATE_GTYPE (templ) ==
       G_TYPE_NONE ? GST_TYPE_AGGREGATOR_PAD : GST_PAD_TEMPLATE_GTYPE (templ);
@@ -2058,34 +2182,56 @@ gst_aggregator_default_create_new_pad (GstAggregator * self,
   if (templ->presence != GST_PAD_REQUEST)
     goto not_request;
 
-  GST_OBJECT_LOCK (self);
-  if (req_name == NULL || strlen (req_name) < 6
-      || !g_str_has_prefix (req_name, "sink_")
-      || strrchr (req_name, '%') != NULL) {
-    /* no name given when requesting the pad, use next available int */
-    serial = ++priv->max_padserial;
-  } else {
-    gchar *endptr = NULL;
+  percent_str = strrchr (templ->name_template, '%');
 
-    /* parse serial number from requested padname */
-    serial = g_ascii_strtoull (&req_name[5], &endptr, 10);
-    if (endptr != NULL && *endptr == '\0') {
-      if (serial > priv->max_padserial) {
-        priv->max_padserial = serial;
+  if (percent_str == NULL) {
+    if (req_name)
+      name = g_strdup (req_name);
+    else
+      name = g_strdup (templ->name_template);
+  } else if (g_strcmp0 (percent_str, "%u") == 0
+      || g_strcmp0 (percent_str, "%d") == 0) {
+    guint percent_index = percent_str - templ->name_template;
+    gchar *template_str = g_strndup (templ->name_template, percent_index);
+
+    GST_OBJECT_LOCK (self);
+    if (req_name == NULL || g_strcmp0 (templ->name_template, req_name) == 0) {
+      /* no name given when requesting the pad, use next available int */
+      serial = ++priv->max_padserial;
+    } else if (g_str_has_prefix (req_name, template_str)) {
+      gchar *endptr = NULL;
+
+      /* parse serial number from requested padname */
+      serial = g_ascii_strtoull (&req_name[percent_index], &endptr, 10);
+
+      if (endptr != NULL && *endptr == '\0') {
+        if (serial > priv->max_padserial) {
+          priv->max_padserial = serial;
+        }
+      } else {
+        g_free (template_str);
+        GST_OBJECT_UNLOCK (self);
+        goto invalid_request_name;
       }
     } else {
-      serial = ++priv->max_padserial;
+      g_free (template_str);
+      GST_OBJECT_UNLOCK (self);
+      goto invalid_request_name;
     }
+
+    name = g_strdup_printf ("%s%u", template_str, serial);
+    g_free (template_str);
+
+    GST_OBJECT_UNLOCK (self);
+  } else {
+    goto invalid_template_name;
   }
 
-  name = g_strdup_printf ("sink_%u", serial);
   g_assert (g_type_is_a (pad_type, GST_TYPE_AGGREGATOR_PAD));
   agg_pad = g_object_new (pad_type,
       "name", name, "direction", GST_PAD_SINK, "template", templ, NULL);
   g_free (name);
 
-  GST_OBJECT_UNLOCK (self);
-
   return agg_pad;
 
   /* errors */
@@ -2099,6 +2245,20 @@ not_request:
     GST_WARNING_OBJECT (self, "request new pad that is not a REQUEST pad");
     return NULL;
   }
+invalid_template_name:
+  {
+    GST_WARNING_OBJECT (self,
+        "template name %s is invalid, must be in the form name_%%u (%s)",
+        templ->name_template, percent_str);
+    return NULL;
+  }
+invalid_request_name:
+  {
+    GST_WARNING_OBJECT (self,
+        "requested name %s is invalid, must be in the form %s", req_name,
+        templ->name_template);
+    return NULL;
+  }
 }
 
 static GstPad *
@@ -2108,7 +2268,6 @@ gst_aggregator_request_new_pad (GstElement * element,
   GstAggregator *self;
   GstAggregatorPad *agg_pad;
   GstAggregatorClass *klass = GST_AGGREGATOR_GET_CLASS (element);
-  GstAggregatorPrivate *priv = GST_AGGREGATOR (element)->priv;
 
   self = GST_AGGREGATOR (element);
 
@@ -2120,9 +2279,6 @@ gst_aggregator_request_new_pad (GstElement * element,
 
   GST_DEBUG_OBJECT (element, "Adding pad %s", GST_PAD_NAME (agg_pad));
 
-  if (priv->running)
-    gst_pad_set_active (GST_PAD (agg_pad), TRUE);
-
   /* add the pad to the element */
   gst_element_add_pad (element, GST_PAD (agg_pad));
 
@@ -2134,9 +2290,11 @@ gst_aggregator_request_new_pad (GstElement * element,
 static gboolean
 gst_aggregator_query_latency_unlocked (GstAggregator * self, GstQuery * query)
 {
-  gboolean query_ret, live;
+  gboolean query_ret, upstream_live;
   GstClockTime our_latency, min, max;
 
+  GST_TRACE_OBJECT (self, "querying latency");
+
   /* Temporarily release the lock to do the query. */
   SRC_UNLOCK (self);
   query_ret = gst_pad_query_default (self->srcpad, GST_OBJECT (self), query);
@@ -2147,7 +2305,12 @@ gst_aggregator_query_latency_unlocked (GstAggregator * self, GstQuery * query)
     return FALSE;
   }
 
-  gst_query_parse_latency (query, &live, &min, &max);
+  gst_query_parse_latency (query, &upstream_live, &min, &max);
+
+  GST_LOG_OBJECT (self,
+      "queried upstream latency, live: %s min: %" GST_TIME_FORMAT " max: %"
+      GST_TIME_FORMAT, upstream_live ? "true" : "false", GST_TIME_ARGS (min),
+      GST_TIME_ARGS (max));
 
   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (min))) {
     GST_ERROR_OBJECT (self, "Invalid minimum latency %" GST_TIME_FORMAT
@@ -2177,7 +2340,7 @@ gst_aggregator_query_latency_unlocked (GstAggregator * self, GstQuery * query)
 
   our_latency = self->priv->latency;
 
-  self->priv->peer_latency_live = live;
+  self->priv->peer_latency_live = upstream_live;
   self->priv->peer_latency_min = min;
   self->priv->peer_latency_max = max;
   self->priv->has_peer_latency = TRUE;
@@ -2194,9 +2357,10 @@ gst_aggregator_query_latency_unlocked (GstAggregator * self, GstQuery * query)
   SRC_BROADCAST (self);
 
   GST_DEBUG_OBJECT (self, "configured latency live:%s min:%" G_GINT64_FORMAT
-      " max:%" G_GINT64_FORMAT, live ? "true" : "false", min, max);
+      " max:%" G_GINT64_FORMAT,
+      is_live_unlocked (self) ? "true" : "false", min, max);
 
-  gst_query_set_latency (query, live, min, max);
+  gst_query_set_latency (query, is_live_unlocked (self), min, max);
 
   return query_ret;
 }
@@ -2635,9 +2799,14 @@ gst_aggregator_default_sink_query_pre_queue (GstAggregator * self,
     SRC_BROADCAST (self);
     SRC_UNLOCK (self);
 
-    while (!gst_aggregator_pad_queue_is_empty (aggpad)
-        && aggpad->priv->flow_return == GST_FLOW_OK) {
-      GST_DEBUG_OBJECT (aggpad, "Waiting for buffer to be consumed");
+    /* Sanity check: aggregator's sink pad can only proccess one serialized
+     * query at a time. */
+    g_warn_if_fail (!aggpad->priv->query_in_proccess);
+
+    while ((!gst_aggregator_pad_queue_is_empty (aggpad)
+            && aggpad->priv->flow_return == GST_FLOW_OK) ||
+        aggpad->priv->query_in_proccess) {
+      GST_DEBUG_OBJECT (aggpad, "Waiting for query to be consumed");
       PAD_WAIT_EVENT (aggpad);
     }
 
@@ -2829,7 +2998,6 @@ gst_aggregator_class_init (GstAggregatorClass * klass)
 {
   GObjectClass *gobject_class = (GObjectClass *) klass;
   GstElementClass *gstelement_class = (GstElementClass *) klass;
-  static const gchar *meta_tags[] = { NULL };
 
   aggregator_parent_class = g_type_class_peek_parent (klass);
 
@@ -2946,8 +3114,7 @@ gst_aggregator_class_init (GstAggregatorClass * klass)
       GST_TYPE_CLOCK_TIME, GST_TYPE_CLOCK_TIME,
       GST_TYPE_STRUCTURE | G_SIGNAL_TYPE_STATIC_SCOPE);
 
-  gst_meta_register_custom ("GstAggregatorMissingDataMeta", meta_tags, NULL,
-      NULL, NULL);
+  gst_meta_register_custom_simple ("GstAggregatorMissingDataMeta");
 }
 
 static inline gpointer
@@ -3105,7 +3272,9 @@ apply_buffer (GstAggregatorPad * aggpad, GstBuffer * buffer, gboolean head)
   else
     aggpad->priv->tail_position = timestamp;
 
+  GST_OBJECT_LOCK (aggpad);
   update_time_level (aggpad, head);
+  GST_OBJECT_UNLOCK (aggpad);
 }
 
 /*
@@ -3120,6 +3289,7 @@ gst_aggregator_pad_chain_internal (GstAggregator * self,
 {
   GstFlowReturn flow_return;
   GstClockTime buf_pts;
+  GstClockTime buf_duration;
 
   GST_TRACE_OBJECT (aggpad,
       "entering chain internal with %" GST_PTR_FORMAT, buffer);
@@ -3132,6 +3302,7 @@ gst_aggregator_pad_chain_internal (GstAggregator * self,
   PAD_UNLOCK (aggpad);
 
   buf_pts = GST_BUFFER_PTS (buffer);
+  buf_duration = GST_BUFFER_DURATION (buffer);
 
   for (;;) {
     SRC_LOCK (self);
@@ -3188,6 +3359,9 @@ gst_aggregator_pad_chain_internal (GstAggregator * self,
         if (aggpad->priv->head_segment.format == GST_FORMAT_TIME) {
           start_time = buf_pts;
           if (start_time != -1) {
+            if (aggpad->priv->head_segment.rate < 0.0 && buf_duration != -1) {
+              start_time += buf_duration;
+            }
             start_time = MAX (start_time, aggpad->priv->head_segment.start);
             start_time =
                 gst_segment_to_running_time (&aggpad->priv->head_segment,
@@ -3198,7 +3372,7 @@ gst_aggregator_pad_chain_internal (GstAggregator * self,
           GST_WARNING_OBJECT (aggpad,
               "Ignoring request of selecting the first start time "
               "as the segment is a %s segment instead of a time segment",
-              gst_format_get_name (aggpad->segment.format));
+              gst_format_get_name (aggpad->priv->head_segment.format));
         }
         GST_OBJECT_UNLOCK (aggpad);
         break;
@@ -3696,8 +3870,8 @@ gst_aggregator_pad_is_inactive (GstAggregatorPad * pad)
   gboolean inactive;
 
   self = GST_AGGREGATOR (gst_pad_get_parent_element (GST_PAD (pad)));
-
-  g_assert_nonnull (self);
+  if (!self)
+    return FALSE;
 
   PAD_LOCK (pad);
   inactive = self->priv->ignore_inactive_pads && is_live_unlocked (self)
@@ -3863,6 +4037,11 @@ gst_aggregator_simple_get_next_time (GstAggregator * self)
   GstSegment *segment = &srcpad->segment;
 
   GST_OBJECT_LOCK (self);
+  if (segment->format != GST_FORMAT_TIME) {
+    GST_OBJECT_UNLOCK (self);
+    return GST_CLOCK_TIME_NONE;
+  }
+
   if (segment->position == -1 || segment->position < segment->start)
     next_time = segment->start;
   else
diff --git a/libs/gst/base/gstbaseparse.c b/libs/gst/base/gstbaseparse.c
index 4e7c46e..422e489 100644
--- a/libs/gst/base/gstbaseparse.c
+++ b/libs/gst/base/gstbaseparse.c
@@ -694,7 +694,7 @@ gst_base_parse_frame_copy (GstBaseParseFrame * frame)
 {
   GstBaseParseFrame *copy;
 
-  copy = g_slice_dup (GstBaseParseFrame, frame);
+  copy = g_memdup2 (frame, sizeof (GstBaseParseFrame));
   copy->buffer = gst_buffer_ref (frame->buffer);
   copy->_private_flags &= ~GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC;
 
@@ -720,7 +720,7 @@ gst_base_parse_frame_free (GstBaseParseFrame * frame)
   }
 
   if (!(frame->_private_flags & GST_BASE_PARSE_FRAME_PRIVATE_FLAG_NOALLOC)) {
-    g_slice_free (GstBaseParseFrame, frame);
+    g_free (frame);
   } else {
     memset (frame, 0, sizeof (*frame));
   }
@@ -769,7 +769,7 @@ gst_base_parse_frame_new (GstBuffer * buffer, GstBaseParseFrameFlags flags,
 {
   GstBaseParseFrame *frame;
 
-  frame = g_slice_new0 (GstBaseParseFrame);
+  frame = g_new0 (GstBaseParseFrame, 1);
   frame->buffer = gst_buffer_ref (buffer);
 
   GST_TRACE ("created frame %p", frame);
@@ -2289,6 +2289,10 @@ gst_base_parse_handle_buffer (GstBaseParse * parse, GstBuffer * buffer,
       outbuf = gst_buffer_make_writable (outbuf);
       GST_BUFFER_PTS (outbuf) = pts;
       GST_BUFFER_DTS (outbuf) = dts;
+      GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
+      GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
+      GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
+      GST_BUFFER_FLAGS (outbuf) = 0;
       parse->priv->buffers_head =
           g_slist_prepend (parse->priv->buffers_head, outbuf);
       outbuf = NULL;
@@ -2678,10 +2682,13 @@ no_caps:
  * @frame: a #GstBaseParseFrame
  * @size: consumed input data represented by frame
  *
- * Collects parsed data and pushes this downstream.
+ * Collects parsed data and pushes it downstream.
  * Source pad caps must be set when this is called.
  *
- * If @frame's out_buffer is set, that will be used as subsequent frame data.
+ * If @frame's out_buffer is set, that will be used as subsequent frame data,
+ * and @size amount will be flushed from the input data. The output_buffer size
+ * can differ from the consumed size indicated by @size.
+ *
  * Otherwise, @size samples will be taken from the input and used for output,
  * and the output's metadata (timestamps etc) will be taken as (optionally)
  * set by the subclass on @frame's (input) buffer (which is otherwise
@@ -2728,6 +2735,7 @@ gst_base_parse_finish_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
     GstBuffer *src, *dest;
 
     frame->out_buffer = gst_adapter_take_buffer (parse->priv->adapter, size);
+    frame->out_buffer = gst_buffer_make_writable (frame->out_buffer);
     dest = frame->out_buffer;
     src = frame->buffer;
     GST_BUFFER_PTS (dest) = GST_BUFFER_PTS (src);
@@ -2735,7 +2743,7 @@ gst_base_parse_finish_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
     GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
     GST_BUFFER_DURATION (dest) = GST_BUFFER_DURATION (src);
     GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
-    GST_MINI_OBJECT_FLAGS (dest) = GST_MINI_OBJECT_FLAGS (src);
+    GST_BUFFER_FLAGS (dest) = GST_BUFFER_FLAGS (src);
   } else {
     gst_adapter_flush (parse->priv->adapter, size);
   }
diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c
index 294d946..e94a957 100644
--- a/libs/gst/base/gstbasesink.c
+++ b/libs/gst/base/gstbasesink.c
@@ -2185,7 +2185,11 @@ again:
       }
       goto do_times;
     }
-    goto out_of_segment;
+    if (basesink->priv->drop_out_of_segment)
+      goto out_of_segment;
+
+    cstart = start;
+    cstop = stop;
   }
 
   if (G_UNLIKELY (start != cstart || stop != cstop)) {
@@ -3664,6 +3668,9 @@ gst_base_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       if (bclass->event)
         result = bclass->event (basesink, event);
       break;
+    case GST_EVENT_STREAM_START:
+      basesink->priv->received_eos = FALSE;
+      /* fallthrough */
     default:
       if (GST_EVENT_IS_SERIALIZED (event)) {
         GST_BASE_SINK_PREROLL_LOCK (basesink);
@@ -3950,6 +3957,11 @@ again:
 
     if (bclass->render)
       ret = bclass->render (basesink, GST_BUFFER_CAST (obj));
+
+    if (ret == GST_BASE_SINK_FLOW_DROPPED) {
+      ret = GST_FLOW_OK;
+      goto dropped;
+    }
   } else {
     GstBufferList *buffer_list = GST_BUFFER_LIST_CAST (obj);
 
@@ -3959,6 +3971,9 @@ again:
     /* Set the first buffer and buffer list to be included in last sample */
     gst_base_sink_set_last_buffer (basesink, sync_buf);
     gst_base_sink_set_last_buffer_list (basesink, buffer_list);
+
+    /* Not currently supported */
+    g_assert (ret != GST_BASE_SINK_FLOW_DROPPED);
   }
 
   if (ret == GST_FLOW_STEP)
@@ -5141,8 +5156,17 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
 
   GST_OBJECT_LOCK (basesink);
   /* we can only get the segment when we are not NULL or READY */
-  if (!basesink->have_newsegment)
+  if (GST_STATE (basesink) <= GST_STATE_READY &&
+      GST_STATE_PENDING (basesink) <= GST_STATE_READY) {
     goto wrong_state;
+  }
+
+  segment = &basesink->segment;
+  /* get the format in the segment */
+  oformat = segment->format;
+
+  if (oformat == GST_FORMAT_UNDEFINED)
+    goto no_segment;
 
   in_paused = FALSE;
   /* when not in PLAYING or when we're busy with a state change, we
@@ -5153,11 +5177,6 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
     in_paused = TRUE;
   }
 
-  segment = &basesink->segment;
-
-  /* get the format in the segment */
-  oformat = segment->format;
-
   /* report with last seen position when EOS */
   last_seen = basesink->eos;
 
@@ -5356,6 +5375,15 @@ wrong_state:
     GST_OBJECT_UNLOCK (basesink);
     goto done;
   }
+no_segment:
+  {
+    GST_DEBUG_OBJECT (basesink,
+        "haven't received a segment yet, can't anwser position, return -1");
+    res = FALSE;
+    *cur = -1;
+    GST_OBJECT_UNLOCK (basesink);
+    goto done;
+  }
 convert_failed:
   {
     GST_DEBUG_OBJECT (basesink, "convert failed, try upstream");
diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h
index 8edae03..2cf799a 100644
--- a/libs/gst/base/gstbasesink.h
+++ b/libs/gst/base/gstbasesink.h
@@ -58,6 +58,20 @@ G_BEGIN_DECLS
 #define GST_BASE_SINK_PREROLL_SIGNAL(obj)     g_cond_signal (GST_BASE_SINK_GET_PREROLL_COND (obj));
 #define GST_BASE_SINK_PREROLL_BROADCAST(obj)  g_cond_broadcast (GST_BASE_SINK_GET_PREROLL_COND (obj));
 
+/**
+ * GST_BASE_SINK_FLOW_DROPPED:
+ *
+ * A #GstFlowReturn that can be returned from
+ * #GstBaseSinkClass::render to indicate that the output buffer was not
+ * rendered.
+ *
+ * Note that this is currently not support for #GstBaseSinkClass::render_list
+ * virtual method.
+ *
+ * Since: 1.24
+ */
+#define GST_BASE_SINK_FLOW_DROPPED     GST_FLOW_CUSTOM_SUCCESS
+
 typedef struct _GstBaseSink GstBaseSink;
 typedef struct _GstBaseSinkClass GstBaseSinkClass;
 typedef struct _GstBaseSinkPrivate GstBaseSinkPrivate;
diff --git a/libs/gst/base/gstbasesrc.c b/libs/gst/base/gstbasesrc.c
index e47d145..a840b4a 100644
--- a/libs/gst/base/gstbasesrc.c
+++ b/libs/gst/base/gstbasesrc.c
@@ -189,6 +189,9 @@ enum
 #define DEFAULT_BLOCKSIZE       4096
 #define DEFAULT_NUM_BUFFERS     -1
 #define DEFAULT_DO_TIMESTAMP    FALSE
+/* FIXME 2.0: automatic_eos should probably be disabled by default,
+ * see https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1330 */
+#define DEFAULT_AUTOMATIC_EOS   TRUE
 
 enum
 {
@@ -198,7 +201,8 @@ enum
 #ifndef GST_REMOVE_DEPRECATED
   PROP_TYPEFIND,
 #endif
-  PROP_DO_TIMESTAMP
+  PROP_DO_TIMESTAMP,
+  PROP_AUTOMATIC_EOS
 };
 
 /* The basesrc implementation need to respect the following locking order:
@@ -261,6 +265,9 @@ struct _GstBaseSrcPrivate
 
   /* for _submit_buffer_list() */
   GstBufferList *pending_bufferlist;
+
+  /* to delay unlock_stop */
+  gboolean pending_unlock_stop;
 };
 
 #define BASE_SRC_HAS_PENDING_BUFFER_LIST(src) \
@@ -404,6 +411,18 @@ gst_base_src_class_init (GstBaseSrcClass * klass)
           "Apply current stream time to buffers", DEFAULT_DO_TIMESTAMP,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  /**
+   * GstBaseSrc:automatic-eos:
+   *
+   * See gst_base_src_set_automatic_eos()
+   *
+   * Since: 1.24
+   */
+  g_object_class_install_property (gobject_class, PROP_AUTOMATIC_EOS,
+      g_param_spec_boolean ("automatic-eos", "Automatic EOS",
+          "Automatically EOS when the segment is done", DEFAULT_AUTOMATIC_EOS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_base_src_change_state);
   gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_src_send_event);
@@ -442,7 +461,7 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
   g_cond_init (&basesrc->live_cond);
   basesrc->num_buffers = DEFAULT_NUM_BUFFERS;
   basesrc->num_buffers_left = -1;
-  g_atomic_int_set (&basesrc->priv->automatic_eos, TRUE);
+  g_atomic_int_set (&basesrc->priv->automatic_eos, DEFAULT_AUTOMATIC_EOS);
 
   basesrc->can_activate_push = TRUE;
 
@@ -2204,6 +2223,9 @@ gst_base_src_set_property (GObject * object, guint prop_id,
     case PROP_DO_TIMESTAMP:
       gst_base_src_set_do_timestamp (src, g_value_get_boolean (value));
       break;
+    case PROP_AUTOMATIC_EOS:
+      gst_base_src_set_automatic_eos (src, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -2233,6 +2255,9 @@ gst_base_src_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_DO_TIMESTAMP:
       g_value_set_boolean (value, gst_base_src_get_do_timestamp (src));
       break;
+    case PROP_AUTOMATIC_EOS:
+      g_value_set_boolean (value, g_atomic_int_get (&src->priv->automatic_eos));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -2538,6 +2563,7 @@ gst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length,
   GstBuffer *res_buf;
   GstBuffer *in_buf;
   gboolean own_res_buf;
+  gboolean pending_unlock_stop;
 
   bclass = GST_BASE_SRC_GET_CLASS (src);
 
@@ -2588,7 +2614,19 @@ again:
   res_buf = in_buf = *buf;
   own_res_buf = (*buf == NULL);
 
+retry_create:
   GST_LIVE_UNLOCK (src);
+
+  /* Undo our unlocking initiated from set_playing function. This is done here
+   * since we require the stream lock to call this virtual function. */
+  GST_OBJECT_LOCK (src);
+  pending_unlock_stop = src->priv->pending_unlock_stop;
+  src->priv->pending_unlock_stop = FALSE;
+  GST_OBJECT_UNLOCK (src);
+
+  if (pending_unlock_stop && bclass->unlock_stop)
+    bclass->unlock_stop (src);
+
   ret = bclass->create (src, offset, length, &res_buf);
   GST_LIVE_LOCK (src);
 
@@ -2596,13 +2634,19 @@ again:
   if (src->is_live) {
     if (G_UNLIKELY (!src->live_running)) {
       GstFlowReturn wait_ret;
+
+      /* no need keep old buffer while in pause */
+      if (ret == GST_FLOW_OK && own_res_buf)
+        gst_clear_buffer (&res_buf);
+      gst_clear_buffer_list (&src->priv->pending_bufferlist);
+
       wait_ret = gst_base_src_wait_playing_unlocked (src);
       if (wait_ret != GST_FLOW_OK) {
-        if (ret == GST_FLOW_OK && own_res_buf)
-          gst_buffer_unref (res_buf);
         ret = wait_ret;
         goto stopped;
       }
+
+      goto retry_create;
     }
   }
 
@@ -2612,7 +2656,8 @@ again:
   if (G_UNLIKELY (g_atomic_int_get (&src->priv->has_pending_eos))) {
     if (ret == GST_FLOW_OK) {
       if (own_res_buf)
-        gst_buffer_unref (res_buf);
+        gst_clear_buffer (&res_buf);
+      gst_clear_buffer_list (&src->priv->pending_bufferlist);
     }
     src->priv->forced_eos = TRUE;
     goto eos;
@@ -3690,7 +3735,7 @@ not_activated_yet:
   {
     GST_PAD_STREAM_UNLOCK (basesrc->srcpad);
     gst_base_src_stop (basesrc);
-    GST_WARNING_OBJECT (basesrc, "pad not activated yet");
+    GST_INFO_OBJECT (basesrc, "pad not activated yet");
     ret = GST_FLOW_ERROR;
     goto error;
   }
@@ -3845,12 +3890,23 @@ gst_base_src_set_flushing (GstBaseSrc * basesrc, gboolean flushing)
 static gboolean
 gst_base_src_set_playing (GstBaseSrc * basesrc, gboolean live_play)
 {
+  GstBaseSrcClass *bclass;
+
+  bclass = GST_BASE_SRC_GET_CLASS (basesrc);
+
   /* we are now able to grab the LIVE lock, when we get it, we can be
    * waiting for PLAYING while blocked in the LIVE cond or we can be waiting
    * for the clock. */
   GST_LIVE_LOCK (basesrc);
   GST_DEBUG_OBJECT (basesrc, "unschedule clock");
 
+  /* unlock subclasses locked in ::create, we only do this when we stop playing. */
+  if (!live_play) {
+    GST_DEBUG_OBJECT (basesrc, "unlock");
+    if (bclass->unlock)
+      bclass->unlock (basesrc);
+  }
+
   /* unblock clock sync (if any) */
   if (basesrc->clock_id)
     gst_clock_id_unschedule (basesrc->clock_id);
@@ -3865,6 +3921,7 @@ gst_base_src_set_playing (GstBaseSrc * basesrc, gboolean live_play)
     /* for live sources we restart the timestamp correction */
     GST_OBJECT_LOCK (basesrc);
     basesrc->priv->latency = -1;
+    basesrc->priv->pending_unlock_stop = TRUE;
     GST_OBJECT_UNLOCK (basesrc);
     /* have to restart the task in case it stopped because of the unlock when
      * we went to PAUSED. Only do this if we operating in push mode. */
@@ -4142,3 +4199,66 @@ gst_base_src_submit_buffer_list (GstBaseSrc * src, GstBufferList * buffer_list)
   GST_LOG_OBJECT (src, "%u buffers submitted in buffer list",
       gst_buffer_list_length (buffer_list));
 }
+
+/**
+ * gst_base_src_push_segment:
+ * @src: a #GstBaseSrc
+ * @segment: a pointer to a #GstSegment
+ *
+ * Send a new segment downstream. This function must
+ * only be called by derived sub-classes, and only from the #GstBaseSrcClass::create function,
+ * as the stream-lock needs to be held.
+ * This method also requires that an out caps has been configured, so
+ * gst_base_src_set_caps() needs to have been called before.
+ *
+ * The format for the @segment must be identical with the current format
+ * of the source, as configured with gst_base_src_set_format().
+ *
+ * The format of @src must not be %GST_FORMAT_UNDEFINED and the format
+ * should be configured via gst_base_src_set_format() before calling this method.
+ *
+ * This is a variant of gst_base_src_new_segment() sending the segment right away,
+ * which can be useful to ensure events ordering.
+ *
+ * Returns: %TRUE if sending of new segment succeeded.
+ *
+ * Since: 1.24
+*/
+gboolean
+gst_base_src_push_segment (GstBaseSrc * src, const GstSegment * segment)
+{
+  GstEvent *seg_event;
+
+  g_return_val_if_fail (GST_IS_BASE_SRC (src), FALSE);
+  g_return_val_if_fail (segment != NULL, FALSE);
+
+  GST_OBJECT_LOCK (src);
+
+  if (src->segment.format == GST_FORMAT_UNDEFINED) {
+    /* subclass must set valid format before calling this method */
+    GST_WARNING_OBJECT (src, "segment format is not configured yet, ignore");
+    GST_OBJECT_UNLOCK (src);
+    return FALSE;
+  }
+
+  if (src->segment.format != segment->format) {
+    GST_WARNING_OBJECT (src, "segment format mismatched, ignore");
+    GST_OBJECT_UNLOCK (src);
+    return FALSE;
+  }
+
+  gst_segment_copy_into (segment, &src->segment);
+  seg_event = gst_event_new_segment (&src->segment);
+  src->priv->segment_pending = FALSE;
+  src->priv->segment_seqnum = gst_util_seqnum_next ();
+  gst_event_set_seqnum (seg_event, src->priv->segment_seqnum);
+
+  GST_OBJECT_UNLOCK (src);
+
+  GST_DEBUG_OBJECT (src, "Sending new segment %" GST_SEGMENT_FORMAT, segment);
+  gst_pad_push_event (src->srcpad, seg_event);
+
+  src->running = TRUE;
+
+  return TRUE;
+}
diff --git a/libs/gst/base/gstbasesrc.h b/libs/gst/base/gstbasesrc.h
index 38c3ef3..0784aaf 100644
--- a/libs/gst/base/gstbasesrc.h
+++ b/libs/gst/base/gstbasesrc.h
@@ -184,6 +184,14 @@ struct _GstBaseSrcClass {
   /* decide on caps */
   gboolean      (*negotiate)    (GstBaseSrc *src);
   /* called if, in negotiation, caps need fixating */
+  /**
+   * GstBaseSrcClass::fixate:
+   * @caps: (transfer full):
+   *
+   * Called if, in negotiation, caps need fixating.
+   *
+   * Returns: (transfer full): the fixated caps
+   */
   GstCaps *     (*fixate)       (GstBaseSrc *src, GstCaps *caps);
   /* notify the subclass of new caps */
   gboolean      (*set_caps)     (GstBaseSrc *src, GstCaps *caps);
@@ -241,7 +249,7 @@ struct _GstBaseSrcClass {
 
   /**
    * GstBaseSrcClass::create:
-   * @buf: (inout):
+   * @buf: (inout) (nullable):
    *
    * Ask the subclass to create a buffer with @offset and @size, the default
    * implementation will call alloc if no allocated @buf is provided and then call fill.
@@ -250,7 +258,7 @@ struct _GstBaseSrcClass {
                                  GstBuffer **buf);
   /**
    * GstBaseSrcClass::alloc:
-   * @buf: (out):
+   * @buf: (out) (nullable):
    *
    * Ask the subclass to allocate an output buffer with @offset and @size, the default
    * implementation will use the negotiated allocator.
@@ -339,6 +347,10 @@ GST_BASE_API
 void            gst_base_src_submit_buffer_list (GstBaseSrc    * src,
                                                  GstBufferList * buffer_list);
 
+GST_BASE_API
+gboolean gst_base_src_push_segment              (GstBaseSrc * src,
+                                                 const GstSegment * segment);
+
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstBaseSrc, gst_object_unref)
 
 G_END_DECLS
diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c
index 3f38c09..470e71c 100644
--- a/libs/gst/base/gstbasetransform.c
+++ b/libs/gst/base/gstbasetransform.c
@@ -655,7 +655,7 @@ gst_base_transform_query_caps (GstBaseTransform * trans, GstPad * pad,
     if (peerfilter) {
       if (!gst_caps_is_empty (peerfilter)) {
         /* and filter against the template of the other pad */
-        GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, otempl);
+        GST_DEBUG_OBJECT (pad, "other template  %" GST_PTR_FORMAT, otempl);
         /* We keep the caps sorted like the returned caps */
         temp =
             gst_caps_intersect_full (peerfilter, otempl,
@@ -687,7 +687,7 @@ gst_base_transform_query_caps (GstBaseTransform * trans, GstPad * pad,
     GST_DEBUG_OBJECT (pad, "peer caps  %" GST_PTR_FORMAT, peercaps);
 
     /* filtered against our padtemplate on the other side */
-    GST_DEBUG_OBJECT (pad, "our template  %" GST_PTR_FORMAT, otempl);
+    GST_DEBUG_OBJECT (pad, "other template  %" GST_PTR_FORMAT, otempl);
     temp = gst_caps_intersect_full (peercaps, otempl, GST_CAPS_INTERSECT_FIRST);
     GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
   } else {
diff --git a/libs/gst/base/gstbitreader.c b/libs/gst/base/gstbitreader.c
index db97ad5..405f2e1 100644
--- a/libs/gst/base/gstbitreader.c
+++ b/libs/gst/base/gstbitreader.c
@@ -63,7 +63,7 @@
 GstBitReader *
 gst_bit_reader_new (const guint8 * data, guint size)
 {
-  GstBitReader *ret = g_slice_new0 (GstBitReader);
+  GstBitReader *ret = g_new0 (GstBitReader, 1);
 
   ret->data = data;
   ret->size = size;
@@ -83,7 +83,7 @@ gst_bit_reader_free (GstBitReader * reader)
 {
   g_return_if_fail (reader != NULL);
 
-  g_slice_free (GstBitReader, reader);
+  g_free (reader);
 }
 
 /**
diff --git a/libs/gst/base/gstbitwriter.c b/libs/gst/base/gstbitwriter.c
index c482040..6dbe66a 100644
--- a/libs/gst/base/gstbitwriter.c
+++ b/libs/gst/base/gstbitwriter.c
@@ -51,7 +51,7 @@
 GstBitWriter *
 gst_bit_writer_new (void)
 {
-  GstBitWriter *ret = g_slice_new0 (GstBitWriter);
+  GstBitWriter *ret = g_new0 (GstBitWriter, 1);
 
   ret->owned = TRUE;
   ret->auto_grow = TRUE;
@@ -72,7 +72,7 @@ gst_bit_writer_new (void)
 GstBitWriter *
 gst_bit_writer_new_with_size (guint size, gboolean fixed)
 {
-  GstBitWriter *ret = g_slice_new0 (GstBitWriter);
+  GstBitWriter *ret = g_new0 (GstBitWriter, 1);
 
   gst_bit_writer_init_with_size (ret, size, fixed);
   return ret;
@@ -95,7 +95,7 @@ gst_bit_writer_new_with_size (guint size, gboolean fixed)
 GstBitWriter *
 gst_bit_writer_new_with_data (guint8 * data, guint size, gboolean initialized)
 {
-  GstBitWriter *ret = g_slice_new0 (GstBitWriter);
+  GstBitWriter *ret = g_new0 (GstBitWriter, 1);
 
   gst_bit_writer_init_with_data (ret, data, size, initialized);
 
@@ -260,7 +260,7 @@ gst_bit_writer_free (GstBitWriter * bitwriter)
   g_return_if_fail (bitwriter != NULL);
 
   gst_bit_writer_reset (bitwriter);
-  g_slice_free (GstBitWriter, bitwriter);
+  g_free (bitwriter);
 }
 
 /**
@@ -283,7 +283,7 @@ gst_bit_writer_free_and_get_data (GstBitWriter * bitwriter)
   g_return_val_if_fail (bitwriter != NULL, NULL);
 
   data = gst_bit_writer_reset_and_get_data (bitwriter);
-  g_slice_free (GstBitWriter, bitwriter);
+  g_free (bitwriter);
 
   return data;
 }
@@ -308,7 +308,7 @@ gst_bit_writer_free_and_get_buffer (GstBitWriter * bitwriter)
   g_return_val_if_fail (bitwriter != NULL, NULL);
 
   buffer = gst_bit_writer_reset_and_get_buffer (bitwriter);
-  g_slice_free (GstBitWriter, bitwriter);
+  g_free (bitwriter);
 
   return buffer;
 }
diff --git a/libs/gst/base/gstbytereader.c b/libs/gst/base/gstbytereader.c
index c0a16ef..c08f561 100644
--- a/libs/gst/base/gstbytereader.c
+++ b/libs/gst/base/gstbytereader.c
@@ -99,7 +99,7 @@
 GstByteReader *
 gst_byte_reader_new (const guint8 * data, guint size)
 {
-  GstByteReader *ret = g_slice_new0 (GstByteReader);
+  GstByteReader *ret = g_new0 (GstByteReader, 1);
 
   ret->data = data;
   ret->size = size;
@@ -119,7 +119,7 @@ gst_byte_reader_free (GstByteReader * reader)
 {
   g_return_if_fail (reader != NULL);
 
-  g_slice_free (GstByteReader, reader);
+  g_free (reader);
 }
 
 /**
diff --git a/libs/gst/base/gstbytewriter.c b/libs/gst/base/gstbytewriter.c
index aec1093..c5111b5 100644
--- a/libs/gst/base/gstbytewriter.c
+++ b/libs/gst/base/gstbytewriter.c
@@ -78,7 +78,7 @@
 GstByteWriter *
 gst_byte_writer_new (void)
 {
-  GstByteWriter *ret = g_slice_new0 (GstByteWriter);
+  GstByteWriter *ret = g_new0 (GstByteWriter, 1);
 
   ret->owned = TRUE;
   return ret;
@@ -289,7 +289,7 @@ gst_byte_writer_free (GstByteWriter * writer)
   g_return_if_fail (writer != NULL);
 
   gst_byte_writer_reset (writer);
-  g_slice_free (GstByteWriter, writer);
+  g_free (writer);
 }
 
 /**
@@ -311,7 +311,7 @@ gst_byte_writer_free_and_get_data (GstByteWriter * writer)
   g_return_val_if_fail (writer != NULL, NULL);
 
   data = gst_byte_writer_reset_and_get_data (writer);
-  g_slice_free (GstByteWriter, writer);
+  g_free (writer);
 
   return data;
 }
@@ -336,7 +336,7 @@ gst_byte_writer_free_and_get_buffer (GstByteWriter * writer)
   g_return_val_if_fail (writer != NULL, NULL);
 
   buffer = gst_byte_writer_reset_and_get_buffer (writer);
-  g_slice_free (GstByteWriter, writer);
+  g_free (writer);
 
   return buffer;
 }
diff --git a/libs/gst/base/gstcollectpads.c b/libs/gst/base/gstcollectpads.c
index b6f9215..abbae44 100644
--- a/libs/gst/base/gstcollectpads.c
+++ b/libs/gst/base/gstcollectpads.c
@@ -1224,7 +1224,7 @@ gst_collect_pads_set_waiting (GstCollectPads * pads, GstCollectData * data,
   /* Do something only on a change and if not locked */
   if (!GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_LOCKED) &&
       (GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_WAITING) !=
-          ! !waiting)) {
+          !!waiting)) {
     /* Set waiting state for this pad */
     if (waiting)
       GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_WAITING);
diff --git a/libs/gst/base/gstflowcombiner.c b/libs/gst/base/gstflowcombiner.c
index d353eae..fc251c6 100644
--- a/libs/gst/base/gstflowcombiner.c
+++ b/libs/gst/base/gstflowcombiner.c
@@ -95,7 +95,7 @@ G_DEFINE_BOXED_TYPE_WITH_CODE (GstFlowCombiner, gst_flow_combiner,
 GstFlowCombiner *
 gst_flow_combiner_new (void)
 {
-  GstFlowCombiner *combiner = g_slice_new (GstFlowCombiner);
+  GstFlowCombiner *combiner = g_new (GstFlowCombiner, 1);
 
   g_queue_init (&combiner->pads);
   combiner->last_ret = GST_FLOW_OK;
@@ -161,7 +161,7 @@ gst_flow_combiner_unref (GstFlowCombiner * combiner)
     while ((pad = g_queue_pop_head (&combiner->pads)))
       gst_object_unref (pad);
 
-    g_slice_free (GstFlowCombiner, combiner);
+    g_free (combiner);
   }
 }
 
diff --git a/libs/gst/base/gstindex.c b/libs/gst/base/gstindex.c
index 964508e..a4bae64 100644
--- a/libs/gst/base/gstindex.c
+++ b/libs/gst/base/gstindex.c
@@ -272,7 +272,7 @@ gst_index_get_property (GObject * object, guint prop_id,
 static GstIndexGroup *
 gst_index_group_new (guint groupnum)
 {
-  GstIndexGroup *indexgroup = g_slice_new (GstIndexGroup);
+  GstIndexGroup *indexgroup = g_new (GstIndexGroup, 1);
 
   indexgroup->groupnum = groupnum;
   indexgroup->entries = NULL;
@@ -287,7 +287,7 @@ gst_index_group_new (guint groupnum)
 static void
 gst_index_group_free (GstIndexGroup * group)
 {
-  g_slice_free (GstIndexGroup, group);
+  g_free (group);
 }
 
 /* do not resurrect this, add a derived dummy index class instead */
@@ -528,7 +528,7 @@ gst_index_set_resolver_full (GstIndex * index, GstIndexResolver resolver,
 GstIndexEntry *
 gst_index_entry_copy (GstIndexEntry * entry)
 {
-  GstIndexEntry *new_entry = g_slice_new (GstIndexEntry);
+  GstIndexEntry *new_entry = g_new (GstIndexEntry, 1);
 
   memcpy (new_entry, entry, sizeof (GstIndexEntry));
   return new_entry;
@@ -562,7 +562,7 @@ gst_index_entry_free (GstIndexEntry * entry)
       break;
   }
 
-  g_slice_free (GstIndexEntry, entry);
+  g_free (entry);
 }
 
 #if 0
@@ -592,7 +592,7 @@ gst_index_add_format (GstIndex * index, gint id, GstFormat format)
   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
     return NULL;
 
-  entry = g_slice_new (GstIndexEntry);
+  entry = g_new (GstIndexEntry, 1);
   entry->type = GST_INDEX_ENTRY_FORMAT;
   entry->id = id;
   entry->data.format.format = format;
@@ -627,7 +627,7 @@ gst_index_add_id (GstIndex * index, gint id, gchar * description)
   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
     return NULL;
 
-  entry = g_slice_new (GstIndexEntry);
+  entry = g_new (GstIndexEntry, 1);
   entry->type = GST_INDEX_ENTRY_ID;
   entry->id = id;
   entry->data.id.description = description;
@@ -742,7 +742,7 @@ gst_index_get_writer_id (GstIndex * index, GstObject * writer, gint * id)
     if (!entry) {
       /* index is probably not writable, make an entry anyway
        * to keep it in our cache */
-      entry = g_slice_new (GstIndexEntry);
+      entry = g_new (GstIndexEntry, 1);
       entry->type = GST_INDEX_ENTRY_ID;
       entry->id = *id;
       entry->data.id.description = writer_string;
@@ -794,7 +794,7 @@ gst_index_add_associationv (GstIndex * index, gint id,
   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
     return NULL;
 
-  entry = g_slice_new (GstIndexEntry);
+  entry = g_new (GstIndexEntry, 1);
 
   entry->type = GST_INDEX_ENTRY_ASSOCIATION;
   entry->id = id;
diff --git a/libs/gst/base/gstmemindex.c b/libs/gst/base/gstmemindex.c
index b667447..66b6c66 100644
--- a/libs/gst/base/gstmemindex.c
+++ b/libs/gst/base/gstmemindex.c
@@ -140,7 +140,7 @@ gst_mem_index_free_format (gpointer key, gpointer value, gpointer user_data)
     g_tree_destroy (index->tree);
   }
 
-  g_slice_free (GstMemIndexFormatIndex, index);
+  g_free (index);
 }
 
 static void
@@ -155,7 +155,7 @@ gst_mem_index_free_id (gpointer key, gpointer value, gpointer user_data)
     id_index->format_index = NULL;
   }
 
-  g_slice_free (GstMemIndexId, id_index);
+  g_free (id_index);
 }
 
 static void
@@ -189,7 +189,7 @@ gst_mem_index_add_id (GstIndex * index, GstIndexEntry * entry)
   id_index = g_hash_table_lookup (memindex->id_index, &entry->id);
 
   if (!id_index) {
-    id_index = g_slice_new0 (GstMemIndexId);
+    id_index = g_new0 (GstMemIndexId, 1);
 
     id_index->id = entry->id;
     id_index->format_index = g_hash_table_new (g_int_hash, g_int_equal);
@@ -224,7 +224,7 @@ gst_mem_index_index_format (GstMemIndexId * id_index, GstIndexEntry * entry,
   index = g_hash_table_lookup (id_index->format_index, format);
 
   if (!index) {
-    index = g_slice_new0 (GstMemIndexFormatIndex);
+    index = g_new0 (GstMemIndexFormatIndex, 1);
 
     index->format = *format;
     index->offset = assoc;
diff --git a/libs/gst/base/gstpushsrc.h b/libs/gst/base/gstpushsrc.h
index d0d8cef..d987be2 100644
--- a/libs/gst/base/gstpushsrc.h
+++ b/libs/gst/base/gstpushsrc.h
@@ -72,7 +72,7 @@ struct _GstPushSrcClass {
 
   /**
    * GstPushSrcClass::create:
-   * @buf: (inout):
+   * @buf: (inout) (nullable):
    *
    * Ask the subclass to create a buffer, the default implementation will call alloc if
    * no allocated @buf is provided and then call fill.
@@ -80,7 +80,7 @@ struct _GstPushSrcClass {
   GstFlowReturn (*create) (GstPushSrc *src, GstBuffer **buf);
   /**
    * GstPushSrcClass::alloc:
-   * @buf: (out):
+   * @buf: (out) (nullable):
    *
    * Allocate memory for a buffer.
    */
diff --git a/libs/gst/base/gstqueuearray.c b/libs/gst/base/gstqueuearray.c
index 2045037..cfd80e4 100644
--- a/libs/gst/base/gstqueuearray.c
+++ b/libs/gst/base/gstqueuearray.c
@@ -37,6 +37,9 @@
 #include <gst/gst.h>
 #include "gstqueuearray.h"
 
+#define gst_queue_array_idx(a, i) \
+  ((a)->array + (((a)->head + (i)) % (a)->size) * (a)->elt_size)
+
 struct _GstQueueArray
 {
   /* < private > */
@@ -50,6 +53,12 @@ struct _GstQueueArray
   GDestroyNotify clear_func;
 };
 
+typedef struct
+{
+  GCompareDataFunc func;
+  gpointer user_data;
+} QueueSortData;
+
 /**
  * gst_queue_array_new_for_struct: (skip)
  * @struct_size: Size of each element (e.g. structure) in the array
@@ -69,7 +78,7 @@ gst_queue_array_new_for_struct (gsize struct_size, guint initial_size)
 
   g_return_val_if_fail (struct_size > 0, NULL);
 
-  array = g_slice_new (GstQueueArray);
+  array = g_new (GstQueueArray, 1);
   array->elt_size = struct_size;
   array->size = initial_size;
   array->array = g_malloc0 (struct_size * initial_size);
@@ -116,7 +125,7 @@ gst_queue_array_free (GstQueueArray * array)
   g_return_if_fail (array != NULL);
   gst_queue_array_clear (array);
   g_free (array->array);
-  g_slice_free (GstQueueArray, array);
+  g_free (array);
 }
 
 /**
@@ -431,6 +440,212 @@ gst_queue_array_push_tail (GstQueueArray * array, gpointer data)
   array->length++;
 }
 
+/* Moves all elements in the queue placed after the given position in the internal array */
+static void
+gst_queue_array_move_data_after_position (GstQueueArray * array, guint pos)
+{
+  guint elt_size = array->elt_size;
+
+  /* If the array does not wrap around OR if it does, but we're inserting past that point */
+  if (array->head < array->tail ||
+      (array->head >= array->tail && pos < array->head)) {
+    memmove (array->array + (pos + 1) * elt_size, array->array + pos * elt_size,
+        (array->tail - pos) * elt_size);
+    return;
+  }
+
+  /* Otherwise, array wraps around and we're inserting before the breaking point. 
+   * First, move everything past that point by one place. */
+  memmove (array->array + elt_size, array->array, array->tail * elt_size);
+
+  /* Then move the last element from before the wrap-around point to right after it. */
+  memcpy (array->array, array->array + (array->size - 1) * elt_size, elt_size);
+
+  /* If we're inserting right before the breaking point, no further action is needed.
+   * Otherwise, move data between insertion point and the breaking point by one place. */
+  if (pos != array->size - 1) {
+    memmove (array->array + (pos + 1) * elt_size, array->array + pos * elt_size,
+        (array->size - pos - 1) * elt_size);
+  }
+}
+
+/**
+ * gst_queue_array_push_sorted: (skip)
+ * @array: a #GstQueueArray object
+ * @data: object to push
+ * @func: comparison function
+ * @user_data: (nullable): data for comparison function
+ *
+ * Pushes @data to the queue @array, finding the correct position
+ * by comparing @data with each array element using @func.
+ *
+ * This has a time complexity of O(n), so depending on the size of the queue
+ * and expected access patterns, a different data structure might be better.
+ *
+ * Assumes that the array is already sorted. If it is not, make sure
+ * to call gst_queue_array_sort() first.
+ *
+ * Since: 1.24
+ */
+void
+gst_queue_array_push_sorted (GstQueueArray * array, gpointer data,
+    GCompareDataFunc func, gpointer user_data)
+{
+  guint i;
+  gpointer *p_element;
+
+  g_return_if_fail (array != NULL);
+  g_return_if_fail (func != NULL);
+
+  /* Check if we need to make room */
+  if (G_UNLIKELY (array->length == array->size))
+    gst_queue_array_do_expand (array);
+
+  /* Compare against each element, assuming they're already sorted */
+  for (i = 0; i < array->length; i++) {
+    p_element = (gpointer *) gst_queue_array_idx (array, i);
+
+    if (func (*p_element, data, user_data) > 0) {
+      guint pos = (array->head + i) % array->size;
+      gst_queue_array_move_data_after_position (array, pos);
+
+      *p_element = data;
+      goto finish;
+    }
+  }
+
+  /* No 'bigger' element found - append to tail */
+  *(gpointer *) (array->array + array->elt_size * array->tail) = data;
+
+finish:
+  array->tail++;
+  array->tail %= array->size;
+  array->length++;
+}
+
+/**
+ * gst_queue_array_push_sorted_struct: (skip)
+ * @array: a #GstQueueArray object
+ * @p_struct: address of element or structure to push into the queue
+ * @func: comparison function
+ * @user_data: (nullable): data for comparison function
+ *
+ * Pushes the element at address @p_struct into the queue @array
+ * (copying the contents of a structure of the struct_size specified
+ * when creating the queue into the array), finding the correct position
+ * by comparing the element at @p_struct with each element in the array using @func.
+ *
+ * This has a time complexity of O(n), so depending on the size of the queue
+ * and expected access patterns, a different data structure might be better.
+ *
+ * Assumes that the array is already sorted. If it is not, make sure
+ * to call gst_queue_array_sort() first.
+ *
+ * Since: 1.24
+ */
+void
+gst_queue_array_push_sorted_struct (GstQueueArray * array, gpointer p_struct,
+    GCompareDataFunc func, gpointer user_data)
+{
+  guint i;
+  gpointer p_element;
+
+  g_return_if_fail (array != NULL);
+  g_return_if_fail (p_struct != NULL);
+  g_return_if_fail (func != NULL);
+
+  /* Check if we need to make room */
+  if (G_UNLIKELY (array->length == array->size))
+    gst_queue_array_do_expand (array);
+
+  /* Compare against each element, assuming they're already sorted */
+  for (i = 0; i < array->length; i++) {
+    p_element = gst_queue_array_idx (array, i);
+
+    if (func (p_element, p_struct, user_data) > 0) {
+      guint pos = (array->head + i) % array->size;
+      gst_queue_array_move_data_after_position (array, pos);
+
+      memcpy (p_element, p_struct, array->elt_size);
+      goto finish;
+    }
+  }
+
+  /* No 'bigger' element found - append to tail */
+  memcpy (array->array + array->elt_size * array->tail, p_struct,
+      array->elt_size);
+
+finish:
+  array->tail++;
+  array->tail %= array->size;
+  array->length++;
+}
+
+static int
+compare_wrapper (gpointer * a, gpointer * b, QueueSortData * sort_data)
+{
+  return sort_data->func (*a, *b, sort_data->user_data);
+}
+
+/** 
+ * gst_queue_array_sort: (skip)
+ * @array: a #GstQueueArray object
+ * @compare_func: comparison function
+ * @user_data: (nullable): data for comparison function
+ *
+ * Sorts the queue @array by comparing elements against each other using
+ * the provided @compare_func.
+ *
+ * Since: 1.24
+ */
+void
+gst_queue_array_sort (GstQueueArray * array, GCompareDataFunc compare_func,
+    gpointer user_data)
+{
+  g_return_if_fail (array != NULL);
+  g_return_if_fail (compare_func != NULL);
+
+  if (array->length == 0)
+    return;
+
+  /* To be able to use g_qsort_with_data, we might need to rearrange:
+   * [0-----TAIL][HEAD-----SIZE] -> [HEAD-------TAIL] */
+  if (array->head >= array->tail) {
+    gsize t1 = array->head;
+    gsize t2 = array->size - array->head;
+    gsize elt_size = array->elt_size;
+
+    /* Copy [0-------TAIL] part to a temporary buffer */
+    guint8 *tmp = g_malloc0_n (t1, elt_size);
+    memcpy (tmp, array->array, t1 * elt_size);
+
+    /* Move [HEAD-----SIZE] part to the beginning of the original array */
+    memmove (array->array, array->array + (elt_size * array->head),
+        t2 * elt_size);
+
+    /* Copy the temporary buffer to the end of the original array */
+    memmove (array->array + (t2 * elt_size), tmp, t1 * elt_size);
+    g_free (tmp);
+
+    array->head = 0;
+    array->tail = array->length % array->size;
+  }
+
+  if (array->struct_array) {
+    g_qsort_with_data (array->array +
+        (array->head % array->size) * array->elt_size, array->length,
+        array->elt_size, compare_func, user_data);
+  } else {
+    /* For non-struct arrays, we need to wrap the provided compare function 
+     * to dereference our pointers before passing them for comparison. 
+     * This matches the behaviour of gst_queue_array_find(). */
+    QueueSortData sort_data = { compare_func, user_data };
+    g_qsort_with_data (array->array +
+        (array->head % array->size) * array->elt_size, array->length,
+        array->elt_size, (GCompareDataFunc) compare_wrapper, &sort_data);
+  }
+}
+
 /**
  * gst_queue_array_peek_tail: (skip)
  * @array: a #GstQueueArray object
@@ -718,7 +933,7 @@ gst_queue_array_drop_element (GstQueueArray * array, guint idx)
 /**
  * gst_queue_array_find: (skip)
  * @array: a #GstQueueArray object
- * @func: (allow-none): comparison function, or %NULL to find @data by value
+ * @func: (nullable): comparison function, or %NULL to find @data by value
  * @data: data for comparison function
  *
  * Finds an element in the queue @array, either by comparing every element
diff --git a/libs/gst/base/gstqueuearray.h b/libs/gst/base/gstqueuearray.h
index 77edec0..2a63e95 100644
--- a/libs/gst/base/gstqueuearray.h
+++ b/libs/gst/base/gstqueuearray.h
@@ -104,6 +104,23 @@ gpointer        gst_queue_array_pop_tail_struct  (GstQueueArray * array);
 GST_BASE_API
 gpointer        gst_queue_array_peek_tail_struct (GstQueueArray * array);
 
+GST_BASE_API
+void            gst_queue_array_push_sorted (GstQueueArray * array, 
+                                             gpointer data,
+                                             GCompareDataFunc func, 
+                                             gpointer user_data);
+
+GST_BASE_API
+void            gst_queue_array_push_sorted_struct (GstQueueArray * array, 
+                                                    gpointer p_struct,
+                                                    GCompareDataFunc func, 
+                                                    gpointer user_data);
+
+GST_BASE_API
+void            gst_queue_array_sort (GstQueueArray *array,
+                                      GCompareDataFunc compare_func,
+                                      gpointer user_data);
+
 G_END_DECLS
 
 #endif
diff --git a/libs/gst/base/gsttypefindhelper.c b/libs/gst/base/gsttypefindhelper.c
index f385e80..455b229 100644
--- a/libs/gst/base/gsttypefindhelper.c
+++ b/libs/gst/base/gsttypefindhelper.c
@@ -181,7 +181,7 @@ helper_find_peek (gpointer data, gint64 offset, guint size)
     return NULL;
   }
 
-  bmap = g_slice_new0 (GstMappedBuffer);
+  bmap = g_new0 (GstMappedBuffer, 1);
 
   if (!gst_buffer_map (buffer, &bmap->map, GST_MAP_READ))
     goto map_failed;
@@ -210,7 +210,7 @@ map_failed:
   {
     GST_ERROR ("map failed");
     gst_buffer_unref (buffer);
-    g_slice_free (GstMappedBuffer, bmap);
+    g_free (bmap);
     return NULL;
   }
 }
@@ -436,7 +436,7 @@ gst_type_find_helper_get_range_full (GstObject * obj, GstObject * parent,
 
     gst_buffer_unmap (bmap->buffer, &bmap->map);
     gst_buffer_unref (bmap->buffer);
-    g_slice_free (GstMappedBuffer, bmap);
+    g_free (bmap);
   }
   g_slist_free (helper.buffers);
 
@@ -728,10 +728,9 @@ gst_type_find_helper_for_data_with_caps (GstObject * obj,
 {
   GstTypeFind *find;
   GstTypeFindData *find_data;
-  GstTypeFindFactory *factory;
   GList *l, *factories = NULL;
   GstCaps *result = NULL;
-  GstTypeFindProbability found_probability, last_found_probability;
+  GstTypeFindProbability last_found_probability;
 
   g_return_val_if_fail (data != NULL, NULL);
   g_return_val_if_fail (caps != NULL, NULL);
@@ -742,16 +741,16 @@ gst_type_find_helper_for_data_with_caps (GstObject * obj,
 
   factories = gst_type_find_list_factories_for_caps (obj, caps);
   if (!factories) {
-    GST_ERROR_OBJECT (obj, "Failed to typefind for caps: %" GST_PTR_FORMAT,
+    GST_INFO_OBJECT (obj, "Failed to typefind for caps: %" GST_PTR_FORMAT,
         caps);
     goto out;
   }
 
-  found_probability = GST_TYPE_FIND_NONE;
   last_found_probability = GST_TYPE_FIND_NONE;
 
   for (l = factories; l; l = l->next) {
-    factory = GST_TYPE_FIND_FACTORY (l->data);
+    GstTypeFindProbability found_probability;
+    GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (l->data);
 
     gst_type_find_factory_call_function (factory, find);
 
diff --git a/libs/gst/base/meson.build b/libs/gst/base/meson.build
index d897abe..e08254d 100644
--- a/libs/gst/base/meson.build
+++ b/libs/gst/base/meson.build
@@ -79,6 +79,7 @@ if build_gir
   library_def += {'gir': [gir]}
   if not static_build
     gst_base_gir = gnome.generate_gir(gst_base, kwargs: gir)
+    library_def += {'gir_targets':  library_def.get('gir_targets', []) + [gst_base_gir]}
     gst_base_gen_sources += [gst_base_gir]
   endif
 endif
diff --git a/libs/gst/check/gstcheck.c b/libs/gst/check/gstcheck.c
index 0b6b22d..accf41a 100644
--- a/libs/gst/check/gstcheck.c
+++ b/libs/gst/check/gstcheck.c
@@ -99,7 +99,7 @@ gst_check_alloc_log_filter (const gchar * log_domain, GLogLevelFlags log_level,
 {
   GstCheckLogFilter *filter;
 
-  filter = g_slice_new (GstCheckLogFilter);
+  filter = g_new (GstCheckLogFilter, 1);
   filter->log_domain = g_strdup (log_domain);
   filter->log_level = log_level;
   filter->regex = regex;
@@ -120,7 +120,7 @@ gst_check_free_log_filter (GstCheckLogFilter * filter)
   g_regex_unref (filter->regex);
   if (filter->destroy)
     filter->destroy (filter->user_data);
-  g_slice_free (GstCheckLogFilter, filter);
+  g_free (filter);
 }
 
 
@@ -353,6 +353,7 @@ static const gchar *log_domains[] = {
   "GStreamer-GL",
   "GStreamer-InsertBin",
   "GStreamer-ISOFF",
+  "GStreamer-MSE",
   "GStreamer-MpegTS",
   "GStreamer-Net",
   "GStreamer-OpenCV",
@@ -1271,7 +1272,7 @@ gst_check_objects_destroyed_on_unref (gpointer object_to_unref,
 {
   GObject *object;
   GList *objs = NULL, *tmp;
-  DestroyedObjectStruct *destroyed = g_slice_new0 (DestroyedObjectStruct);
+  DestroyedObjectStruct *destroyed = g_new0 (DestroyedObjectStruct, 1);
 
   destroyed->object = object_to_unref;
   g_object_weak_ref (object_to_unref, (GWeakNotify) weak_notify, destroyed);
@@ -1284,7 +1285,7 @@ gst_check_objects_destroyed_on_unref (gpointer object_to_unref,
 
     va_start (varargs, first_object);
     while (object) {
-      destroyed = g_slice_new0 (DestroyedObjectStruct);
+      destroyed = g_new0 (DestroyedObjectStruct, 1);
       destroyed->object = object;
       g_object_weak_ref (object, (GWeakNotify) weak_notify, destroyed);
       objs = g_list_prepend (objs, destroyed);
@@ -1305,7 +1306,7 @@ gst_check_objects_destroyed_on_unref (gpointer object_to_unref,
           G_OBJECT_TYPE_NAME (destroyed), destroyed->object,
           destroyed->object->ref_count);
     }
-    g_slice_free (DestroyedObjectStruct, tmp->data);
+    g_free (tmp->data);
   }
   g_list_free (objs);
 }
diff --git a/libs/gst/check/gstharness.c b/libs/gst/check/gstharness.c
index 295b66f..03a135f 100644
--- a/libs/gst/check/gstharness.c
+++ b/libs/gst/check/gstharness.c
@@ -126,6 +126,7 @@
 #endif
 
 #include "gstharness.h"
+#include "gstharnesslink.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -133,8 +134,12 @@
 
 static void gst_harness_stress_free (GstHarnessThread * t);
 
-#define HARNESS_KEY "harness"
+/* Keys used for storing and retrieving associations to pads and elements with
+ * g_object_set_data (): */
+/* The HARNESS_REF association inside a GstElement will keep track of how many
+ * GstHarness'es are attached to that element. */
 #define HARNESS_REF "harness-ref"
+
 #define HARNESS_LOCK(h) g_mutex_lock (&(h)->priv->priv_mutex)
 #define HARNESS_UNLOCK(h) g_mutex_unlock (&(h)->priv->priv_mutex)
 
@@ -211,10 +216,16 @@ struct _GstHarnessPrivate
 static GstFlowReturn
 gst_harness_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
 {
-  GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
-  GstHarnessPrivate *priv = h->priv;
+  GstHarness *h;
+  GstHarnessLink *link;
+  GstHarnessPrivate *priv;
   (void) parent;
+
+  if (!(link = gst_harness_pad_link_lock (pad, &h)))
+    return GST_FLOW_FLUSHING;
   g_assert (h != NULL);
+  priv = h->priv;
+
   g_mutex_lock (&priv->blocking_push_mutex);
   g_atomic_int_inc (&priv->recv_buffers);
 
@@ -233,31 +244,45 @@ gst_harness_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
   }
   g_mutex_unlock (&priv->blocking_push_mutex);
 
+  gst_harness_link_unlock (link);
   return GST_FLOW_OK;
 }
 
 static gboolean
 gst_harness_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
 {
-  GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
-  GstHarnessPrivate *priv = h->priv;
+  GstHarness *h;
+  GstHarnessLink *link;
+  GstHarnessPrivate *priv;
   (void) parent;
+
+  if (!(link = gst_harness_pad_link_lock (pad, &h)))
+    return FALSE;
   g_assert (h != NULL);
+  priv = h->priv;
+
   g_atomic_int_inc (&priv->recv_upstream_events);
   g_async_queue_push (priv->src_event_queue, event);
+
+  gst_harness_link_unlock (link);
   return TRUE;
 }
 
 static gboolean
 gst_harness_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
 {
-  GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
-  GstHarnessPrivate *priv = h->priv;
+  GstHarness *h;
+  GstHarnessLink *link;
+  GstHarnessPrivate *priv;
   gboolean ret = TRUE;
   gboolean forward;
+  (void) parent;
 
+  if (!(link = gst_harness_pad_link_lock (pad, &h)))
+    return FALSE;
   g_assert (h != NULL);
-  (void) parent;
+  priv = h->priv;
+
   g_atomic_int_inc (&priv->recv_events);
 
   switch (GST_EVENT_TYPE (event)) {
@@ -289,6 +314,7 @@ gst_harness_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
   }
   HARNESS_UNLOCK (h);
 
+  gst_harness_link_unlock (link);
   return ret;
 }
 
@@ -369,10 +395,16 @@ gst_harness_negotiate (GstHarness * h)
 static gboolean
 gst_harness_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
 {
-  GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
-  GstHarnessPrivate *priv = h->priv;
+  GstHarness *h;
+  GstHarnessLink *link;
+  GstHarnessPrivate *priv;
   gboolean res = TRUE;
+  (void) parent;
+
+  if (!(link = gst_harness_pad_link_lock (pad, &h)))
+    return FALSE;
   g_assert (h != NULL);
+  priv = h->priv;
 
   // FIXME: forward all queries?
 
@@ -456,16 +488,23 @@ gst_harness_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
       res = gst_pad_query_default (pad, parent, query);
   }
 
+  gst_harness_link_unlock (link);
   return res;
 }
 
 static gboolean
 gst_harness_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
 {
-  GstHarness *h = g_object_get_data (G_OBJECT (pad), HARNESS_KEY);
-  GstHarnessPrivate *priv = h->priv;
+  GstHarness *h;
+  GstHarnessLink *link;
+  GstHarnessPrivate *priv;
   gboolean res = TRUE;
+  (void) parent;
+
+  if (!(link = gst_harness_pad_link_lock (pad, &h)))
+    return FALSE;
   g_assert (h != NULL);
+  priv = h->priv;
 
   switch (GST_QUERY_TYPE (query)) {
     case GST_QUERY_LATENCY:
@@ -495,6 +534,7 @@ gst_harness_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
     default:
       res = gst_pad_query_default (pad, parent, query);
   }
+  gst_harness_link_unlock (link);
   return res;
 }
 
@@ -579,8 +619,8 @@ gst_harness_setup_src_pad (GstHarness * h,
   /* sending pad */
   h->srcpad = gst_pad_new_from_static_template (src_tmpl, "src");
   g_assert (h->srcpad);
-  g_object_set_data (G_OBJECT (h->srcpad), HARNESS_KEY, h);
 
+  gst_harness_pad_link_set (h->srcpad, h);
   gst_pad_set_query_function (h->srcpad, gst_harness_src_query);
   gst_pad_set_event_function (h->srcpad, gst_harness_src_event);
 
@@ -600,8 +640,8 @@ gst_harness_setup_sink_pad (GstHarness * h,
   /* receiving pad */
   h->sinkpad = gst_pad_new_from_static_template (sink_tmpl, "sink");
   g_assert (h->sinkpad);
-  g_object_set_data (G_OBJECT (h->sinkpad), HARNESS_KEY, h);
 
+  gst_harness_pad_link_set (h->sinkpad, h);
   gst_pad_set_chain_function (h->sinkpad, gst_harness_chain);
   gst_pad_set_query_function (h->sinkpad, gst_harness_sink_query);
   gst_pad_set_event_function (h->sinkpad, gst_harness_sink_event);
@@ -1090,10 +1130,9 @@ gst_harness_teardown (GstHarness * h)
 
     /* Make sure our funcs are not called after harness is teared down since
      * they try to access this harness through pad data */
-    GST_PAD_STREAM_LOCK (h->srcpad);
+    gst_harness_pad_link_tear_down (h->srcpad);
     gst_pad_set_event_function (h->srcpad, NULL);
     gst_pad_set_query_function (h->srcpad, NULL);
-    GST_PAD_STREAM_UNLOCK (h->srcpad);
 
     gst_object_unref (h->srcpad);
   }
@@ -1108,11 +1147,10 @@ gst_harness_teardown (GstHarness * h)
 
     /* Make sure our funcs are not called after harness is teared down since
      * they try to access this harness through pad data */
-    GST_PAD_STREAM_LOCK (h->sinkpad);
+    gst_harness_pad_link_tear_down (h->sinkpad);
     gst_pad_set_chain_function (h->sinkpad, NULL);
     gst_pad_set_event_function (h->sinkpad, NULL);
     gst_pad_set_query_function (h->sinkpad, NULL);
-    GST_PAD_STREAM_UNLOCK (h->sinkpad);
 
     gst_object_unref (h->sinkpad);
   }
@@ -2898,13 +2936,13 @@ gst_harness_thread_init (GstHarnessThread * t, GDestroyNotify freefunc,
 static void
 gst_harness_thread_free (GstHarnessThread * t)
 {
-  g_slice_free (GstHarnessThread, t);
+  g_free (t);
 }
 
 static void
 gst_harness_custom_thread_free (GstHarnessCustomThread * t)
 {
-  g_slice_free (GstHarnessCustomThread, t);
+  g_free (t);
 }
 
 static void
@@ -2914,7 +2952,7 @@ gst_harness_push_buffer_thread_free (GstHarnessPushBufferThread * t)
     gst_caps_replace (&t->caps, NULL);
     if (t->notify != NULL)
       t->notify (t->data);
-    g_slice_free (GstHarnessPushBufferThread, t);
+    g_free (t);
   }
 }
 
@@ -2924,7 +2962,7 @@ gst_harness_push_event_thread_free (GstHarnessPushEventThread * t)
   if (t != NULL) {
     if (t->notify != NULL)
       t->notify (t->data);
-    g_slice_free (GstHarnessPushEventThread, t);
+    g_free (t);
   }
 }
 
@@ -2934,7 +2972,7 @@ gst_harness_property_thread_free (GstHarnessPropThread * t)
   if (t != NULL) {
     g_free (t->name);
     g_value_unset (&t->value);
-    g_slice_free (GstHarnessPropThread, t);
+    g_free (t);
   }
 }
 
@@ -2963,7 +3001,7 @@ gst_harness_requestpad_thread_free (GstHarnessReqPadThread * t)
     gst_caps_replace (&t->caps, NULL);
 
     gst_harness_requestpad_release_pads (t);
-    g_slice_free (GstHarnessReqPadThread, t);
+    g_free (t);
   }
 }
 
@@ -3209,7 +3247,7 @@ GstHarnessThread *
 gst_harness_stress_custom_start (GstHarness * h,
     GFunc init, GFunc callback, gpointer data, gulong sleep)
 {
-  GstHarnessCustomThread *t = g_slice_new0 (GstHarnessCustomThread);
+  GstHarnessCustomThread *t = g_new0 (GstHarnessCustomThread, 1);
   gst_harness_thread_init (&t->t,
       (GDestroyNotify) gst_harness_custom_thread_free, h, sleep);
 
@@ -3239,7 +3277,7 @@ gst_harness_stress_custom_start (GstHarness * h,
 GstHarnessThread *
 gst_harness_stress_statechange_start_full (GstHarness * h, gulong sleep)
 {
-  GstHarnessThread *t = g_slice_new0 (GstHarnessThread);
+  GstHarnessThread *t = g_new0 (GstHarnessThread, 1);
   gst_harness_thread_init (t,
       (GDestroyNotify) gst_harness_thread_free, h, sleep);
   GST_HARNESS_THREAD_START (statechange, t);
@@ -3312,7 +3350,7 @@ gst_harness_stress_push_buffer_with_cb_start_full (GstHarness * h,
     GstHarnessPrepareBufferFunc func, gpointer data, GDestroyNotify notify,
     gulong sleep)
 {
-  GstHarnessPushBufferThread *t = g_slice_new0 (GstHarnessPushBufferThread);
+  GstHarnessPushBufferThread *t = g_new0 (GstHarnessPushBufferThread, 1);
   gst_harness_thread_init (&t->t,
       (GDestroyNotify) gst_harness_push_buffer_thread_free, h, sleep);
 
@@ -3375,7 +3413,7 @@ gst_harness_stress_push_event_with_cb_start_full (GstHarness * h,
     GstHarnessPrepareEventFunc func, gpointer data, GDestroyNotify notify,
     gulong sleep)
 {
-  GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
+  GstHarnessPushEventThread *t = g_new0 (GstHarnessPushEventThread, 1);
   gst_harness_thread_init (&t->t,
       (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
 
@@ -3436,7 +3474,7 @@ gst_harness_stress_push_upstream_event_with_cb_start_full (GstHarness * h,
     GstHarnessPrepareEventFunc func, gpointer data, GDestroyNotify notify,
     gulong sleep)
 {
-  GstHarnessPushEventThread *t = g_slice_new0 (GstHarnessPushEventThread);
+  GstHarnessPushEventThread *t = g_new0 (GstHarnessPushEventThread, 1);
   gst_harness_thread_init (&t->t,
       (GDestroyNotify) gst_harness_push_event_thread_free, h, sleep);
 
@@ -3468,7 +3506,7 @@ GstHarnessThread *
 gst_harness_stress_property_start_full (GstHarness * h,
     const gchar * name, const GValue * value, gulong sleep)
 {
-  GstHarnessPropThread *t = g_slice_new0 (GstHarnessPropThread);
+  GstHarnessPropThread *t = g_new0 (GstHarnessPropThread, 1);
   gst_harness_thread_init (&t->t,
       (GDestroyNotify) gst_harness_property_thread_free, h, sleep);
 
@@ -3503,7 +3541,7 @@ gst_harness_stress_requestpad_start_full (GstHarness * h,
     GstPadTemplate * templ, const gchar * name, GstCaps * caps,
     gboolean release, gulong sleep)
 {
-  GstHarnessReqPadThread *t = g_slice_new0 (GstHarnessReqPadThread);
+  GstHarnessReqPadThread *t = g_new0 (GstHarnessReqPadThread, 1);
   gst_harness_thread_init (&t->t,
       (GDestroyNotify) gst_harness_requestpad_thread_free, h, sleep);
 
diff --git a/libs/gst/check/gstharnesslink.c b/libs/gst/check/gstharnesslink.c
new file mode 100644
index 0000000..0a16d35
--- /dev/null
+++ b/libs/gst/check/gstharnesslink.c
@@ -0,0 +1,230 @@
+/* GstHarnessLink - A ref counted class arbitrating access to a
+ * pad harness in a thread-safe manner.
+ *
+ * Copyright (C) 2023 Igalia S.L.
+ * Copyright (C) 2023 Metrological
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstharnesslink.h"
+
+/* The HARNESS_LINK association inside a GstPad will store a pointer to
+ * GstHarnessLink, which can be used to read and atomically lock the harness
+ * while in use. */
+#define HARNESS_LINK "harness-link"
+
+struct _GstHarnessLink
+{
+  /* rw_lock will be locked for writing for tearing down the harness,
+   * and locked for reading for any other use. The goal is to allow simultaneous
+   * access to the harness from multiple threads while guaranteeing that the
+   * resources of harness won't be freed during use. */
+  GRWLock rw_lock;
+  GstHarness *harness;
+};
+
+static void
+gst_harness_link_init (GstHarnessLink * link)
+{
+  g_rw_lock_init (&link->rw_lock);
+}
+
+static void
+gst_harness_link_dispose (GstHarnessLink * link)
+{
+  gboolean lock_acquired = g_rw_lock_writer_trylock (&link->rw_lock);
+  if (lock_acquired)
+    g_rw_lock_writer_unlock (&link->rw_lock);
+  else
+    g_critical
+        ("GstHarnessLink was about to be disposed while having the lock in use.");
+
+  g_rw_lock_clear (&link->rw_lock);
+}
+
+static GstHarnessLink *
+gst_harness_link_new (void)
+{
+  GstHarnessLink *link = g_atomic_rc_box_new0 (GstHarnessLink);
+  gst_harness_link_init (link);
+  return link;
+}
+
+static GstHarnessLink *
+gst_harness_link_ref (GstHarnessLink * link)
+{
+  return g_atomic_rc_box_acquire (link);
+}
+
+static void
+gst_harness_link_unref (GstHarnessLink * link)
+{
+  g_atomic_rc_box_release_full (link,
+      (GDestroyNotify) gst_harness_link_dispose);
+}
+
+/**
+ * gst_harness_pad_link_set: (skip)
+ * @pad: (transfer none): The pad that will be associated with a #GstHarness.
+ * @harness: (transfer none): The #GstHarness that will be associated with the
+ * pad.
+ *
+ * Creates a new #GstHarnessLink pointing to the provided @harness and
+ * associates it to the provided @pad.
+ *
+ * Once this association is set, the #GstHarness can be obtained using
+ * @gst_harness_pad_link_lock, which will also lock it until
+ * @gst_harness_link_unlock is called to prevent the #GstHarness from being
+ * destroyed while in use.
+ */
+void
+gst_harness_pad_link_set (GstPad * pad, GstHarness * harness)
+{
+  GstHarnessLink *link = gst_harness_link_new ();
+  link->harness = harness;
+  // The pad will own a reference to GstHarnessLink.
+  g_object_set_data_full (G_OBJECT (pad), HARNESS_LINK,
+      link, (GDestroyNotify) gst_harness_link_unref);
+}
+
+static gpointer
+_gst_harness_link_dup_func (gpointer harness_link, gpointer user_data)
+{
+  if (harness_link)
+    gst_harness_link_ref (harness_link);
+  return harness_link;
+}
+
+/**
+ * gst_harness_pad_link_lock: (skip)
+ * @pad: (transfer none): A #GstPad that has been at one point associated to a
+ * #GstHarness.
+ * @dst_harness: (transfer none): An address where the pointer to #GstHarness
+ * will be placed.
+ *
+ * Find a #GstHarness associated with this @pad and place a pointer to it on
+ * @dst_harness, locking it to prevent it being destroyed while in use.
+ *
+ * Both @dst_harness and the return value will be set to %NULL if the @pad is no
+ * longer linked to a GstHarness. Generally user code will need to handle this
+ * gracefully.
+ *
+ * Call @gst_harness_link_unlock once you're done using #GstHarness.
+ *
+ * Locking the link in this manner is reentrant: it is valid to lock the pad
+ * link more than once from the same thread as long as @gst_harness_link_unlock
+ * is called after exactly that many times.
+ *
+ * Returns: (transfer full) (nullable): a #GstHarnessLink object that you must
+ * pass to @gst_harness_link_unlock after being done with the #GstHarness, or
+ * %NULL if the link has been torn down at this point.
+ */
+GstHarnessLink *
+gst_harness_pad_link_lock (GstPad * pad, GstHarness ** dst_harness)
+{
+  // g_object_dup_data() will call _gst_harness_link_dup_func() while holding
+  // the mutex of the GObject association table. This guarantees that the
+  // GstHarnessLink is not destroyed between the time we get the pointer to it
+  // and increase its refcount.
+  GstHarnessLink *link = g_object_dup_data (G_OBJECT (pad), HARNESS_LINK,
+      _gst_harness_link_dup_func, NULL);
+  if (!link) {
+    // There is no longer a link between this pad and a GstHarness, as there is
+    // no associated GstHarnessLink.
+    *dst_harness = NULL;
+    return NULL;
+  }
+  g_rw_lock_reader_lock (&link->rw_lock);
+  if ((*dst_harness = link->harness)) {
+    // This GstHarnessLink has a valid link to GstHarness and will remain valid
+    // for at least as long as the user holds the lock.
+    return link;
+  } else {
+    // This GstHarnessLink has been torn down, it no longer points to a
+    // GstHarness. This will happen if we lock the link just after another
+    // thread torn it down. The GstHarnessLink will stay alive for a little
+    // longer until its refcount runs out.
+    g_rw_lock_reader_unlock (&link->rw_lock);
+    gst_harness_link_unref (link);
+    return NULL;
+  }
+}
+
+/**
+ * gst_harness_link_unlock: (skip)
+ * @link: (nullable) (transfer full): A #GstHarnessLink.
+ *
+ * Release the lock of the harness link for this particular thread.
+ *
+ * Whenever @gst_harness_pad_link_lock returns non-NULL this function must be
+ * called after the caller has finished use of the #GstHarness.
+ *
+ * The harness data must not be accessed after this function is called, as it is
+ * no longer guaranteed not to be destroyed.
+ *
+ * For convenience, the function will accept %NULL, in which case it will do
+ * nothing.
+ */
+void
+gst_harness_link_unlock (GstHarnessLink * link)
+{
+  if (!link)
+    return;
+
+  g_rw_lock_reader_unlock (&link->rw_lock);
+  gst_harness_link_unref (link);
+}
+
+/**
+ * gst_harness_pad_link_tear_down: (skip)
+ * @pad: (transfer none): A #GstPad that has been at one point associated to a
+ * #GstHarness.
+ *
+ * Reset the link to the harness. Further calls to @gst_harness_pad_link_lock
+ * will return NULL.
+ *
+ * This function will block until every thread that successfully locked the
+ * harness link with @gst_harness_pad_link_lock has unlocked it with
+ * @gst_harness_link_unlock.
+ */
+void
+gst_harness_pad_link_tear_down (GstPad * pad)
+{
+  // Steal the reference from the pad. This is still synchronized with
+  // g_object_dup_data().
+  GstHarnessLink *link = g_object_steal_data (G_OBJECT (pad), HARNESS_LINK);
+  g_return_if_fail (link != NULL);
+
+  // Take the lock for writing, which will wait for all threads that have locked
+  // the harness and will block future lock attempts until we unlock.
+  g_rw_lock_writer_lock (&link->rw_lock);
+  link->harness = NULL;
+  g_rw_lock_writer_unlock (&link->rw_lock);
+
+  // Unref the reference. In the likely case that no other thread has just done
+  // g_object_dup_data() and has therefore increase the refcount, this will be
+  // the last reference and terminate the GstHarnessLink.
+  gst_harness_link_unref (link);
+
+  // Even in the case where there is a remaining reference to GstHarnessLink in
+  // a different thread, the GstHarness pointer has been cleared at this point,
+  // so the caller thread can safely tear down the GstHarness.
+}
diff --git a/libs/gst/check/gstharnesslink.h b/libs/gst/check/gstharnesslink.h
new file mode 100644
index 0000000..5951187
--- /dev/null
+++ b/libs/gst/check/gstharnesslink.h
@@ -0,0 +1,57 @@
+/* GstHarnessLink - A ref counted class arbitrating access to a
+ * pad harness in a thread-safe manner.
+ *
+ * Copyright (C) 2023 Igalia S.L.
+ * Copyright (C) 2023 Metrological
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_HARNESS_LINK_H__
+#define __GST_HARNESS_LINK_H__
+
+#include <gst/gst.h>
+#include <gst/check/check-prelude.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstHarness GstHarness;
+
+/**
+ * GstHarnessLink: (skip)
+ *
+ * Opaque handle that can be used to release a pad lock over the harness.
+ */
+typedef struct _GstHarnessLink GstHarnessLink;
+
+G_GNUC_INTERNAL
+GType gst_harness_link_get_type (void);
+
+G_GNUC_INTERNAL
+void gst_harness_pad_link_set (GstPad* pad, GstHarness* harness);
+
+G_GNUC_INTERNAL
+GstHarnessLink* gst_harness_pad_link_lock (GstPad* pad, GstHarness** dst_harness);
+
+G_GNUC_INTERNAL
+void gst_harness_link_unlock (GstHarnessLink* link);
+
+G_GNUC_INTERNAL
+void gst_harness_pad_link_tear_down (GstPad* pad);
+
+G_END_DECLS
+
+#endif /* __GST_HARNESS_LINK_H__ */
diff --git a/libs/gst/check/gsttestclock.c b/libs/gst/check/gsttestclock.c
index 7d6849f..6223732 100644
--- a/libs/gst/check/gsttestclock.c
+++ b/libs/gst/check/gsttestclock.c
@@ -556,7 +556,7 @@ gst_test_clock_add_entry (GstTestClock * test_clock,
   if (jitter != NULL)
     *jitter = GST_CLOCK_DIFF (GST_CLOCK_ENTRY_TIME (entry), now);
 
-  ctx = g_slice_new (GstClockEntryContext);
+  ctx = g_new (GstClockEntryContext, 1);
   ctx->clock_entry = GST_CLOCK_ENTRY (gst_clock_id_ref (entry));
   ctx->time_diff = GST_CLOCK_DIFF (now, GST_CLOCK_ENTRY_TIME (entry));
 
@@ -576,7 +576,7 @@ gst_test_clock_remove_entry (GstTestClock * test_clock, GstClockEntry * entry)
   if (ctx != NULL) {
     gst_clock_id_unref (ctx->clock_entry);
     priv->entry_contexts = g_list_remove (priv->entry_contexts, ctx);
-    g_slice_free (GstClockEntryContext, ctx);
+    g_free (ctx);
 
     g_cond_broadcast (&priv->entry_processed_cond);
   }
diff --git a/libs/gst/check/libcheck/check_run.c b/libs/gst/check/libcheck/check_run.c
index a97379c..2b8a87f 100644
--- a/libs/gst/check/libcheck/check_run.c
+++ b/libs/gst/check/libcheck/check_run.c
@@ -386,7 +386,8 @@ tcase_run_tfun_nofork (SRunner * sr, TCase * tc, TF * tfun, int i)
 {
   TestResult *tr;
   struct timespec ts_start = { 0, 0 }, ts_end = {
-  0, 0};
+    0, 0
+  };
 
   tr = tcase_run_checked_setup (sr, tc);
   if (tr == NULL) {
@@ -448,7 +449,8 @@ tcase_run_tfun_fork (SRunner * sr, TCase * tc, TF * tfun, int i)
   pid_t pid;
   int status = 0;
   struct timespec ts_start = { 0, 0 }, ts_end = {
-  0, 0};
+    0, 0
+  };
 
   timer_t timerid;
   struct itimerspec timer_spec;
diff --git a/libs/gst/check/libcheck/libcompat/getline.c b/libs/gst/check/libcheck/libcompat/getline.c
index edc073f..6e85856 100644
--- a/libs/gst/check/libcheck/libcompat/getline.c
+++ b/libs/gst/check/libcheck/libcompat/getline.c
@@ -25,7 +25,7 @@
 #define DELIMITER '\n'
 
 ssize_t
-getline (char **lineptr, size_t * n, FILE * stream)
+getline (char **lineptr, size_t *n, FILE * stream)
 {
   ssize_t written = 0;
   int character;
diff --git a/libs/gst/check/meson.build b/libs/gst/check/meson.build
index 5cd583e..6b3a53f 100644
--- a/libs/gst/check/meson.build
+++ b/libs/gst/check/meson.build
@@ -3,6 +3,7 @@ gst_check_sources = files(
   'gstcheck.c',
   'gstconsistencychecker.c',
   'gstharness.c',
+  'gstharnesslink.c',
   'gsttestclock.c',
 )
 gst_check_headers = files(
@@ -81,6 +82,7 @@ if build_gir
   library_def += {'gir': [gir]}
   if not static_build
     gst_check_gir = gnome.generate_gir(gst_check, kwargs: gir)
+    library_def += {'gir_targets':  library_def.get('gir_targets', []) + [gst_check_gir]}
     gst_check_gen_sources += gst_check_gir
   endif
 endif
diff --git a/libs/gst/controller/gstinterpolationcontrolsource.c b/libs/gst/controller/gstinterpolationcontrolsource.c
index c0b6c86..5d473a7 100644
--- a/libs/gst/controller/gstinterpolationcontrolsource.c
+++ b/libs/gst/controller/gstinterpolationcontrolsource.c
@@ -607,15 +607,16 @@ static struct
   GstControlSourceGetValueArray get_value_array;
 } interpolation_modes[] = {
   {
-  (GstControlSourceGetValue) interpolate_none_get,
-        (GstControlSourceGetValueArray) interpolate_none_get_value_array}, {
-  (GstControlSourceGetValue) interpolate_linear_get,
-        (GstControlSourceGetValueArray) interpolate_linear_get_value_array}, {
-  (GstControlSourceGetValue) interpolate_cubic_get,
-        (GstControlSourceGetValueArray) interpolate_cubic_get_value_array}, {
-    (GstControlSourceGetValue) interpolate_cubic_monotonic_get,
+        (GstControlSourceGetValue) interpolate_none_get,
+      (GstControlSourceGetValueArray) interpolate_none_get_value_array}, {
+        (GstControlSourceGetValue) interpolate_linear_get,
+      (GstControlSourceGetValueArray) interpolate_linear_get_value_array}, {
+        (GstControlSourceGetValue) interpolate_cubic_get,
+      (GstControlSourceGetValueArray) interpolate_cubic_get_value_array}, {
+        (GstControlSourceGetValue) interpolate_cubic_monotonic_get,
         (GstControlSourceGetValueArray)
-interpolate_cubic_monotonic_get_value_array}};
+      interpolate_cubic_monotonic_get_value_array}
+};
 
 static const guint num_interpolation_modes = G_N_ELEMENTS (interpolation_modes);
 
diff --git a/libs/gst/controller/gstlfocontrolsource.c b/libs/gst/controller/gstlfocontrolsource.c
index 1706efd..582b7ec 100644
--- a/libs/gst/controller/gstlfocontrolsource.c
+++ b/libs/gst/controller/gstlfocontrolsource.c
@@ -352,16 +352,16 @@ static struct
   GstControlSourceGetValueArray get_value_array;
 } waveforms[] = {
   {
-  (GstControlSourceGetValue) waveform_sine_get,
-        (GstControlSourceGetValueArray) waveform_sine_get_value_array}, {
-  (GstControlSourceGetValue) waveform_square_get,
-        (GstControlSourceGetValueArray) waveform_square_get_value_array}, {
-  (GstControlSourceGetValue) waveform_saw_get,
-        (GstControlSourceGetValueArray) waveform_saw_get_value_array}, {
-  (GstControlSourceGetValue) waveform_rsaw_get,
-        (GstControlSourceGetValueArray) waveform_rsaw_get_value_array}, {
-  (GstControlSourceGetValue) waveform_triangle_get,
-        (GstControlSourceGetValueArray) waveform_triangle_get_value_array}
+        (GstControlSourceGetValue) waveform_sine_get,
+      (GstControlSourceGetValueArray) waveform_sine_get_value_array}, {
+        (GstControlSourceGetValue) waveform_square_get,
+      (GstControlSourceGetValueArray) waveform_square_get_value_array}, {
+        (GstControlSourceGetValue) waveform_saw_get,
+      (GstControlSourceGetValueArray) waveform_saw_get_value_array}, {
+        (GstControlSourceGetValue) waveform_rsaw_get,
+      (GstControlSourceGetValueArray) waveform_rsaw_get_value_array}, {
+        (GstControlSourceGetValue) waveform_triangle_get,
+      (GstControlSourceGetValueArray) waveform_triangle_get_value_array}
 };
 
 static const guint num_waveforms = G_N_ELEMENTS (waveforms);
diff --git a/libs/gst/controller/gsttimedvaluecontrolsource.c b/libs/gst/controller/gsttimedvaluecontrolsource.c
index 080df32..7325f42 100644
--- a/libs/gst/controller/gsttimedvaluecontrolsource.c
+++ b/libs/gst/controller/gsttimedvaluecontrolsource.c
@@ -78,7 +78,7 @@ gst_control_point_free (GstControlPoint * cp)
 {
   g_return_if_fail (cp);
 
-  g_slice_free (GstControlPoint, cp);
+  g_free (cp);
 }
 
 /**
@@ -92,7 +92,7 @@ gst_control_point_free (GstControlPoint * cp)
 GstControlPoint *
 gst_control_point_copy (GstControlPoint * cp)
 {
-  return g_slice_dup (GstControlPoint, cp);
+  return g_memdup2 (cp, sizeof (GstControlPoint));
 }
 
 GType
@@ -171,7 +171,7 @@ _make_new_cp (GstTimedValueControlSource * self, GstClockTime timestamp,
   GstControlPoint *cp;
 
   /* create a new GstControlPoint */
-  cp = g_slice_new0 (GstControlPoint);
+  cp = g_new0 (GstControlPoint, 1);
   cp->timestamp = timestamp;
   cp->value = value;
 
@@ -343,7 +343,7 @@ gst_timed_value_control_source_unset (GstTimedValueControlSource * self,
     /* Iter contains the iter right after timestamp, i.e.
      * we need to get the previous one and check the timestamp
      */
-    cp = g_slice_dup (GstControlPoint, g_sequence_get (iter));
+    cp = g_memdup2 (g_sequence_get (iter), sizeof (GstControlPoint));
     g_sequence_remove (iter);
     self->nvalues--;
     self->valid_cache = FALSE;
@@ -354,7 +354,7 @@ gst_timed_value_control_source_unset (GstTimedValueControlSource * self,
   if (cp) {
     g_signal_emit (self,
         gst_timed_value_control_source_signals[VALUE_REMOVED_SIGNAL], 0, cp);
-    g_slice_free (GstControlPoint, cp);
+    g_free (cp);
   }
 
   return res;
diff --git a/libs/gst/controller/meson.build b/libs/gst/controller/meson.build
index a5db2ce..5863df5 100644
--- a/libs/gst/controller/meson.build
+++ b/libs/gst/controller/meson.build
@@ -76,6 +76,7 @@ if build_gir
   library_def += {'gir': [gir]}
   if not static_build
     gst_controller_gir = gnome.generate_gir(gst_controller, kwargs: gir)
+    library_def += {'gir_targets':  library_def.get('gir_targets', []) + [gst_controller_gir]}
     gst_controller_gen_sources += [gst_controller_gir]
   endif
 endif
diff --git a/libs/gst/helpers/glib_gobject_helper.py b/libs/gst/helpers/glib_gobject_helper.py
index 5b08c38..9cf0581 100644
--- a/libs/gst/helpers/glib_gobject_helper.py
+++ b/libs/gst/helpers/glib_gobject_helper.py
@@ -1,5 +1,5 @@
 ##
-## imported from glib: glib/glib_gdb.py
+# imported from glib: glib/glib_gdb.py
 ##
 import gdb
 import sys
@@ -8,62 +8,103 @@ if sys.version_info[0] >= 3:
     long = int
 
 # This is not quite right, as local vars may override symname
-def read_global_var (symname):
+
+
+def read_global_var(symname):
     return gdb.selected_frame().read_var(symname)
 
-def g_quark_to_string (quark):
+
+def g_quark_to_string(quark):
     if quark is None:
         return None
     quark = long(quark)
     if quark == 0:
         return None
+    max_q = None
     try:
-        val = read_global_var ("quarks")
-        max_q = long(read_global_var ("quark_seq_id"))
-    except:
+        val = read_global_var("quarks")
+        try:
+            max_q = long(read_global_var("quark_seq_id"))
+        # quark_seq_id gets optimized out in some builds so work around it
+        except gdb.error:
+            pass
+    except Exception:
+        try:
+            val = read_global_var("g_quarks")
+            try:
+                max_q = long(read_global_var("g_quark_seq_id"))
+            except gdb.error:
+                pass
+        except Exception:
+            return None
+    if max_q is None or quark < max_q:
         try:
-            val = read_global_var ("g_quarks")
-            max_q = long(read_global_var ("g_quark_seq_id"))
-        except:
-            return None;
-    if quark < max_q:
-        return val[quark].string()
+            return val[quark].string()
+        except gdb.MemoryError:
+            print("Invalid quark %d" % quark)
     return None
 
 ##
-## imported from glib: gobject/gobject_gdb.py
+# imported from glib: gobject/gobject_gdb.py
 ##
 
-def g_type_to_typenode (gtype):
-    def lookup_fundamental_type (typenode):
+
+def is_fundamental(gtype):
+    gtype = long(gtype)
+    typenode = gtype - gtype % 4
+
+    return typenode < (255 << 2)
+
+
+def g_type_to_typenode(gtype):
+    def lookup_fundamental_type(typenode):
         if typenode == 0:
             return None
-        val = read_global_var ("static_fundamental_type_nodes")
-        if val is None:
+        val = read_global_var("static_fundamental_type_nodes")
+        if val is None or val.is_optimized_out:
             return None
         return val[typenode >> 2].address
 
     gtype = long(gtype)
     typenode = gtype - gtype % 4
-    if typenode > (255 << 2):
-        typenode = gdb.Value(typenode).cast (gdb.lookup_type("TypeNode").pointer())
+    if not is_fundamental(gtype):
+        res = gdb.Value(typenode).cast(gdb.lookup_type("TypeNode").pointer())
     else:
-        typenode = lookup_fundamental_type (typenode)
-    return typenode
+        res = lookup_fundamental_type(typenode)
 
-def g_type_to_name (gtype):
+    return res
+
+
+def g_type_fundamental_name(gtype):
+    if is_fundamental(gtype):
+        return g_type_to_name(gtype)
+    else:
+        typenode = g_type_to_typenode(gtype)
+        if typenode:
+            return g_quark_to_string(typenode["qname"])
+        return None
+
+    return g_type_to_name(typenode["supers"][int(typenode["n_supers"])])
+
+
+def g_type_to_name(gtype):
     typenode = g_type_to_typenode(gtype)
-    if typenode != None:
-        return g_quark_to_string (typenode["qname"])
-    return None
+    if typenode:
+        return g_quark_to_string(typenode["qname"])
+
+    try:
+        return gdb.parse_and_eval(f"g_type_name({gtype})").string()
+    except Exception:
+        return None
+
 
-def g_type_name_from_instance (instance):
+def g_type_name_from_instance(instance):
     if long(instance) != 0:
         try:
-            inst = instance.cast (gdb.lookup_type("GTypeInstance").pointer())
+            inst = instance.cast(gdb.lookup_type("GTypeInstance").pointer())
             klass = inst["g_class"]
             gtype = klass["g_type"]
-            name = g_type_to_name (gtype)
+            name = g_type_to_name(gtype)
             return name
         except RuntimeError:
             pass
diff --git a/libs/gst/helpers/gst-plugin-scanner.c b/libs/gst/helpers/gst-plugin-scanner.c
index cbefb29..f83e50f 100644
--- a/libs/gst/helpers/gst-plugin-scanner.c
+++ b/libs/gst/helpers/gst-plugin-scanner.c
@@ -37,11 +37,28 @@ main (int argc, char *argv[])
   gboolean res;
   char **my_argv;
   int my_argc;
+  char *pipe_name = NULL;
 
+#ifdef G_OS_WIN32
+  /* On Windows, we need pipe name
+   * arg0: exe path
+   * arg1: -l
+   * arg2: parent process exe path
+   * arg3: pipe name */
+  if (argc != 4)
+    return 1;
+
+  _gst_executable_path = g_strdup (argv[2]);
+  pipe_name = argv[3];
+#else
   /* We may or may not have an executable path */
   if (argc != 2 && argc != 3)
     return 1;
 
+  if (argc == 3)
+    _gst_executable_path = g_strdup (argv[2]);
+#endif
+
   if (strcmp (argv[1], "-l"))
     return 1;
 
@@ -54,9 +71,6 @@ main (int argc, char *argv[])
   _gst_disable_registry_cache = TRUE;
 #endif
 
-  if (argc == 3)
-    _gst_executable_path = g_strdup (argv[2]);
-
   res = gst_init_check (&my_argc, &my_argv, NULL);
 
   g_free (my_argv);
@@ -64,7 +78,7 @@ main (int argc, char *argv[])
     return 1;
 
   /* Create registry scanner listener and run */
-  if (!_gst_plugin_loader_client_run ())
+  if (!_gst_plugin_loader_client_run (pipe_name))
     return 1;
 
   return 0;
diff --git a/libs/gst/helpers/gst-ptp-helper.c b/libs/gst/helpers/gst-ptp-helper.c
deleted file mode 100644
index 4e8ab36..0000000
--- a/libs/gst/helpers/gst-ptp-helper.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/* GStreamer
- * Copyright (C) 2015 Sebastian Dröge <sebastian@centricular.com>
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-/* Helper process that runs setuid root or with appropriate privileges to
- * listen on ports < 1024, do multicast operations and get MAC addresses of
- * interfaces. Privileges are dropped after these operations are done.
- *
- * It listens on the PTP multicast group on port 319 and 320 and forwards
- * everything received there to stdout, while forwarding everything received
- * on stdout to those sockets.
- * Additionally it provides the MAC address of a network interface via stdout
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <string.h>
-
-#ifdef HAVE_GETIFADDRS_AF_LINK
-#include <ifaddrs.h>
-#include <net/if_dl.h>
-#endif
-
-#ifdef HAVE_PTP_HELPER_SETUID
-#include <grp.h>
-#include <pwd.h>
-#endif
-
-#ifdef HAVE_PTP_HELPER_CAPABILITIES
-#include <sys/capability.h>
-#endif
-
-#include <glib.h>
-#include <gio/gio.h>
-
-#include <gst/gst.h>
-#include <gst/net/gstptp_private.h>
-
-#define PTP_MULTICAST_GROUP "224.0.1.129"
-#define PTP_EVENT_PORT   319
-#define PTP_GENERAL_PORT 320
-
-static gchar **ifaces = NULL;
-static gboolean verbose = FALSE;
-static guint64 clock_id = (guint64) - 1;
-static guint8 clock_id_array[8];
-
-static GOptionEntry opt_entries[] = {
-  {"interface", 'i', 0, G_OPTION_ARG_STRING_ARRAY, &ifaces,
-      "Interface to listen on", NULL},
-  {"clock-id", 'c', 0, G_OPTION_ARG_INT64, &clock_id,
-      "PTP clock id", NULL},
-  {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
-      "Be verbose", NULL},
-  {NULL}
-};
-
-static GSocketAddress *event_saddr, *general_saddr;
-static GSocket *socket_event, *socket_general;
-static GIOChannel *stdin_channel, *stdout_channel;
-
-static gboolean
-have_socket_data_cb (GSocket * socket, GIOCondition condition,
-    gpointer user_data)
-{
-  gchar buffer[8192];
-  gssize read;
-  gsize written;
-  GError *err = NULL;
-  GIOStatus status;
-  StdIOHeader header = { 0, };
-
-  read = g_socket_receive (socket, buffer, sizeof (buffer), NULL, &err);
-  if (read == -1)
-    g_error ("Failed to read from socket: %s", err->message);
-  g_clear_error (&err);
-
-  if (verbose)
-    g_message ("Received %" G_GSSIZE_FORMAT " bytes from %s socket", read,
-        (socket == socket_event ? "event" : "general"));
-
-  header.size = read;
-  header.type = (socket == socket_event) ? TYPE_EVENT : TYPE_GENERAL;
-
-  status =
-      g_io_channel_write_chars (stdout_channel, (gchar *) & header,
-      sizeof (header), &written, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    g_error ("Failed to write to stdout: %s", err->message);
-    g_clear_error (&err);
-  } else if (status == G_IO_STATUS_EOF) {
-    g_message ("EOF on stdout");
-    exit (0);
-  } else if (status != G_IO_STATUS_NORMAL) {
-    g_error ("Unexpected stdout write status: %d", status);
-  } else if (written != sizeof (header)) {
-    g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
-  }
-
-  status =
-      g_io_channel_write_chars (stdout_channel, buffer, read, &written, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    g_error ("Failed to write to stdout: %s", err->message);
-    g_clear_error (&err);
-  } else if (status == G_IO_STATUS_EOF) {
-    g_message ("EOF on stdout");
-    exit (0);
-  } else if (status != G_IO_STATUS_NORMAL) {
-    g_error ("Unexpected stdout write status: %d", status);
-  } else if (written != read) {
-    g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
-  }
-
-  return G_SOURCE_CONTINUE;
-}
-
-static gboolean
-have_stdin_data_cb (GIOChannel * channel, GIOCondition condition,
-    gpointer user_data)
-{
-  GIOStatus status;
-  StdIOHeader header = { 0, };
-  gchar buffer[8192];
-  GError *err = NULL;
-  gsize read;
-  gssize written;
-
-  if ((condition & G_IO_STATUS_EOF)) {
-    g_message ("EOF on stdin");
-    exit (0);
-  }
-
-  status =
-      g_io_channel_read_chars (channel, (gchar *) & header, sizeof (header),
-      &read, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    g_error ("Failed to read from stdin: %s", err->message);
-    g_clear_error (&err);
-  } else if (status == G_IO_STATUS_EOF) {
-    g_message ("EOF on stdin");
-    exit (0);
-  } else if (status != G_IO_STATUS_NORMAL) {
-    g_error ("Unexpected stdin read status: %d", status);
-  } else if (read != sizeof (header)) {
-    g_error ("Unexpected read size: %" G_GSIZE_FORMAT, read);
-  } else if (header.size > 8192) {
-    g_error ("Unexpected size: %u", header.size);
-  }
-
-  status = g_io_channel_read_chars (channel, buffer, header.size, &read, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    g_error ("Failed to read from stdin: %s", err->message);
-    g_clear_error (&err);
-  } else if (status == G_IO_STATUS_EOF) {
-    g_message ("EOF on stdin");
-    exit (0);
-  } else if (status != G_IO_STATUS_NORMAL) {
-    g_error ("Unexpected stdin read status: %d", status);
-  } else if (read != header.size) {
-    g_error ("Unexpected read size: %" G_GSIZE_FORMAT, read);
-  }
-
-  switch (header.type) {
-    case TYPE_EVENT:
-    case TYPE_GENERAL:
-      written =
-          g_socket_send_to (header.type ==
-          TYPE_EVENT ? socket_event : socket_general,
-          (header.type == TYPE_EVENT ? event_saddr : general_saddr), buffer,
-          header.size, NULL, &err);
-      if (written == -1)
-        g_error ("Failed to write to socket: %s", err->message);
-      else if (written != header.size)
-        g_error ("Unexpected write size: %" G_GSSIZE_FORMAT, written);
-      g_clear_error (&err);
-      if (verbose)
-        g_message ("Sent %" G_GSSIZE_FORMAT " bytes to %s socket", read,
-            (header.type == TYPE_EVENT ? "event" : "general"));
-      break;
-    default:
-      break;
-  }
-
-  return G_SOURCE_CONTINUE;
-}
-
-static void
-setup_sockets (void)
-{
-  GInetAddress *bind_addr, *mcast_addr;
-  GSocketAddress *bind_saddr;
-  GSource *socket_event_source, *socket_general_source;
-  gchar **probed_ifaces = NULL;
-  GError *err = NULL;
-
-  /* Create sockets */
-  socket_event =
-      g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
-      G_SOCKET_PROTOCOL_UDP, &err);
-  if (!socket_event)
-    g_error ("Couldn't create event socket: %s", err->message);
-  g_clear_error (&err);
-
-  socket_general =
-      g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
-      G_SOCKET_PROTOCOL_UDP, &err);
-  if (!socket_general)
-    g_error ("Couldn't create general socket: %s", err->message);
-  g_clear_error (&err);
-
-  /* Bind sockets */
-  bind_addr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
-  bind_saddr = g_inet_socket_address_new (bind_addr, PTP_EVENT_PORT);
-  if (!g_socket_bind (socket_event, bind_saddr, TRUE, &err))
-    g_error ("Couldn't bind event socket: %s", err->message);
-  g_object_unref (bind_saddr);
-  bind_saddr = g_inet_socket_address_new (bind_addr, PTP_GENERAL_PORT);
-  if (!g_socket_bind (socket_general, bind_saddr, TRUE, &err))
-    g_error ("Couldn't bind general socket: %s", err->message);
-  g_object_unref (bind_saddr);
-  g_object_unref (bind_addr);
-
-  /* Probe all non-loopback interfaces */
-  if (!ifaces) {
-#if defined(HAVE_SIOCGIFCONF_SIOCGIFFLAGS_SIOCGIFHWADDR)
-    struct ifreq ifr;
-    struct ifconf ifc;
-    gchar buf[8192];
-
-    ifc.ifc_len = sizeof (buf);
-    ifc.ifc_buf = buf;
-    if (ioctl (g_socket_get_fd (socket_event), SIOCGIFCONF, &ifc) != -1) {
-      guint i, idx = 0;
-
-      probed_ifaces = g_new0 (gchar *, ifc.ifc_len + 1);
-
-      for (i = 0; i < ifc.ifc_len / sizeof (struct ifreq); i++) {
-        strncpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name, IFNAMSIZ);
-        if (ioctl (g_socket_get_fd (socket_event), SIOCGIFFLAGS, &ifr) == 0) {
-          if ((ifr.ifr_flags & IFF_LOOPBACK))
-            continue;
-          probed_ifaces[idx] = g_strndup (ifc.ifc_req[i].ifr_name, IFNAMSIZ);
-          idx++;
-        } else {
-          g_warning ("can't get flags of interface '%s'",
-              ifc.ifc_req[i].ifr_name);
-          probed_ifaces[idx] = g_strndup (ifc.ifc_req[i].ifr_name, IFNAMSIZ);
-          idx++;
-        }
-        if (idx != 0)
-          ifaces = probed_ifaces;
-      }
-    }
-#elif defined(HAVE_GETIFADDRS_AF_LINK)
-    struct ifaddrs *ifaddr, *ifa;
-
-    if (getifaddrs (&ifaddr) != -1) {
-      GPtrArray *arr;
-
-      arr = g_ptr_array_new ();
-
-      for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
-        if ((ifa->ifa_flags & IFF_LOOPBACK))
-          continue;
-
-        if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_LINK)
-          continue;
-
-        g_ptr_array_add (arr, g_strdup (ifa->ifa_name));
-      }
-      freeifaddrs (ifaddr);
-
-      g_ptr_array_add (arr, NULL);
-      ifaces = probed_ifaces = (gchar **) g_ptr_array_free (arr, FALSE);
-    }
-#else
-#warning "Implement something to list all network interfaces"
-#endif
-  }
-
-  /* Get a clock id from the MAC address if none was given */
-  if (clock_id == (guint64) - 1) {
-    gboolean success = FALSE;
-
-#if defined(HAVE_SIOCGIFCONF_SIOCGIFFLAGS_SIOCGIFHWADDR)
-    struct ifreq ifr;
-
-    if (ifaces) {
-      gchar **ptr = ifaces;
-
-      while (*ptr) {
-        memcpy (ifr.ifr_name, *ptr, IFNAMSIZ);
-        if (ioctl (g_socket_get_fd (socket_event), SIOCGIFHWADDR, &ifr) == 0) {
-          clock_id_array[0] = ifr.ifr_hwaddr.sa_data[0];
-          clock_id_array[1] = ifr.ifr_hwaddr.sa_data[1];
-          clock_id_array[2] = ifr.ifr_hwaddr.sa_data[2];
-          clock_id_array[3] = 0xff;
-          clock_id_array[4] = 0xfe;
-          clock_id_array[5] = ifr.ifr_hwaddr.sa_data[3];
-          clock_id_array[6] = ifr.ifr_hwaddr.sa_data[4];
-          clock_id_array[7] = ifr.ifr_hwaddr.sa_data[5];
-          success = TRUE;
-          break;
-        }
-      }
-
-      ptr++;
-    } else {
-      struct ifconf ifc;
-      gchar buf[8192];
-
-      ifc.ifc_len = sizeof (buf);
-      ifc.ifc_buf = buf;
-      if (ioctl (g_socket_get_fd (socket_event), SIOCGIFCONF, &ifc) != -1) {
-        guint i;
-
-        for (i = 0; i < ifc.ifc_len / sizeof (struct ifreq); i++) {
-          strncpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name, IFNAMSIZ);
-          if (ioctl (g_socket_get_fd (socket_event), SIOCGIFFLAGS, &ifr) == 0) {
-            if ((ifr.ifr_flags & IFF_LOOPBACK))
-              continue;
-
-            if (ioctl (g_socket_get_fd (socket_event), SIOCGIFHWADDR,
-                    &ifr) == 0) {
-              clock_id_array[0] = ifr.ifr_hwaddr.sa_data[0];
-              clock_id_array[1] = ifr.ifr_hwaddr.sa_data[1];
-              clock_id_array[2] = ifr.ifr_hwaddr.sa_data[2];
-              clock_id_array[3] = 0xff;
-              clock_id_array[4] = 0xfe;
-              clock_id_array[5] = ifr.ifr_hwaddr.sa_data[3];
-              clock_id_array[6] = ifr.ifr_hwaddr.sa_data[4];
-              clock_id_array[7] = ifr.ifr_hwaddr.sa_data[5];
-              success = TRUE;
-              break;
-            }
-          } else {
-            g_warning ("can't get flags of interface '%s'",
-                ifc.ifc_req[i].ifr_name);
-          }
-        }
-      }
-    }
-#elif defined(HAVE_GETIFADDRS_AF_LINK)
-    struct ifaddrs *ifaddr, *ifa;
-
-    if (getifaddrs (&ifaddr) != -1) {
-      for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
-        struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
-        guint8 mac_addr[6];
-
-        if ((ifa->ifa_flags & IFF_LOOPBACK))
-          continue;
-
-        if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_LINK)
-          continue;
-
-        if (ifaces) {
-          gchar **p = ifaces;
-          gboolean found = FALSE;
-
-          while (*p) {
-            if (strcmp (*p, ifa->ifa_name) == 0) {
-              found = TRUE;
-              break;
-            }
-            p++;
-          }
-
-          if (!found)
-            continue;
-        }
-
-        if (sdl->sdl_alen != 6)
-          continue;
-
-        memcpy (mac_addr, LLADDR (sdl), sdl->sdl_alen);
-
-        clock_id_array[0] = mac_addr[0];
-        clock_id_array[1] = mac_addr[1];
-        clock_id_array[2] = mac_addr[2];
-        clock_id_array[3] = 0xff;
-        clock_id_array[4] = 0xfe;
-        clock_id_array[5] = mac_addr[3];
-        clock_id_array[6] = mac_addr[4];
-        clock_id_array[7] = mac_addr[5];
-        success = TRUE;
-        break;
-      }
-
-      freeifaddrs (ifaddr);
-    }
-#else
-#warning "Implement something to get MAC addresses of network interfaces"
-#endif
-
-    if (!success) {
-      g_warning ("can't get any MAC address, using random clock id");
-      clock_id = (((guint64) g_random_int ()) << 32) | (g_random_int ());
-      GST_WRITE_UINT64_BE (clock_id_array, clock_id);
-      clock_id_array[3] = 0xff;
-      clock_id_array[4] = 0xfe;
-    }
-  } else {
-    GST_WRITE_UINT64_BE (clock_id_array, clock_id);
-  }
-
-  /* Join multicast groups */
-  mcast_addr = g_inet_address_new_from_string (PTP_MULTICAST_GROUP);
-  if (ifaces) {
-    gchar **ptr = ifaces;
-    gboolean success = FALSE;
-
-    while (*ptr) {
-      gint c = 0;
-      if (!g_socket_join_multicast_group (socket_event, mcast_addr, FALSE, *ptr,
-              &err)
-          && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE))
-        g_warning ("Couldn't join multicast group on interface '%s': %s", *ptr,
-            err->message);
-      else
-        c++;
-      g_clear_error (&err);
-
-      if (!g_socket_join_multicast_group (socket_general, mcast_addr, FALSE,
-              *ptr, &err)
-          && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE))
-        g_warning ("Couldn't join multicast group on interface '%s': %s", *ptr,
-            err->message);
-      else
-        c++;
-      g_clear_error (&err);
-
-      if (c == 2)
-        success = TRUE;
-      ptr++;
-    }
-
-    if (!success) {
-      /* Join multicast group without any interface */
-      if (!g_socket_join_multicast_group (socket_event, mcast_addr, FALSE, NULL,
-              &err))
-        g_error ("Couldn't join multicast group: %s", err->message);
-      g_clear_error (&err);
-      if (!g_socket_join_multicast_group (socket_general, mcast_addr, FALSE,
-              NULL, &err))
-        g_error ("Couldn't join multicast group: %s", err->message);
-      g_clear_error (&err);
-    }
-  } else {
-    /* Join multicast group without any interface */
-    if (!g_socket_join_multicast_group (socket_event, mcast_addr, FALSE, NULL,
-            &err))
-      g_error ("Couldn't join multicast group: %s", err->message);
-    g_clear_error (&err);
-    if (!g_socket_join_multicast_group (socket_general, mcast_addr, FALSE, NULL,
-            &err))
-      g_error ("Couldn't join multicast group: %s", err->message);
-    g_clear_error (&err);
-  }
-
-  event_saddr = g_inet_socket_address_new (mcast_addr, PTP_EVENT_PORT);
-  general_saddr = g_inet_socket_address_new (mcast_addr, PTP_GENERAL_PORT);
-
-  /* Create socket sources */
-  socket_event_source =
-      g_socket_create_source (socket_event, G_IO_IN | G_IO_PRI, NULL);
-  g_source_set_priority (socket_event_source, G_PRIORITY_HIGH);
-  g_source_set_callback (socket_event_source, (GSourceFunc) have_socket_data_cb,
-      NULL, NULL);
-  g_source_attach (socket_event_source, NULL);
-  socket_general_source =
-      g_socket_create_source (socket_general, G_IO_IN | G_IO_PRI, NULL);
-  g_source_set_priority (socket_general_source, G_PRIORITY_DEFAULT);
-  g_source_set_callback (socket_general_source,
-      (GSourceFunc) have_socket_data_cb, NULL, NULL);
-  g_source_attach (socket_general_source, NULL);
-
-  g_strfreev (probed_ifaces);
-}
-
-static void
-drop_privileges (void)
-{
-#ifdef HAVE_PTP_HELPER_SETUID
-  /* Switch to the given user/group */
-#ifdef HAVE_PTP_HELPER_SETUID_GROUP
-  {
-    struct group *grp;
-
-    grp = getgrnam (HAVE_PTP_HELPER_SETUID_GROUP);
-    if (!grp)
-      g_error ("Failed to get group information '%s': %s",
-          HAVE_PTP_HELPER_SETUID_GROUP, g_strerror (errno));
-
-    if (setgid (grp->gr_gid) != 0)
-      g_error ("Failed to change to group '%s': %s",
-          HAVE_PTP_HELPER_SETUID_GROUP, g_strerror (errno));
-  }
-#endif
-
-#ifdef HAVE_PTP_HELPER_SETUID_USER
-  {
-    struct passwd *pwd;
-
-    pwd = getpwnam (HAVE_PTP_HELPER_SETUID_USER);
-    if (!pwd)
-      g_error ("Failed to get user information '%s': %s",
-          HAVE_PTP_HELPER_SETUID_USER, g_strerror (errno));
-
-#ifndef HAVE_PTP_HELPER_SETUID_GROUP
-    if (setgid (pwd->pw_gid) != 0)
-      g_error ("Failed to change to user group '%s': %s",
-          HAVE_PTP_HELPER_SETUID_USER, g_strerror (errno));
-#endif
-
-    if (setuid (pwd->pw_uid) != 0)
-      g_error ("Failed to change to user '%s': %s", HAVE_PTP_HELPER_SETUID_USER,
-          g_strerror (errno));
-  }
-#endif
-#endif
-#ifdef HAVE_PTP_HELPER_CAPABILITIES
-  /* Drop all capabilities */
-  {
-    cap_t caps;
-
-    caps = cap_get_proc ();
-    if (caps == 0)
-      g_error ("Failed to get process caps: %s", g_strerror (errno));
-    if (cap_clear (caps) != 0)
-      g_error ("Failed to clear caps: %s", g_strerror (errno));
-    if (cap_set_proc (caps) != 0)
-      g_error ("Failed to set process caps: %s", g_strerror (errno));
-  }
-#endif
-}
-
-static void
-setup_stdio_channels (void)
-{
-  GSource *stdin_source;
-
-  /* Create stdin source */
-  stdin_channel = g_io_channel_unix_new (STDIN_FILENO);
-  if (g_io_channel_set_encoding (stdin_channel, NULL,
-          NULL) == G_IO_STATUS_ERROR)
-    g_error ("Failed to set stdin to binary encoding");
-  g_io_channel_set_buffered (stdin_channel, FALSE);
-  stdin_source =
-      g_io_create_watch (stdin_channel, G_IO_IN | G_IO_PRI | G_IO_HUP);
-  g_source_set_priority (stdin_source, G_PRIORITY_DEFAULT);
-  g_source_set_callback (stdin_source, (GSourceFunc) have_stdin_data_cb, NULL,
-      NULL);
-  g_source_attach (stdin_source, NULL);
-
-  /* Create stdout channel */
-  stdout_channel = g_io_channel_unix_new (STDOUT_FILENO);
-  if (g_io_channel_set_encoding (stdout_channel, NULL,
-          NULL) == G_IO_STATUS_ERROR)
-    g_error ("Failed to set stdout to binary encoding");
-  g_io_channel_set_buffered (stdout_channel, FALSE);
-}
-
-static void
-write_clock_id (void)
-{
-  GError *err = NULL;
-  GIOStatus status;
-  StdIOHeader header = { 0, };
-  gsize written;
-
-  /* Write clock id to stdout */
-
-  header.type = TYPE_CLOCK_ID;
-  header.size = 8;
-  status =
-      g_io_channel_write_chars (stdout_channel, (gchar *) & header,
-      sizeof (header), &written, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    g_error ("Failed to write to stdout: %s", err->message);
-    g_clear_error (&err);
-  } else if (status == G_IO_STATUS_EOF) {
-    g_message ("EOF on stdout");
-    exit (0);
-  } else if (status != G_IO_STATUS_NORMAL) {
-    g_error ("Unexpected stdout write status: %d", status);
-  } else if (written != sizeof (header)) {
-    g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
-  }
-
-  status =
-      g_io_channel_write_chars (stdout_channel,
-      (const gchar *) clock_id_array, sizeof (clock_id_array), &written, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    g_error ("Failed to write to stdout: %s", err->message);
-    g_clear_error (&err);
-  } else if (status == G_IO_STATUS_EOF) {
-    g_message ("EOF on stdout");
-    exit (0);
-  } else if (status != G_IO_STATUS_NORMAL) {
-    g_error ("Unexpected stdout write status: %d", status);
-  } else if (written != sizeof (clock_id_array)) {
-    g_error ("Unexpected write size: %" G_GSIZE_FORMAT, written);
-  }
-}
-
-#ifdef __APPLE__
-static gint
-dummy_poll (GPollFD * fds, guint nfds, gint timeout)
-{
-  return g_poll (fds, nfds, timeout);
-}
-#endif
-
-gint
-main (gint argc, gchar ** argv)
-{
-  GOptionContext *opt_ctx;
-  GMainLoop *loop;
-  GError *err = NULL;
-
-  /* FIXME: Work around some side effects of the changes from
-   * https://bugzilla.gnome.org/show_bug.cgi?id=741054
-   *
-   * The modified poll function somehow calls setugid(), which
-   * then abort()s the application. Make sure that we use g_poll()
-   * here!
-   */
-#ifdef __APPLE__
-  {
-    GMainContext *context = g_main_context_default ();
-    g_main_context_set_poll_func (context, dummy_poll);
-  }
-#endif
-
-#ifdef HAVE_PTP_HELPER_SETUID
-  if (setuid (0) < 0)
-    g_error ("not running with superuser privileges");
-#endif
-
-  opt_ctx = g_option_context_new ("- GStreamer PTP helper process");
-  g_option_context_add_main_entries (opt_ctx, opt_entries, NULL);
-  if (!g_option_context_parse (opt_ctx, &argc, &argv, &err))
-    g_error ("Error parsing options: %s", err->message);
-  g_clear_error (&err);
-  g_option_context_free (opt_ctx);
-
-  setup_sockets ();
-  drop_privileges ();
-  setup_stdio_channels ();
-  write_clock_id ();
-
-  /* Get running */
-  loop = g_main_loop_new (NULL, FALSE);
-  g_main_loop_run (loop);
-
-  /* We never exit cleanly, so don't do cleanup */
-  g_assert_not_reached ();
-
-  return 0;
-}
diff --git a/libs/gst/helpers/gst_gdb.py b/libs/gst/helpers/gst_gdb.py
index 90374fb..364d4f3 100644
--- a/libs/gst/helpers/gst_gdb.py
+++ b/libs/gst/helpers/gst_gdb.py
@@ -23,7 +23,7 @@ import sys
 import re
 
 from glib_gobject_helper import g_type_to_name, g_type_name_from_instance, \
-    g_type_to_typenode, g_quark_to_string
+    g_type_to_typenode, g_quark_to_string, g_type_fundamental_name
 
 if sys.version_info[0] >= 3:
     long = int
@@ -92,8 +92,8 @@ class GstObjectPrettyPrinter:
 
 
 GST_SECOND = 1000000000
-GST_CLOCK_TIME_NONE = 2**64-1
-GST_CLOCK_STIME_NONE = -2**63
+GST_CLOCK_TIME_NONE = (2 ** 64) - 1
+GST_CLOCK_STIME_NONE = -(2 ** 63)
 
 
 def format_time(n, signed=False):
@@ -214,11 +214,8 @@ def _g_array_iter(array, element_type):
 
 
 def _g_value_get_value(val):
-    typenode = g_type_to_typenode(val["g_type"])
-    if not typenode:
-        return None
-    tname = g_quark_to_string(typenode["qname"])
-    fname = g_type_to_name(typenode["supers"][int(typenode["n_supers"])])
+    tname = g_type_to_name(val["g_type"])
+    fname = g_type_fundamental_name(val["g_type"])
     if fname in ("gchar", "guchar", "gboolean", "gint", "guint", "glong",
                  "gulong", "gint64", "guint64", "gfloat", "gdouble",
                  "gpointer", "GFlags"):
@@ -283,7 +280,7 @@ def gst_object_pipeline(obj):
         pass
 
     if not g_inherits_type(obj, "GstElement"):
-        raise Exception("Toplevel parent is not a GstElement")
+        raise Exception("Toplevel %s parent is not a GstElement" % obj)
     return obj.cast(gdb.lookup_type("GstElement").pointer())
 
 
@@ -361,8 +358,8 @@ class GdbGstCaps:
     def items(self):
         gdb_type = gdb.lookup_type("GstCapsArrayElement")
         for f in _g_array_iter(self.val["array"], gdb_type):
-            yield(GdbCapsFeatures(f["features"]),
-                  GdbGstStructure(f["structure"]))
+            yield (GdbCapsFeatures(f["features"]),
+                   GdbGstStructure(f["structure"]))
 
     def __eq__(self, other):
         if self.size() != other.size():
@@ -394,6 +391,7 @@ class GdbGstCaps:
         if len(items) != 1:
             _gdb_write(indent, prefix)
             prefix = ""
+        s = ""
         for (features, structure) in items:
             s = "%s %s" % (prefix, structure.name())
             tmp = str(features)
@@ -401,7 +399,7 @@ class GdbGstCaps:
                 s += "(" + tmp + ")"
             _gdb_write(indent, s)
             for val in structure.value_strings("%s: %s", False):
-                _gdb_write(indent+1, val)
+                _gdb_write(indent + 1, val)
         return s
 
 
@@ -438,7 +436,7 @@ class GdbGValue:
                 if step == 1:
                     v = "[ %d, %d ]" % (rmin, rmax)
                 else:
-                    v = "[ %d, %d, %d ]" % (rmin*step, rmax*step, step)
+                    v = "[ %d, %d, %d ]" % (rmin * step, rmax * step, step)
             elif tname == "GstFractionRange":
                 v = "[ %s, %s ]" % (GdbGValue(value[0]), GdbGValue(value[1]))
             elif tname in ("GstValueList", "GstValueArray"):
@@ -446,9 +444,9 @@ class GdbGValue:
                     gdb_type = gdb.lookup_type("GArray").pointer()
                     value = value[0]["v_pointer"].cast(gdb_type)
                 v = "<"
-                for l in _g_array_iter(value, gvalue_type):
+                for array_val in _g_array_iter(value, gvalue_type):
                     v += " " if v == "<" else ", "
-                    v += str(GdbGValue(l))
+                    v += str(GdbGValue(array_val))
                 v += " >"
             elif tname in ("GEnum"):
                 v = "%s(%s)" % (
@@ -490,7 +488,7 @@ class GdbGstStructure:
             f = item[i]
             key = g_quark_to_string(f["name"])
             value = GdbGValue(f["value"])
-            yield(key, value)
+            yield (key, value)
 
     def value(self, key):
         for (k, value) in self.values():
@@ -532,7 +530,8 @@ class GdbGstStructure:
 
 class GdbGstSegment:
     def __init__(self, val):
-        self.val = val
+        t = gdb.lookup_type("GstSegment").pointer().pointer()
+        self.val = val.cast(t).dereference()
         self.fmt = str(self.val["format"]).split("_")[-1].lower()
 
     def format_value(self, n):
@@ -545,7 +544,7 @@ class GdbGstSegment:
         value = int(self.val[key])
         if skip is None or value != skip:
             _gdb_write(indent, "%s:%s %s" %
-                       (key, (8-len(key))*" ", self.format_value(value)))
+                       (key, (8 - len(key)) * " ", self.format_value(value)))
 
     def print(self, indent, seqnum=None):
         s = "segment:"
@@ -558,14 +557,14 @@ class GdbGstSegment:
             applied = "(applied rate: %g)" % applied_rate
         else:
             applied = ""
-        _gdb_write(indent+1, "rate: %g%s" % (rate, applied))
-        self.print_optional(indent+1, "base", 0)
-        self.print_optional(indent+1, "offset", 0)
-        self.print_optional(indent+1, "start")
-        self.print_optional(indent+1, "stop", GST_CLOCK_TIME_NONE)
-        self.print_optional(indent+1, "time")
-        self.print_optional(indent+1, "position")
-        self.print_optional(indent+1, "duration", GST_CLOCK_TIME_NONE)
+        _gdb_write(indent + 1, "rate: %g%s" % (rate, applied))
+        self.print_optional(indent + 1, "base", 0)
+        self.print_optional(indent + 1, "offset", 0)
+        self.print_optional(indent + 1, "start")
+        self.print_optional(indent + 1, "stop", GST_CLOCK_TIME_NONE)
+        self.print_optional(indent + 1, "time")
+        self.print_optional(indent + 1, "position")
+        self.print_optional(indent + 1, "duration", GST_CLOCK_TIME_NONE)
 
 
 class GdbGstEvent:
@@ -596,7 +595,7 @@ class GdbGstEvent:
             caps.print(indent, "caps (seqnum: %s):" % seqnum)
         elif typestr == "stream-start":
             stream_id = self.structure().value("stream-id").value()
-            _gdb_write(indent, "stream-start: (seqnum %s)"  % seqnum)
+            _gdb_write(indent, "stream-start: (seqnum %s)" % seqnum)
             _gdb_write(indent + 1, "stream-id: %s" % stream_id.string())
         elif typestr == "segment":
             segment = self.structure().value("segment").value()
@@ -610,7 +609,7 @@ class GdbGstEvent:
             structure = GdbGstStructure(s)
             _gdb_write(indent, "tag: %s (seqnum: %s)" % (name, seqnum))
             for (key, value) in structure.values():
-                _gdb_write(indent+1, "%s: %s" % (key, str(value)))
+                _gdb_write(indent + 1, "%s: %s" % (key, str(value)))
         else:
             self.structure().print(indent, "%s (seqnum: %s)" % (typestr, seqnum))
 
@@ -623,7 +622,7 @@ class GdbGstBuffer:
         value = int(self.val[key])
         if skip is None or value != skip:
             _gdb_write(indent, "%s:%s %s" %
-                       (key, (8-len(key))*" ", format_func(value)))
+                       (key, (8 - len(key)) * " ", format_func(value)))
 
     @save_memory_access_print("<inaccessible memory>")
     def print(self, indent):
@@ -647,8 +646,8 @@ class GdbGstBuffer:
                 _gdb_write(indent, "%s:" % meta_type_name)
                 indent += 1
                 meta_info = str(meta.cast(gdb.lookup_type(meta_type_name)))
-                for l in meta_info.split('\n'):
-                    _gdb_write(indent, l)
+                for info in meta_info.split('\n'):
+                    _gdb_write(indent, info)
                 indent -= 1
                 meta_item = meta_item['next']
         else:
@@ -770,30 +769,30 @@ class GdbGstPad(GdbGstObject):
         first = True
         for ev in self.events():
             if first:
-                _gdb_write(indent+1, "events:")
+                _gdb_write(indent + 1, "events:")
                 first = False
-            ev.print(indent+2)
+            ev.print(indent + 2)
 
         if self.is_linked():
             real = self.peer().parent_pad()
-            _gdb_write(indent+1, "peer: %s" %
+            _gdb_write(indent + 1, "peer: %s" %
                        (real.full_name() if real else self.peer().full_name()))
 
         if g_inherits_type(self.val, "GstGhostPad"):
             t = gdb.lookup_type("GstProxyPad").pointer()
             internal = GdbGstPad(self.val.cast(t)["priv"]["internal"])
             if internal and internal.peer():
-                _gdb_write(indent+1, "inner peer: %s" %
+                _gdb_write(indent + 1, "inner peer: %s" %
                            internal.peer().full_name())
 
         task = self.val["task"]
         if long(task) != 0:
-            _gdb_write(indent+1, "task: %s" %
+            _gdb_write(indent + 1, "task: %s" %
                        task_state_to_name(int(task["state"])))
 
         offset = long(self.val["offset"])
         if offset != 0:
-            _gdb_write(indent+1, "offset: %d [%s]" %
+            _gdb_write(indent + 1, "offset: %d [%s]" %
                        (offset, format_time(offset, True)))
 
         _gdb_write(indent, "}")
@@ -852,10 +851,10 @@ class GdbGstPad(GdbGstObject):
                 other_pname = other.dot_name()
                 if direction == "GST_PAD_SRC":
                     s += "%s%s_%s -> %s_%s [style=dashed, minlen=0]\n" % \
-                       (spc, other_ename, other_pname, ename, pname)
+                        (spc, other_ename, other_pname, ename, pname)
                 else:
                     s += "%s%s_%s -> %s_%s [style=dashed, minlen=0]\n" % \
-                       (spc, ename, pname, other_ename, other_pname)
+                        (spc, ename, pname, other_ename, other_pname)
         else:
             if direction == "GST_PAD_SRC":
                 color = "#ffaaaa"
@@ -887,11 +886,11 @@ class GdbGstPad(GdbGstObject):
 
         if caps and peer_caps and caps == peer_caps:
             s = "%s%s_%s -> %s_%s [label=\"%s\"]\n" % \
-               (spc, ename, pname, peer_ename, peer_pname, caps.dot())
+                (spc, ename, pname, peer_ename, peer_pname, caps.dot())
         elif caps and peer_caps and caps != peer_caps:
             s = "%s%s_%s -> %s_%s [labeldistance=\"10\", labelangle=\"0\", " \
                 % (spc, ename, pname, peer_ename, peer_pname)
-            s += "label=\"" + " "*50 + "\", "
+            s += "label=\"" + " " * 50 + "\", "
             if self.direction() == "GST_PAD_SRC":
                 media_src = caps.dot()
                 media_dst = peer_caps.dot()
@@ -948,14 +947,14 @@ class GdbGstElement(GdbGstObject):
         _gdb_write(indent, "%s(%s) {" %
                    (g_type_name_from_instance(self.val), self.name()))
         for p in self.pads():
-            p.print(indent+2)
+            p.print(indent + 2)
 
         first = True
         for child in self.children():
             if first:
-                _gdb_write(indent+2, "children:")
+                _gdb_write(indent + 2, "children:")
                 first = False
-            _gdb_write(indent+3, child.name())
+            _gdb_write(indent + 3, child.name())
 
         current_state = self.val["current_state"]
         s = "state: %s" % element_state_to_name(current_state)
@@ -963,11 +962,11 @@ class GdbGstElement(GdbGstObject):
             state = self.val[var + "_state"]
             if state > 0 and state != current_state:
                 s += ", %s: %s" % (var, element_state_to_name(state))
-        _gdb_write(indent+2, s)
+        _gdb_write(indent + 2, s)
 
-        _gdb_write(indent+2, "base_time: %s" %
+        _gdb_write(indent + 2, "base_time: %s" %
                    format_time_value(self.val["base_time"]))
-        _gdb_write(indent+2, "start_time: %s" %
+        _gdb_write(indent + 2, "start_time: %s" %
                    format_time_value(self.val["start_time"]))
 
         _gdb_write(indent, "}")
@@ -976,7 +975,7 @@ class GdbGstElement(GdbGstObject):
     def print_tree(self, indent):
         _gdb_write(indent, "%s(%s)" % (self.name(), self.val))
         for child in self.children():
-            child.print_tree(indent+1)
+            child.print_tree(indent + 1)
 
     def _dot(self, indent=0):
         spc = "  " * indent
@@ -992,12 +991,12 @@ class GdbGstElement(GdbGstObject):
 
         sink_name = None
         if self.has_pads("sinkpads"):
-            (ss, sink_name) = self._dot_pads(indent+1, "sinkpads",
+            (ss, sink_name) = self._dot_pads(indent + 1, "sinkpads",
                                              self.dot_name() + "_sink")
             s += ss
         src_name = None
         if self.has_pads("srcpads"):
-            (ss, src_name) = self._dot_pads(indent+1, "srcpads",
+            (ss, src_name) = self._dot_pads(indent + 1, "srcpads",
                                             self.dot_name() + "_src")
             s += ss
         if sink_name and src_name:
@@ -1007,7 +1006,7 @@ class GdbGstElement(GdbGstObject):
 
         if gst_is_bin(self.val):
             s += "%s  fillcolor=\"#ffffff\";\n" % spc
-            s += self.dot(indent+1)
+            s += self.dot(indent + 1)
         else:
             if src_name and not sink_name:
                 s += "%s  fillcolor=\"#ffaaaa\";\n" % spc
@@ -1042,7 +1041,7 @@ class GdbGstElement(GdbGstObject):
             if not name:
                 name = p.dot_name()
         s += "%s}\n\n" % spc
-        return(s, name)
+        return (s, name)
 
     def dot(self, indent):
         s = ""
@@ -1097,6 +1096,7 @@ GST_DEBUG_BIN_TO_DOT_FILE. This command will find the top-level parent
 for the given gstreamer object and create the dot for that element.
 
 Usage: gst-dot <gst-object> <file-name>"""
+
     def __init__(self):
         super(GstDot, self).__init__("gst-dot", gdb.COMMAND_DATA)
 
@@ -1120,7 +1120,7 @@ Usage: gst-dot <gst-object> <file-name>"""
 
     def complete(self, text, word):
         cmd = gdb.string_to_argv(text)
-        if len(cmd) == 0 or(len(cmd) == 1 and len(word) > 0):
+        if len(cmd) == 0 or (len(cmd) == 1 and len(word) > 0):
             return gdb.COMPLETE_SYMBOL
         return gdb.COMPLETE_FILENAME
 
@@ -1130,6 +1130,7 @@ class GstPrint(gdb.Command):
 Print high-level information for GStreamer objects
 
 Usage gst-print <gstreamer-object>"""
+
     def __init__(self):
         super(GstPrint, self).__init__("gst-print", gdb.COMMAND_DATA,
                                        gdb.COMPLETE_SYMBOL)
@@ -1165,6 +1166,7 @@ Usage gst-print <gstreamer-object>"""
 class GstPipelineTree(gdb.Command):
     """\
 Usage: gst-pipeline-tree <gst-object>"""
+
     def __init__(self):
         super(GstPipelineTree, self).__init__("gst-pipeline-tree",
                                               gdb.COMPLETE_SYMBOL)
diff --git a/libs/gst/helpers/meson.build b/libs/gst/helpers/meson.build
index 543064c..bb8c621 100644
--- a/libs/gst/helpers/meson.build
+++ b/libs/gst/helpers/meson.build
@@ -1,129 +1,49 @@
-exe = executable('gst-plugin-scanner',
-  'gst-plugin-scanner.c',
-  c_args : gst_c_args,
-  include_directories : [configinc],
-  dependencies : [gst_dep, mathlib, gmodule_dep,],
-  install_dir : helpers_install_dir,
-  install: true,
-)
-
-meson.add_devenv({'GST_PLUGIN_SCANNER': exe.full_path()})
-
-# Used in test env setup to make tests find plugin scanner in build tree
-gst_scanner_dir = meson.current_build_dir()
-
-if bashcomp_found
-  executable('gst-completion-helper',
-    'gst-completion-helper.c',
-    c_args : gst_c_args,
-    include_directories : [configinc],
-    dependencies : [gst_dep],
-    install_dir : helpers_install_dir,
-    install_tag : 'bin',
-    install: true,
-  )
-endif
-
-# Check PTP support
-have_ptp = false
-if host_system == 'android'
-  message('PTP not supported on Android because of permissions.')
-elif host_system == 'windows'
-  message('PTP not supported on Windows, not ported yet.')
-elif host_system == 'ios'
-  message('PTP not supported on iOS because of permissions.')
-elif ['linux', 'darwin', 'netbsd', 'freebsd', 'openbsd', 'kfreebsd', 'dragonfly', 'sunos', 'gnu', 'gnu/kfreebsd'].contains(host_system)
-  message('PTP supported on ' + host_system + '.')
-  have_ptp = true
-else
-  message('PTP not supported on ' + host_system + ', not ported yet.')
-endif
-
-if have_ptp
-  cdata.set('HAVE_PTP', 1, description : 'PTP support available')
-
-  if cc.compiles('''#include <sys/ioctl.h>
-                    #include <net/if.h>
-                    int some_func (void) {
-                      struct ifreq ifr;
-                      struct ifconf ifc;
-                      ioctl(0, SIOCGIFCONF, &ifc);
-                      ioctl(0, SIOCGIFFLAGS, &ifr);
-                      ioctl(0, SIOCGIFHWADDR, &ifr);
-                      return ifr.ifr_hwaddr.sa_data[0];
-                    }''',
-                 name : 'SIOCGIFCONF, SIOCGIFFLAGS and SIOCGIFHWADDR available')
-    cdata.set('HAVE_SIOCGIFCONF_SIOCGIFFLAGS_SIOCGIFHWADDR', 1,
-      description : 'SIOCGIFCONF, SIOCGIFFLAGS and SIOCGIFHWADDR is available')
-  endif
-
-  if cc.compiles('''#include <ifaddrs.h>
-                    #include <net/if.h>
-                    #include <net/if_dl.h>
-                    int some_func (void) {
-                      struct ifaddrs *ifaddr;
-                      getifaddrs(&ifaddr);
-                      return (ifaddr->ifa_flags & IFF_LOOPBACK) && ifaddr->ifa_addr->sa_family != AF_LINK;
-                    }''', name : 'getifaddrs() and AF_LINK available')
-    cdata.set('HAVE_GETIFADDRS_AF_LINK', 1,
-      description : 'getifaddrs() and AF_LINK is available')
-  endif
-
-  setcap_prog = find_program('setcap', '/usr/sbin/setcap', '/sbin/setcap', required : false)
-  cap_dep = dependency('libcap', required: false)
-
-  # user/group to change to in gst-ptp-helper
-  ptp_helper_setuid_user = get_option('ptp-helper-setuid-user')
-  if ptp_helper_setuid_user != ''
-    cdata.set_quoted('HAVE_PTP_HELPER_SETUID_USER', ptp_helper_setuid_user,
-      description : 'PTP helper setuid user')
-  endif
-  ptp_helper_setuid_group = get_option('ptp-helper-setuid-group')
-  if ptp_helper_setuid_group != ''
-    cdata.set_quoted('HAVE_PTP_HELPER_SETUID_GROUP', ptp_helper_setuid_group,
-      description : 'PTP helper setuid group')
-  endif
-
-  # how to install gst-ptp-helper
-  with_ptp_helper_permissions = get_option('ptp-helper-permissions')
-  if with_ptp_helper_permissions == 'auto'
-    if setcap_prog.found() and cap_dep.found()
-      with_ptp_helper_permissions = 'capabilities'
-    else
-      with_ptp_helper_permissions = 'setuid-root'
+subdir('ptp')
+
+gst_helpers = {
+  'gst-plugin-scanner': {
+    'files': files('gst-plugin-scanner.c'),
+    'deps': [gst_dep, mathlib, gmodule_dep],
+    'env': ['GST_PLUGIN_SCANNER', 'exe-full-path'],
+    'install_dir': helpers_install_dir,
+  },
+  'gst-completion-helper': {
+    'files': files('gst-completion-helper.c'),
+    'deps': [gst_dep],
+    'install_dir': helpers_install_dir,
+  },
+}
+
+if not get_option('tools').disabled() and not static_build
+  foreach helper, data: gst_helpers
+    exe_name = '@0@'.format(helper)
+    exe = executable(exe_name,
+      data.get('files'),
+      install: data.get('install', true),
+      install_tag: 'bin',
+      install_dir:  data.get('install_dir', get_option('bindir')),
+      include_directories : [configinc],
+      dependencies : data.get('deps', []),
+      c_args: data.get('extra_c_args', []) + ['-DG_LOG_DOMAIN="@0@"'.format(exe_name)],
+    )
+    if(data.has_key('env'))
+        env = data.get(('env'))
+        value = env[1]
+        if env[1] == 'exe-full-path'
+          value = exe.full_path()
+        endif
+        meson.add_devenv({env[0]: value})
     endif
-  endif
-  message('How to install gst-ptp-helper: ' + with_ptp_helper_permissions)
 
-  if with_ptp_helper_permissions == 'none'
-    # nothing to do
-  elif with_ptp_helper_permissions == 'setuid-root'
-    cdata.set('HAVE_PTP_HELPER_SETUID', 1,
-        description : 'Use setuid-root for permissions in PTP helper')
-  elif with_ptp_helper_permissions == 'capabilities'
-    if not setcap_prog.found()
-      error('capabilities-based ptp-helper-permissions requested, but could not find setcap tool.')
-    elif not cap_dep.found()
-      error('capabilities-based ptp-helper-permissions requested, but could not find libcap.')
+    if data.has_key('man_page')
+      install_man(data.get('man_page'))
     endif
-    cdata.set('HAVE_PTP_HELPER_CAPABILITIES', 1,
-        description : 'Use capabilities for permissions in PTP helper')
-  else
-    error('Unexpected ptp helper permissions value: ' + with_ptp_helper_permissions)
-  endif
+  endforeach
+endif
 
-  exe = executable('gst-ptp-helper', 'gst-ptp-helper.c',
-    c_args : gst_c_args,
-    include_directories : [configinc, libsinc],
-    dependencies : [gst_dep, gio_dep, mathlib, cap_dep],
-    install_dir : helpers_install_dir,
-    install : true)
+# Used in test env setup to make tests find plugin scanner in build tree
+gst_scanner_dir = meson.current_build_dir()
 
-  meson.add_install_script('ptp_helper_post_install.sh',
-      helpers_install_dir, with_ptp_helper_permissions,
-      setcap_prog.found() ? setcap_prog.full_path() : '')
-  meson.add_devenv({'GST_PTP_HELPER': exe.full_path()})
-endif
 
 install_data(['gst_gdb.py', 'glib_gobject_helper.py'],
   install_dir : join_paths(get_option('datadir'), 'gstreamer-@0@'.format(apiversion), 'gdb'),
diff --git a/libs/gst/helpers/ptp/args.rs b/libs/gst/helpers/ptp/args.rs
new file mode 100644
index 0000000..fa62c5f
--- /dev/null
+++ b/libs/gst/helpers/ptp/args.rs
@@ -0,0 +1,76 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+use std::env;
+
+use crate::{
+    bail,
+    error::{Context, Error},
+};
+
+/// Parsed command-line arguments.
+#[derive(Debug)]
+pub struct Args {
+    pub interfaces: Vec<String>,
+    pub verbose: bool,
+    pub clock_id: u64,
+    pub ttl: u32,
+}
+
+/// Parse the command-line arguments.
+pub fn parse_args() -> Result<Args, Error> {
+    let mut interfaces = Vec::new();
+    let mut verbose = false;
+    let mut clock_id = 0;
+    let mut ttl = 1;
+
+    let mut args = env::args();
+    // Skip executable name
+    let _ = args.next();
+
+    while let Some(arg) = args.next() {
+        match arg.as_str() {
+            "-v" | "--verbose" => {
+                verbose = true;
+            }
+            "-i" | "--interface" => {
+                let iface = args.next().context("No interface following -i")?;
+                interfaces.push(iface);
+            }
+            "-c" | "--clock-id" => {
+                let clock_id_arg = args.next().context("No clock-id following -c")?;
+                if !clock_id_arg.starts_with("0x") && !clock_id_arg.starts_with("0X") {
+                    bail!("Clock ID not starting with 0x");
+                }
+                clock_id =
+                    u64::from_str_radix(&clock_id_arg[2..], 16).context("Invalid clock ID")?;
+            }
+            "--ttl" => {
+                let ttl_arg = args.next().context("No TTL following --ttl")?;
+                ttl = ttl_arg.parse::<u32>().context("Invalid TTL value")?;
+            }
+
+            arg => {
+                bail!("Unknown command-line argument {}", arg);
+            }
+        }
+    }
+
+    let args = Args {
+        interfaces,
+        verbose,
+        clock_id,
+        ttl,
+    };
+
+    info!("Running with arguments {:#?}", args);
+
+    Ok(args)
+}
diff --git a/libs/gst/helpers/ptp/clock.rs b/libs/gst/helpers/ptp/clock.rs
new file mode 100644
index 0000000..9feb845
--- /dev/null
+++ b/libs/gst/helpers/ptp/clock.rs
@@ -0,0 +1,119 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+#[cfg(target_os = "macos")]
+/// Returns the monotonic system clock in nanoseconds or 0 on error.
+pub fn time() -> u64 {
+    use std::{
+        mem,
+        sync::atomic::{self, AtomicU32},
+    };
+
+    use crate::ffi::unix::macos::*;
+
+    static TIMEBASE_N: AtomicU32 = AtomicU32::new(0);
+    static TIMEBASE_D: AtomicU32 = AtomicU32::new(0);
+
+    let mut timebase_n = TIMEBASE_N.load(atomic::Ordering::Relaxed);
+    let mut timebase_d = TIMEBASE_D.load(atomic::Ordering::Relaxed);
+    if timebase_n == 0 || timebase_d == 0 {
+        // SAFETY: This is safe to call at any time and returns the timebase. Returns 0 on success.
+        unsafe {
+            let mut timebase = mem::MaybeUninit::uninit();
+            if mach_timebase_info(timebase.as_mut_ptr()) != 0 {
+                return 0;
+            }
+            let timebase = timebase.assume_init();
+            timebase_n = timebase.numer;
+            timebase_d = timebase.denom;
+
+            TIMEBASE_N.store(timebase_n, atomic::Ordering::Relaxed);
+            TIMEBASE_D.store(timebase_d, atomic::Ordering::Relaxed);
+        }
+    }
+
+    // SAFETY: This is safe to call at any time.
+    let time = unsafe { mach_absolute_time() };
+
+    (time as u128 * timebase_n as u128 / timebase_d as u128) as u64
+}
+
+#[cfg(target_os = "windows")]
+/// Returns the monotonic system clock in nanoseconds or 0 on error.
+pub fn time() -> u64 {
+    use std::{
+        mem,
+        sync::atomic::{self, AtomicI64},
+    };
+
+    use crate::ffi::windows::*;
+
+    static FREQUENCY: AtomicI64 = AtomicI64::new(0);
+
+    let mut freq = FREQUENCY.load(atomic::Ordering::Relaxed);
+    if freq == 0 {
+        // SAFETY: This is safe to call at any time and will never fail on Windows XP or newer.
+        unsafe {
+            QueryPerformanceFrequency(&mut freq);
+        }
+        FREQUENCY.store(freq, atomic::Ordering::Relaxed);
+    }
+
+    // SAFETY: This is safe to call at any time and will never fail on Windows XP or newer.
+    let time = unsafe {
+        let mut time = mem::MaybeUninit::uninit();
+        QueryPerformanceCounter(time.as_mut_ptr());
+        time.assume_init()
+    };
+
+    (time as u128 * 1_000_000_000 / freq as u128) as u64
+}
+
+#[cfg(any(
+    target_os = "linux",
+    target_os = "freebsd",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "dragonfly",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "hurd",
+))]
+/// Returns the monotonic system clock in nanoseconds or 0 on error.
+pub fn time() -> u64 {
+    use std::mem;
+
+    use crate::ffi::unix::clock_gettime::*;
+
+    // SAFETY: This is safe to call at any time. 0 will be returned on success, any other value on
+    // error.
+    unsafe {
+        let mut timespec = mem::MaybeUninit::uninit();
+        let res = clock_gettime(CLOCK_MONOTONIC, timespec.as_mut_ptr());
+        if res == 0 {
+            let timespec = timespec.assume_init();
+
+            timespec.tv_sec as u64 * 1_000_000_000 + timespec.tv_nsec as u64
+        } else {
+            0
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    #[test]
+    fn test_clock() {
+        // Check that this doesn't return 0 as that's very likely an indication of things going
+        // wrong.
+        let now = super::time();
+        assert_ne!(now, 0);
+    }
+}
diff --git a/libs/gst/helpers/ptp/conf_lib.rs.in b/libs/gst/helpers/ptp/conf_lib.rs.in
new file mode 100644
index 0000000..039b153
--- /dev/null
+++ b/libs/gst/helpers/ptp/conf_lib.rs.in
@@ -0,0 +1,2 @@
+pub const PTP_HELPER_SETUID_USER: Option<&str> = @PTP_HELPER_SETUID_USER@;
+pub const PTP_HELPER_SETUID_GROUP: Option<&str> = @PTP_HELPER_SETUID_GROUP@;
diff --git a/libs/gst/helpers/ptp/error.rs b/libs/gst/helpers/ptp/error.rs
new file mode 100644
index 0000000..8a8218f
--- /dev/null
+++ b/libs/gst/helpers/ptp/error.rs
@@ -0,0 +1,219 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+use std::{
+    error::Error as StdError,
+    fmt::{Debug, Display},
+};
+
+/// Custom error type for error display reasons.
+pub struct Error(Box<ErrorInner>);
+
+impl Error {
+    #[doc(hidden)]
+    pub fn new(message: String, source: Option<Box<dyn StdError + 'static>>) -> Self {
+        Error(Box::new(ErrorInner { message, source }))
+    }
+}
+
+struct ErrorInner {
+    message: String,
+    source: Option<Box<dyn StdError + 'static>>,
+}
+
+impl Debug for Error {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let mut e = self;
+        let mut first = true;
+
+        // Print the actual error message of this error and then iterate over the whole
+        // error chain and print each cause on the chain indented.
+        'next_error: loop {
+            if first {
+                writeln!(f, "{}", e.0.message)?;
+                first = false;
+            } else {
+                for line in e.0.message.lines() {
+                    writeln!(f, "  {}", line)?;
+                }
+            }
+
+            let mut source = match e.0.source {
+                Some(ref source) => &**source,
+                None => break 'next_error,
+            };
+
+            if let Some(source) = source.downcast_ref::<Error>() {
+                e = source;
+                writeln!(f, "\nCaused by:\n")?;
+                continue 'next_error;
+            }
+
+            loop {
+                writeln!(f, "\nCaused by:\n")?;
+                let source_str = source.to_string();
+                for line in source_str.lines() {
+                    writeln!(f, "  {}", line)?;
+                }
+
+                source = match source.source() {
+                    None => break 'next_error,
+                    Some(source) => source,
+                };
+
+                if let Some(source) = source.downcast_ref::<Error>() {
+                    e = source;
+                    writeln!(f, "\nCaused by:\n")?;
+                    continue 'next_error;
+                }
+            }
+        }
+
+        Ok(())
+    }
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        <Self as Debug>::fmt(self, f)
+    }
+}
+
+impl StdError for Error {
+    fn source(&self) -> Option<&(dyn StdError + 'static)> {
+        match self.0.source {
+            None => None,
+            Some(ref source) => Some(&**source),
+        }
+    }
+}
+
+impl<'a> From<&'a str> for Error {
+    fn from(message: &'a str) -> Self {
+        Error(Box::new(ErrorInner {
+            message: String::from(message),
+            source: None,
+        }))
+    }
+}
+
+impl From<String> for Error {
+    fn from(message: String) -> Self {
+        Error(Box::new(ErrorInner {
+            message,
+            source: None,
+        }))
+    }
+}
+
+#[macro_export]
+/// Create a new `Error` from the given message and possibly source error.
+macro_rules! format_err {
+    (source: $source:expr, $msg:literal $(,)?) => {
+        $crate::error::Error::new(
+            String::from($msg),
+            Some($source.into()),
+        )
+    };
+    (source: $source:expr, $err:expr $(,)?) => {
+        $crate::error::Error::new(
+            format!($err),
+            Some($source.into()),
+        )
+    };
+    (source: $source:expr, $fmt:expr, $($arg:tt)*) => {
+        $crate::error::Error::new(
+            format!($fmt, $($arg)*),
+            Some($source.into()),
+        )
+    };
+
+    ($msg:literal $(,)?) => {
+        $crate::error::Error::new(
+            String::from($msg),
+            None,
+        )
+    };
+    ($err:expr $(,)?) => {
+        $crate::error::Error::new(
+            format!($err),
+            None,
+        )
+    };
+    ($fmt:expr, $($arg:tt)*) => {
+        $crate::error::Error::new(
+            format!($fmt, $($arg)*),
+            None,
+        )
+    };
+}
+
+#[macro_export]
+/// Return new `Error` from the given message and possibly source error.
+macro_rules! bail {
+    ($($arg:tt)+) => {
+        return Err($crate::format_err!($($arg)+));
+    };
+}
+
+/// Trait for adding a context message to any `Result<T, E>` or `Option<T>`
+/// and turning it into a `Result<T, Error>`.
+pub trait Context<T, E> {
+    /// Add a static context.
+    ///
+    /// This should only be called if `context` requires no allocations or otherwise
+    /// exists already.
+    fn context<C>(self, context: C) -> Result<T, Error>
+    where
+        C: Display;
+
+    /// Add a lazily created context.
+    fn with_context<C, F>(self, func: F) -> Result<T, Error>
+    where
+        C: Display,
+        F: FnOnce() -> C;
+}
+
+impl<T, E> Context<T, E> for Result<T, E>
+where
+    E: StdError + 'static,
+{
+    fn context<C>(self, context: C) -> Result<T, Error>
+    where
+        C: Display,
+    {
+        self.map_err(|err| Error::new(context.to_string(), Some(Box::new(err))))
+    }
+
+    fn with_context<C, F>(self, func: F) -> Result<T, Error>
+    where
+        C: Display,
+        F: FnOnce() -> C,
+    {
+        self.map_err(|err| Error::new(func().to_string(), Some(Box::new(err))))
+    }
+}
+
+impl<T> Context<T, Error> for Option<T> {
+    fn context<C>(self, context: C) -> Result<T, Error>
+    where
+        C: Display,
+    {
+        self.ok_or_else(|| Error::new(context.to_string(), None))
+    }
+
+    fn with_context<C, F>(self, func: F) -> Result<T, Error>
+    where
+        C: Display,
+        F: FnOnce() -> C,
+    {
+        self.ok_or_else(|| Error::new(func().to_string(), None))
+    }
+}
diff --git a/libs/gst/helpers/ptp/ffi.rs b/libs/gst/helpers/ptp/ffi.rs
new file mode 100644
index 0000000..be527be
--- /dev/null
+++ b/libs/gst/helpers/ptp/ffi.rs
@@ -0,0 +1,1077 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+#[cfg(unix)]
+#[allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
+pub mod unix {
+    use std::os::{raw::*, unix::io::RawFd};
+
+    #[cfg(not(any(
+        target_os = "linux",
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "hurd",
+    )))]
+    compile_error!("Unsupported Operating System");
+
+    // The API definitions below are taken from the libc crate version 0.2.139, the corresponding C
+    // headers, manpages and related documentation.
+    //
+    // XXX: Once meson has cargo subproject support all of the below can be replaced with the libc crate.
+    pub const STDIN_FILENO: RawFd = 0;
+    pub const STDOUT_FILENO: RawFd = 1;
+    #[cfg(not(test))]
+    pub const STDERR_FILENO: RawFd = 2;
+    pub const O_RDONLY: c_int = 0;
+
+    pub const POLLIN: c_short = 0x1;
+    pub const POLLERR: c_short = 0x8;
+    pub const POLLHUP: c_short = 0x10;
+    pub const POLLNVAL: c_short = 0x20;
+
+    pub const IPPROTO_IP: c_int = 0;
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    pub const IP_ADD_MEMBERSHIP: c_int = 12;
+    #[cfg(target_os = "linux")]
+    pub const IP_ADD_MEMBERSHIP: c_int = 35;
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    pub const IP_ADD_MEMBERSHIP: c_int = 19;
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    pub const IP_MULTICAST_IF: c_int = 9;
+    #[cfg(target_os = "linux")]
+    pub const IP_MULTICAST_IF: c_int = 32;
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    pub const IP_MULTICAST_IF: c_int = 16;
+
+    #[cfg(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    pub const SOL_SOCKET: c_int = 0xffff;
+    #[cfg(all(
+        target_os = "linux",
+        any(
+            target_arch = "sparc",
+            target_arch = "sparc64",
+            target_arch = "mips",
+            target_arch = "mips64",
+        )
+    ))]
+    pub const SOL_SOCKET: c_int = 0xffff;
+    #[cfg(all(
+        target_os = "linux",
+        not(any(
+            target_arch = "sparc",
+            target_arch = "sparc64",
+            target_arch = "mips",
+            target_arch = "mips64",
+        )),
+    ))]
+    pub const SOL_SOCKET: c_int = 1;
+
+    #[cfg(target_os = "linux")]
+    pub const SO_BINDTODEVICE: c_int = 25;
+
+    #[cfg(target_os = "linux")]
+    pub const SO_BINDTOIFINDEX: c_int = 62;
+
+    #[cfg(target_os = "macos")]
+    pub const FIOCLEX: c_ulong = 0x20006601;
+
+    #[cfg(target_os = "macos")]
+    pub const SO_NOSIGPIPE: c_int = 0x1022;
+
+    #[cfg(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    pub const SO_REUSEADDR: c_int = 0x4;
+    #[cfg(all(
+        target_os = "linux",
+        any(
+            target_arch = "sparc",
+            target_arch = "sparc64",
+            target_arch = "mips",
+            target_arch = "mips64",
+        ),
+    ))]
+    pub const SO_REUSEADDR: c_int = 0x4;
+    #[cfg(all(
+        target_os = "linux",
+        not(any(
+            target_arch = "sparc",
+            target_arch = "sparc64",
+            target_arch = "mips",
+            target_arch = "mips64",
+        )),
+    ))]
+    pub const SO_REUSEADDR: c_int = 2;
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    pub const SO_REUSEPORT: c_int = 0x200;
+    #[cfg(all(
+        target_os = "linux",
+        any(
+            target_arch = "sparc",
+            target_arch = "sparc64",
+            target_arch = "mips",
+            target_arch = "mips64",
+        ),
+    ))]
+    pub const SO_REUSEPORT: c_int = 0x200;
+    #[cfg(all(
+        target_os = "linux",
+        not(any(
+            target_arch = "sparc",
+            target_arch = "sparc64",
+            target_arch = "mips",
+            target_arch = "mips64"
+        )),
+    ))]
+    pub const SO_REUSEPORT: c_int = 15;
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "dragonfly",
+        target_os = "netbsd",
+        target_os = "hurd",
+    ))]
+    pub const SOCK_CLOEXEC: c_int = 0x10000000;
+    #[cfg(target_os = "openbsd")]
+    pub const SOCK_CLOEXEC: c_int = 0x8000;
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    pub const SOCK_CLOEXEC: c_int = 0x080000;
+    #[cfg(all(
+        target_os = "linux",
+        any(target_arch = "sparc", target_arch = "sparc64"),
+    ))]
+    pub const SOCK_CLOEXEC: c_int = 0x400000;
+    #[cfg(all(
+        target_os = "linux",
+        not(any(target_arch = "sparc", target_arch = "sparc64")),
+    ))]
+    pub const SOCK_CLOEXEC: c_int = 0x80000;
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "dragonfly",
+        target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    pub const SOCK_DGRAM: c_int = 2;
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    pub const SOCK_DGRAM: c_int = 1;
+    #[cfg(all(target_os = "linux", any(target_arch = "mips", target_arch = "mips64"),))]
+    pub const SOCK_DGRAM: c_int = 1;
+    #[cfg(all(
+        target_os = "linux",
+        not(any(target_arch = "mips", target_arch = "mips64")),
+    ))]
+    pub const SOCK_DGRAM: c_int = 2;
+
+    pub const AF_INET: c_int = 2;
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    pub const AF_LINK: c_int = 18;
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    pub const AF_LINK: c_int = 25;
+    #[cfg(target_os = "linux")]
+    pub const AF_PACKET: c_int = 17;
+
+    #[cfg(any(
+        target_os = "linux",
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    pub type IfaFlags = c_uint;
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    pub type IfaFlags = u64;
+
+    pub const IFF_UP: IfaFlags = 0x1;
+    pub const IFF_LOOPBACK: IfaFlags = 0x8;
+
+    #[cfg(any(target_os = "linux", target_os = "hurd"))]
+    pub const IFF_MULTICAST: IfaFlags = 0x1000;
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    pub const IFF_MULTICAST: IfaFlags = 0x0800;
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+    ))]
+    pub const IFF_MULTICAST: IfaFlags = 0x08000;
+
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    pub const IF_NAMESIZE: usize = 32;
+    #[cfg(not(any(
+        target_os = "linux",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "hurd",
+    )))]
+    pub const IF_NAMESIZE: usize = 16;
+
+    pub const PRIO_PROCESS: c_int = 0;
+
+    extern "C" {
+        #[cfg_attr(
+            all(target_os = "macos", target_arch = "x86"),
+            link_name = "open$UNIX2003"
+        )]
+        pub fn open(path: *const u8, oflag: c_int, ...) -> i32;
+        #[cfg_attr(
+            all(target_os = "macos", target_arch = "x86"),
+            link_name = "read$UNIX2003"
+        )]
+        pub fn read(fd: RawFd, buf: *mut u8, count: usize) -> isize;
+        #[cfg_attr(
+            all(target_os = "macos", target_arch = "x86"),
+            link_name = "write$UNIX2003"
+        )]
+        pub fn write(fd: RawFd, buf: *const u8, count: usize) -> isize;
+
+        #[cfg_attr(
+            all(target_os = "macos", target_arch = "x86"),
+            link_name = "close$UNIX2003"
+        )]
+        pub fn close(fd: c_int) -> c_int;
+
+        #[cfg_attr(
+            all(target_os = "macos", target_arch = "x86"),
+            link_name = "poll$UNIX2003"
+        )]
+        pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int;
+
+        pub fn if_nametoindex(name: *const c_char) -> c_uint;
+        pub fn setsockopt(
+            socket: c_int,
+            level: c_int,
+            name: c_int,
+            value: *const c_void,
+            option_len: u32,
+        ) -> c_int;
+
+        pub fn getifaddrs(ifap: *mut *mut ifaddrs) -> c_int;
+        pub fn freeifaddrs(ifa: *mut ifaddrs);
+
+        pub fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int;
+
+        #[cfg_attr(target_os = "netbsd", link_name = "__socket30")]
+        #[cfg_attr(target_os = "illumos", link_name = "__xnet_socket")]
+        pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int;
+
+        #[cfg_attr(target_os = "illumos", link_name = "__xnet_bind")]
+        #[cfg_attr(
+            all(target_os = "macos", target_arch = "x86"),
+            link_name = "bind$UNIX2003"
+        )]
+        pub fn bind(socket: c_int, address: *const sockaddr, address_len: u32) -> c_int;
+
+        #[cfg(target_os = "macos")]
+        pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
+
+        #[cfg(test)]
+        pub fn pipe(pipefd: *mut i32) -> i32;
+    }
+
+    #[cfg(any(
+        target_os = "linux",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "hurd",
+    ))]
+    pub type nfds_t = c_ulong;
+    #[cfg(not(any(
+        target_os = "linux",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "hurd",
+    )))]
+    pub type nfds_t = c_uint;
+
+    #[repr(C)]
+    #[derive(Clone, Copy)]
+    pub struct pollfd {
+        pub fd: c_int,
+        pub events: c_short,
+        pub revents: c_short,
+    }
+
+    pub type in_addr_t = u32;
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct in_addr {
+        pub s_addr: in_addr_t,
+    }
+
+    // Solaris does not have support for this so we fall back to use the std API
+    #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct ip_mreqn {
+        pub imr_multiaddr: in_addr,
+        pub imr_address: in_addr,
+        pub imr_ifindex: c_int,
+    }
+
+    // macOS uses ip_mreq instead of ip_mreqn in its latest version of the MAC Kernel for IP_ADD_MEMBERSHIP
+    #[cfg(target_os = "macos")]
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct ip_mreq {
+        pub imr_multiaddr: in_addr,
+        pub imr_address: in_addr,
+    }
+
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    #[repr(C)]
+    pub struct ifaddrs {
+        pub ifa_next: *mut ifaddrs,
+        pub ifa_name: *mut c_char,
+        pub ifa_flags: IfaFlags,
+        pub ifa_addr: *mut sockaddr,
+        pub ifa_netmask: *mut sockaddr,
+        pub ifa_dstaddr: *mut sockaddr,
+        pub ifa_data: *mut c_void,
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "hurd"))]
+    #[repr(C)]
+    pub struct ifaddrs {
+        pub ifa_next: *mut ifaddrs,
+        pub ifa_name: *mut c_char,
+        pub ifa_flags: IfaFlags,
+        pub ifa_addr: *mut sockaddr,
+        pub ifa_netmask: *mut sockaddr,
+        pub ifa_ifu: *mut sockaddr,
+        pub ifa_data: *mut c_void,
+    }
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+    ))]
+    #[repr(C)]
+    pub struct ifaddrs {
+        pub ifa_next: *mut ifaddrs,
+        pub ifa_name: *mut c_char,
+        pub ifa_flags: IfaFlags,
+        pub ifa_addr: *mut sockaddr,
+        pub ifa_netmask: *mut sockaddr,
+        pub ifa_dstaddr: *mut sockaddr,
+        pub ifa_data: *mut c_void,
+        #[cfg(target_os = "netbsd")]
+        pub ifa_addrflags: c_uint,
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "solaris", target_os = "illumos"))]
+    #[repr(C)]
+    pub struct sockaddr {
+        pub sa_family: u16,
+        pub sa_data: [u8; 14],
+    }
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    #[repr(C)]
+    pub struct sockaddr {
+        pub sa_len: u8,
+        pub sa_family: u8,
+        pub sa_data: [u8; 14],
+    }
+
+    #[cfg(any(target_os = "linux", target_os = "solaris", target_os = "illumos"))]
+    #[repr(C)]
+    pub struct sockaddr_in {
+        pub sin_family: u16,
+        pub sin_port: u16,
+        pub sin_addr: in_addr,
+        pub sin_zero: [u8; 8],
+    }
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "openbsd",
+        target_os = "netbsd",
+        target_os = "dragonfly",
+        target_os = "macos",
+        target_os = "hurd",
+    ))]
+    #[repr(C)]
+    pub struct sockaddr_in {
+        pub sin_len: u8,
+        pub sin_family: u8,
+        pub sin_port: u16,
+        pub sin_addr: in_addr,
+        pub sin_zero: [u8; 8],
+    }
+
+    #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+    #[repr(C)]
+    pub struct sockaddr_dl {
+        pub sdl_family: u16,
+        pub sdl_index: u16,
+        pub sdl_type: u8,
+        pub sdl_nlen: u8,
+        pub sdl_alen: u8,
+        pub sdl_slen: u8,
+        pub sdl_data: [u8; 244],
+    }
+
+    #[cfg(any(target_os = "netbsd", target_os = "macos"))]
+    #[repr(C)]
+    pub struct sockaddr_dl {
+        pub sdl_len: u8,
+        pub sdl_family: u8,
+        pub sdl_index: u16,
+        pub sdl_type: u8,
+        pub sdl_nlen: u8,
+        pub sdl_alen: u8,
+        pub sdl_slen: u8,
+        pub sdl_data: [u8; 12],
+    }
+
+    #[cfg(target_os = "openbsd")]
+    #[repr(C)]
+    pub struct sockaddr_dl {
+        pub sdl_len: u8,
+        pub sdl_family: u8,
+        pub sdl_index: u16,
+        pub sdl_type: u8,
+        pub sdl_nlen: u8,
+        pub sdl_alen: u8,
+        pub sdl_slen: u8,
+        pub sdl_data: [u8; 24],
+    }
+
+    #[cfg(target_os = "freebsd")]
+    #[repr(C)]
+    pub struct sockaddr_dl {
+        pub sdl_len: u8,
+        pub sdl_family: u8,
+        pub sdl_index: u16,
+        pub sdl_type: u8,
+        pub sdl_nlen: u8,
+        pub sdl_alen: u8,
+        pub sdl_slen: u8,
+        pub sdl_data: [u8; 46],
+    }
+
+    #[cfg(target_os = "dragonfly")]
+    #[repr(C)]
+    pub struct sockaddr_dl {
+        pub sdl_len: u8,
+        pub sdl_family: u8,
+        pub sdl_index: u16,
+        pub sdl_type: u8,
+        pub sdl_nlen: u8,
+        pub sdl_alen: u8,
+        pub sdl_slen: u8,
+        pub sdl_data: [u8; 12],
+        pub sdl_rcf: u16,
+        pub sdl_route: [u8; 16],
+    }
+
+    #[cfg(target_os = "linux")]
+    #[repr(C)]
+    pub struct sockaddr_ll {
+        pub sll_family: u16,
+        pub sll_protocol: u16,
+        pub sll_ifindex: u32,
+        pub sll_hatype: u16,
+        pub sll_pkttype: u8,
+        pub sll_halen: u8,
+        pub sll_addr: [u8; 8],
+    }
+
+    #[cfg(target_os = "linux")]
+    pub mod linux {
+        pub use super::*;
+
+        #[cfg(target_arch = "x86")]
+        pub const SYS_getrandom: c_ulong = 355;
+        #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
+        pub const SYS_getrandom: c_ulong = 0x40000000 + 318;
+        #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+        pub const SYS_getrandom: c_ulong = 318;
+        #[cfg(target_arch = "arm")]
+        pub const SYS_getrandom: c_ulong = 384;
+        #[cfg(target_arch = "aarch64")]
+        pub const SYS_getrandom: c_ulong = 278;
+        #[cfg(target_arch = "mips")]
+        pub const SYS_getrandom: c_ulong = 4000 + 353;
+        #[cfg(target_arch = "mips64")]
+        pub const SYS_getrandom: c_ulong = 5000 + 313;
+        #[cfg(any(
+            target_arch = "riscv32",
+            target_arch = "riscv64",
+            target_arch = "loongarch64"
+        ))]
+        pub const SYS_getrandom: c_ulong = 278;
+        #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+        pub const SYS_getrandom: c_ulong = 359;
+        #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
+        pub const SYS_getrandom: c_ulong = 347;
+        #[cfg(target_arch = "s390x")]
+        pub const SYS_getrandom: c_ulong = 349;
+        #[cfg(target_arch = "m68k")]
+        pub const SYS_getrandom: c_ulong = 352;
+        #[cfg(not(any(
+            target_arch = "x86",
+            target_arch = "x86_64",
+            target_arch = "arm",
+            target_arch = "aarch64",
+            target_arch = "mips",
+            target_arch = "mips64",
+            target_arch = "riscv32",
+            target_arch = "riscv64",
+            target_arch = "loongarch64",
+            target_arch = "powerpc",
+            target_arch = "powerpc64",
+            target_arch = "sparc",
+            target_arch = "sparc64",
+            target_arch = "s390x",
+            target_arch = "m68k",
+        )))]
+        pub const SYS_getrandom: c_ulong = 0;
+
+        extern "C" {
+            pub fn syscall(num: c_ulong, ...) -> c_long;
+        }
+    }
+
+    #[cfg(target_os = "macos")]
+    pub mod macos {
+        pub use super::*;
+
+        #[repr(C)]
+        pub struct mach_timebase_info {
+            pub numer: u32,
+            pub denom: u32,
+        }
+
+        extern "C" {
+            pub fn mach_timebase_info(info: *mut mach_timebase_info) -> c_int;
+            pub fn mach_absolute_time() -> u64;
+        }
+    }
+
+    #[cfg(not(target_os = "macos"))]
+    pub mod clock_gettime {
+        pub use super::*;
+
+        #[cfg(any(
+            target_os = "linux",
+            target_os = "freebsd",
+            target_os = "openbsd",
+            target_os = "netbsd",
+            target_os = "solaris",
+            target_os = "illumos",
+            target_os = "hurd",
+        ))]
+        pub type clock_id_t = c_int;
+
+        #[cfg(target_os = "dragonfly")]
+        pub type clock_id_t = c_ulong;
+
+        #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "hurd"))]
+        pub type time_t = c_long;
+
+        #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly"))]
+        pub type time_t = i64;
+
+        #[cfg(all(target_os = "freebsd", target_arch = "x86"))]
+        pub type time_t = i32;
+        #[cfg(all(target_os = "freebsd", not(target_arch = "x86")))]
+        pub type time_t = i64;
+
+        #[cfg(all(target_os = "linux", target_env = "gnu", target_arch = "riscv32"))]
+        pub type time_t = i64;
+        #[cfg(all(
+            target_os = "linux",
+            target_env = "gnu",
+            any(
+                target_arch = "x86",
+                target_arch = "arm",
+                target_arch = "m68k",
+                target_arch = "mips",
+                target_arch = "powerpc",
+                target_arch = "sparc",
+                all(target_arch = "aarch64", target_pointer_width = "32"),
+            )
+        ))]
+        pub type time_t = i32;
+        #[cfg(all(
+            target_os = "linux",
+            target_env = "gnu",
+            any(
+                target_arch = "x86_64",
+                all(target_arch = "aarch64", target_pointer_width = "64"),
+                target_arch = "powerpc64",
+                target_arch = "mips64",
+                target_arch = "s390x",
+                target_arch = "sparc64",
+                target_arch = "riscv64",
+                target_arch = "loongarch64",
+            )
+        ))]
+        pub type time_t = i64;
+        #[cfg(all(target_os = "linux", target_env = "musl"))]
+        pub type time_t = c_long;
+
+        #[cfg(all(target_os = "linux", target_env = "uclibc", target_arch = "x86_64"))]
+        pub type time_t = c_int;
+        #[cfg(all(
+            target_os = "linux",
+            target_env = "uclibc",
+            not(target_arch = "x86_64"),
+        ))]
+        pub type time_t = c_long;
+
+        #[repr(C)]
+        pub struct timespec {
+            pub tv_sec: time_t,
+            #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
+            pub tv_nsec: i64,
+            #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
+            pub tv_nsec: c_long,
+        }
+
+        #[cfg(any(
+            target_os = "freebsd",
+            target_os = "dragonfly",
+            target_os = "solaris",
+            target_os = "illumos",
+        ))]
+        pub const CLOCK_MONOTONIC: clock_id_t = 4;
+
+        #[cfg(any(target_os = "openbsd", target_os = "netbsd",))]
+        pub const CLOCK_MONOTONIC: clock_id_t = 3;
+
+        #[cfg(any(target_os = "linux", target_os = "hurd"))]
+        pub const CLOCK_MONOTONIC: clock_id_t = 1;
+
+        extern "C" {
+            pub fn clock_gettime(clk_id: clock_id_t, tp: *mut timespec) -> c_int;
+        }
+    }
+
+    #[cfg(ptp_helper_permissions = "setcap")]
+    pub mod setcaps {
+        use super::*;
+
+        pub type cap_t = *mut c_void;
+
+        #[link(name = "cap")]
+        extern "C" {
+            pub fn cap_clear(c: cap_t) -> c_int;
+            pub fn cap_get_proc() -> cap_t;
+            pub fn cap_set_proc(c: cap_t) -> c_int;
+            pub fn cap_free(c: cap_t) -> c_int;
+        }
+    }
+
+    #[cfg(ptp_helper_permissions = "setuid-root")]
+    pub mod setuid_root {
+        use super::*;
+
+        pub type uid_t = u32;
+        pub type gid_t = u32;
+
+        #[repr(C)]
+        pub struct passwd {
+            pub pw_name: *mut c_char,
+            pub pw_passwd: *mut c_char,
+            pub pw_uid: uid_t,
+            pub pw_gid: gid_t,
+            // More fields following here
+            truncated: c_void,
+        }
+
+        #[repr(C)]
+        pub struct group {
+            pub gr_name: *mut c_char,
+            pub gr_passwd: *mut c_char,
+            pub gr_gid: gid_t,
+            // More fields following here
+            truncated: c_void,
+        }
+
+        extern "C" {
+            #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam50")]
+            pub fn getpwnam(name: *const c_char) -> *mut passwd;
+            pub fn getgrnam(name: *const c_char) -> *mut group;
+            pub fn setgid(gid: gid_t) -> c_int;
+            pub fn getgid() -> gid_t;
+            pub fn setuid(gid: gid_t) -> c_int;
+        }
+    }
+}
+
+#[cfg(windows)]
+#[allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
+pub mod windows {
+    use std::os::{
+        raw::*,
+        windows::raw::{HANDLE, SOCKET},
+    };
+
+    // The API definitions below are taken from the windows-sys crate version 0.45.0, the
+    // corresponding C headers, MSDN and related documentation.
+    //
+    // XXX: Once meson has cargo subproject support all of the below can be replaced with the windows-sys crate.
+    pub const INVALID_HANDLE_VALUE: HANDLE = (-1 as isize as usize) as HANDLE;
+    pub const INVALID_SOCKET: SOCKET = (-1 as isize as usize) as SOCKET;
+
+    pub const STD_INPUT_HANDLE: i32 = -10;
+    pub const STD_OUTPUT_HANDLE: i32 = -11;
+    #[cfg(not(test))]
+    pub const STD_ERROR_HANDLE: i32 = -12;
+
+    pub const FILE_TYPE_CHAR: u32 = 0x0002;
+    pub const FILE_TYPE_PIPE: u32 = 0x0003;
+
+    pub const THREAD_PRIORITY_TIME_CRITICAL: i32 = 15;
+
+    #[link(name = "kernel32")]
+    extern "system" {
+        pub fn GetStdHandle(nstdhandle: i32) -> HANDLE;
+
+        pub fn ReadFile(
+            hfile: HANDLE,
+            lpbuffer: *mut u8,
+            nnumberofbytestoread: u32,
+            lpnumberofbytesread: *mut u32,
+            lpoverlapped: *mut c_void,
+        ) -> i32;
+
+        pub fn WriteFile(
+            hfile: HANDLE,
+            lpbuffer: *const u8,
+            nnumberofbytestowrite: u32,
+            lpnumberofbyteswritten: *mut u32,
+            lpoverlapped: *mut c_void,
+        ) -> i32;
+
+        pub fn WaitForMultipleObjects(
+            ncount: u32,
+            lphandles: *const HANDLE,
+            bwaitall: i32,
+            dwmilliseconds: u32,
+        ) -> u32;
+
+        pub fn SetConsoleMode(hconsolehandle: HANDLE, dwmode: u32) -> i32;
+        pub fn FlushConsoleInputBuffer(hconsolehandle: HANDLE) -> i32;
+
+        pub fn CreateEventA(
+            lpeventattributes: *const c_void,
+            bmanualreset: i32,
+            binitialstate: i32,
+            lpname: *const u8,
+        ) -> HANDLE;
+        pub fn SetEvent(hevent: HANDLE) -> i32;
+        pub fn ResetEvent(hevent: HANDLE) -> i32;
+        pub fn CloseHandle(hobject: HANDLE) -> i32;
+
+        pub fn GetFileType(hfile: HANDLE) -> u32;
+
+        pub fn GetProcessHeap() -> isize;
+        pub fn HeapAlloc(hheap: isize, dwflags: u32, dwbytes: usize) -> *mut c_void;
+        pub fn HeapFree(hheap: isize, dwflags: u32, lpmem: *mut c_void) -> i32;
+        pub fn HeapReAlloc(
+            hheap: isize,
+            dwflags: u32,
+            lpmem: *mut c_void,
+            dwbytes: usize,
+        ) -> *mut c_void;
+
+        pub fn SetThreadPriority(pthread: HANDLE, npriority: i32) -> i32;
+        pub fn GetCurrentThread() -> HANDLE;
+
+        #[cfg(test)]
+        pub fn CreatePipe(
+            hreadpipe: *mut HANDLE,
+            hwritepipe: *mut HANDLE,
+            lppipeattributes: *mut c_void,
+            nsize: u32,
+        ) -> i32;
+
+        pub fn QueryPerformanceFrequency(lpfrequence: *mut i64) -> i32;
+        pub fn QueryPerformanceCounter(lpperformancecount: *mut i64) -> i32;
+    }
+
+    pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
+
+    #[link(name = "bcrypt")]
+    extern "system" {
+        pub fn BCryptGenRandom(
+            hAlgorithm: *mut c_void,
+            pBuffer: *mut u8,
+            cbBuffer: u32,
+            dwFlags: u32,
+        ) -> u32;
+    }
+
+    pub const FD_READ: u32 = 1;
+    pub const FD_READ_BIT: usize = 0;
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct WSANETWORKEVENTS {
+        pub lnetworkevents: u32,
+        pub ierrorcode: [i32; 10],
+    }
+
+    pub const IPPROTO_IP: u32 = 0u32;
+
+    pub const IP_ADD_MEMBERSHIP: u32 = 12u32;
+    pub const IP_MULTICAST_IF: u32 = 9u32;
+
+    pub const SOL_SOCKET: u32 = 65535;
+    pub const SO_REUSEADDR: u32 = 4;
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct IN_ADDR_0_0 {
+        pub s_b1: u8,
+        pub s_b2: u8,
+        pub s_b3: u8,
+        pub s_b4: u8,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct IN_ADDR_0_1 {
+        pub s_w1: u16,
+        pub s_w2: u16,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub union IN_ADDR_0 {
+        pub S_un_b: IN_ADDR_0_0,
+        pub S_un_w: IN_ADDR_0_1,
+        pub S_addr: u32,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct IN_ADDR {
+        pub S_un: IN_ADDR_0,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct IP_MREQ {
+        pub imr_multiaddr: IN_ADDR,
+        pub imr_address: IN_ADDR,
+    }
+
+    #[link(name = "ws2_32")]
+    extern "system" {
+        pub fn WSAEventSelect(s: SOCKET, heventobject: HANDLE, lnetworkevents: u32) -> i32;
+        pub fn WSAEnumNetworkEvents(
+            s: SOCKET,
+            heventobject: HANDLE,
+            lpnetworkevents: *mut WSANETWORKEVENTS,
+        ) -> i32;
+        pub fn WSACreateEvent() -> HANDLE;
+        pub fn WSACloseEvent(hevent: HANDLE) -> i32;
+        pub fn WSAGetLastError() -> i32;
+
+        pub fn setsockopt(
+            socket: SOCKET,
+            level: i32,
+            name: i32,
+            value: *const c_void,
+            option_len: i32,
+        ) -> i32;
+
+        pub fn WSASocketW(
+            af: i32,
+            ty: i32,
+            protocol: i32,
+            lpprotocolinfo: *const c_void,
+            g: u32,
+            dwflags: u32,
+        ) -> SOCKET;
+        pub fn bind(s: SOCKET, name: *const SOCKADDR, namelen: i32) -> i32;
+        pub fn closesocket(socket: SOCKET) -> i32;
+    }
+
+    pub const AF_INET: u32 = 2;
+
+    pub const SOCK_DGRAM: u16 = 2u16;
+
+    pub const WSA_FLAG_OVERLAPPED: u32 = 1u32;
+    pub const WSA_FLAG_NO_HANDLE_INHERIT: u32 = 128u32;
+
+    pub const GAA_FLAG_SKIP_ANYCAST: u32 = 0x0002;
+    pub const GAA_FLAG_SKIP_MULTICAST: u32 = 0x0004;
+    pub const GAA_FLAG_SKIP_DNS_SERVER: u32 = 0x0008;
+
+    pub const ADAPTER_FLAG_RECEIVE_ONLY: u32 = 0x08;
+    pub const ADAPTER_FLAG_NO_MULTICAST: u32 = 0x10;
+    pub const ADAPTER_FLAG_IPV4_ENABLED: u32 = 0x80;
+
+    pub const IF_TYPE_SOFTWARE_LOOPBACK: u32 = 24;
+
+    pub const IF_OPER_STATUS_UP: u32 = 1;
+
+    pub const ERROR_NOT_ENOUGH_MEMORY: u32 = 8u32;
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct IP_ADAPTER_ADDRESSES_LH_0_0 {
+        pub length: u32,
+        pub ifindex: u32,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub union IP_ADAPTER_ADDRESSES_LH_0 {
+        pub alignment: u64,
+        pub anonymous: IP_ADAPTER_ADDRESSES_LH_0_0,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub struct IP_ADAPTER_UNICAST_ADDRESS_LH_0_0 {
+        pub length: u32,
+        pub ifindex: u32,
+    }
+
+    #[repr(C)]
+    #[derive(Copy, Clone)]
+    pub union IP_ADAPTER_UNICAST_ADDRESS_LH_0 {
+        pub alignment: u64,
+        pub anonymous: IP_ADAPTER_UNICAST_ADDRESS_LH_0_0,
+    }
+
+    // XXX: Actually SOCKADDR_IN but we don't care about others
+    #[repr(C)]
+    pub struct SOCKADDR {
+        pub sa_family: u16,
+        pub sin_port: u16,
+        pub in_addr: IN_ADDR,
+        pub sin_zero: [u8; 8],
+    }
+
+    #[repr(C)]
+    pub struct SOCKET_ADDRESS {
+        pub lpsocketaddr: *mut SOCKADDR,
+        pub isocketaddrlength: i32,
+    }
+
+    #[repr(C)]
+    pub struct IP_ADAPTER_UNICAST_ADDRESS_LH {
+        pub anonymous: IP_ADAPTER_UNICAST_ADDRESS_LH_0,
+        pub next: *mut IP_ADAPTER_UNICAST_ADDRESS_LH,
+        pub address: SOCKET_ADDRESS,
+        // More fields following here
+        truncated: c_void,
+    }
+
+    #[repr(C)]
+    pub struct IP_ADAPTER_ADDRESSES_LH {
+        pub anonymous: IP_ADAPTER_ADDRESSES_LH_0,
+        pub next: *mut IP_ADAPTER_ADDRESSES_LH,
+        pub adaptername: *const u8,
+        pub firstunicastaddress: *mut IP_ADAPTER_UNICAST_ADDRESS_LH,
+        pub firstanycastaddress: *mut c_void,
+        pub firstmulticastaddress: *mut c_void,
+        pub firstdnsserveraddress: *mut c_void,
+        pub dnssuffix: *const u16,
+        pub description: *const u16,
+        pub friendlyname: *const u16,
+        pub physicaladdress: [u8; 8],
+        pub physicaladdresslength: u32,
+        pub flags: u32,
+        pub mtu: u32,
+        pub iftype: u32,
+        pub operstatus: u32,
+        // More fields following here
+        truncated: c_void,
+    }
+
+    #[link(name = "iphlpapi")]
+    extern "system" {
+        pub fn GetAdaptersAddresses(
+            family: u32,
+            flags: u32,
+            reserved: *mut c_void,
+            adapteraddresses: *mut IP_ADAPTER_ADDRESSES_LH,
+            sizepointer: *mut u32,
+        ) -> u32;
+    }
+}
diff --git a/libs/gst/helpers/ptp/io.rs b/libs/gst/helpers/ptp/io.rs
new file mode 100644
index 0000000..c1ccda1
--- /dev/null
+++ b/libs/gst/helpers/ptp/io.rs
@@ -0,0 +1,1402 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+use std::net::UdpSocket;
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum SocketType {
+    EventSocket,
+    GeneralSocket,
+}
+
+/// Result of polling the inputs of the `Poll`.
+///
+/// Note that reading from the sockets is non-blocking but reading from stdin is blocking so
+/// special care has to be taken to only read as much as is available.
+pub struct PollResult<'a> {
+    ready_sockets: &'a [(usize, SocketType, &'a UdpSocket)],
+    sockets: &'a [(UdpSocket, UdpSocket)],
+    stdin: Option<&'a Stdin>,
+    stdout: &'a Stdout,
+}
+
+impl<'a> PollResult<'a> {
+    /// Returns the sockets that are currently ready for reading.
+    pub fn ready_sockets(&self) -> &[(usize, SocketType, &UdpSocket)] {
+        self.ready_sockets
+    }
+
+    /// Returns the event socket.
+    pub fn event_socket(&self, idx: usize) -> &UdpSocket {
+        &self.sockets[idx].0
+    }
+
+    /// Returns the general socket.
+    pub fn general_socket(&self, idx: usize) -> &UdpSocket {
+        &self.sockets[idx].1
+    }
+
+    /// Returns standard input if there is data to read.
+    pub fn stdin(&self) -> Option<&Stdin> {
+        self.stdin
+    }
+
+    /// Returns standard output.
+    pub fn stdout(&self) -> &Stdout {
+        self.stdout
+    }
+}
+
+#[cfg(unix)]
+mod imp {
+    use super::{PollResult, SocketType};
+
+    use std::{
+        io::{self, Read, Write},
+        mem,
+        net::UdpSocket,
+        os::unix::io::{AsRawFd, RawFd},
+    };
+
+    use crate::{bail, error::Error, ffi::unix::*};
+
+    /// Inputs and outputs, and allowing to poll the inputs for available data.
+    ///
+    /// This carries the event/general UDP socket and stdin/stdout.
+    pub struct Poll {
+        sockets: Vec<(UdpSocket, UdpSocket)>,
+        stdin: Stdin,
+        stdout: Stdout,
+        pollfd: Vec<pollfd>,
+        results_cache: Vec<(usize, SocketType, &'static UdpSocket)>,
+    }
+
+    #[cfg(test)]
+    /// A file descriptor pair representing a pipe for testing purposes.
+    pub struct Pipe {
+        pub read: i32,
+        pub write: i32,
+    }
+
+    #[cfg(test)]
+    impl Pipe {
+        fn new() -> io::Result<Self> {
+            // SAFETY: Requires two integers to be passed in and creates the read
+            // and write end of a pipe.
+            unsafe {
+                let mut fds = std::mem::MaybeUninit::<[i32; 2]>::uninit();
+                let res = pipe(fds.as_mut_ptr() as *mut i32);
+                if res == 0 {
+                    let fds = fds.assume_init();
+                    Ok(Pipe {
+                        read: fds[0],
+                        write: fds[1],
+                    })
+                } else {
+                    Err(io::Error::last_os_error())
+                }
+            }
+        }
+    }
+
+    #[cfg(test)]
+    impl Drop for Pipe {
+        fn drop(&mut self) {
+            // SAFETY: Only ever created with valid fds
+            unsafe {
+                close(self.read);
+                close(self.write);
+            }
+        }
+    }
+
+    #[cfg(test)]
+    impl Read for &Pipe {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            // SAFETY: read() requires a valid fd and a mutable buffer with the given size.
+            // The fd is valid by construction as is the buffer.
+            //
+            // read() will return the number of bytes read or a negative value on errors.
+            let res = unsafe { read(self.read, buf.as_mut_ptr(), buf.len()) };
+
+            if res < 0 {
+                Err(std::io::Error::last_os_error())
+            } else {
+                Ok(res as usize)
+            }
+        }
+    }
+
+    #[cfg(test)]
+    impl Write for Pipe {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            // SAFETY: write() requires a valid fd and a mutable buffer with the given size.
+            // The fd is valid by construction as is the buffer.
+            //
+            // write() will return the number of bytes written or a negative value on errors.
+            let res = unsafe { write(self.write, buf.as_ptr(), buf.len()) };
+
+            if res == -1 {
+                Err(std::io::Error::last_os_error())
+            } else {
+                Ok(res as usize)
+            }
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            Ok(())
+        }
+    }
+
+    impl Poll {
+        /// Name of the input based on the `struct pollfd` index.
+        fn fd_name(idx: usize, len: usize) -> &'static str {
+            match idx {
+                i if i == len - 1 => "stdin",
+                i if i % 2 == 0 => "event socket",
+                i if i % 2 == 1 => "general socket",
+                _ => unreachable!(),
+            }
+        }
+
+        /// Create a new `Poll` instance from the pairs of sockets.
+        pub fn new(sockets: Vec<(UdpSocket, UdpSocket)>) -> Result<Self, Error> {
+            let stdin = Stdin::acquire();
+            let stdout = Stdout::acquire();
+            let n_sockets = sockets.len();
+
+            Ok(Self {
+                sockets,
+                stdin,
+                stdout,
+                pollfd: Vec::with_capacity(n_sockets * 2 + 1),
+                results_cache: Vec::with_capacity(n_sockets * 2),
+            })
+        }
+
+        #[cfg(test)]
+        /// Create a new `Poll` instance for testing purposes.
+        ///
+        /// The returned `Pipe`s are for stdin and stdout.
+        pub fn new_test(
+            event_socket: UdpSocket,
+            general_socket: UdpSocket,
+        ) -> Result<(Self, Pipe, Pipe), Error> {
+            let stdin = Pipe::new().unwrap();
+            let stdout = Pipe::new().unwrap();
+
+            Ok((
+                Self {
+                    sockets: vec![(event_socket, general_socket)],
+                    stdin: Stdin(stdin.read),
+                    stdout: Stdout(stdout.write),
+                    pollfd: Vec::with_capacity(3),
+                    results_cache: Vec::with_capacity(2),
+                },
+                stdin,
+                stdout,
+            ))
+        }
+
+        /// Reference to the event socket.
+        #[allow(unused)]
+        pub fn event_socket(&self, iface: usize) -> &UdpSocket {
+            &self.sockets[iface].0
+        }
+
+        /// Reference to the general socket.
+        #[allow(unused)]
+        pub fn general_socket(&self, iface: usize) -> &UdpSocket {
+            &self.sockets[iface].1
+        }
+
+        /// Reference to stdin for reading.
+        #[allow(unused)]
+        pub fn stdin(&self) -> &Stdin {
+            &self.stdin
+        }
+
+        /// Reference to stdout for writing.
+        pub fn stdout(&self) -> &Stdout {
+            &self.stdout
+        }
+
+        /// Poll the event socket, general socket and stdin for available data to read.
+        ///
+        /// This blocks until at least one input has data available.
+        pub fn poll<'a>(&'a mut self) -> Result<PollResult<'a>, Error> {
+            self.pollfd.clear();
+            for (event_socket, general_socket) in &self.sockets {
+                self.pollfd.push(pollfd {
+                    fd: event_socket.as_raw_fd(),
+                    events: POLLIN,
+                    revents: 0,
+                });
+                self.pollfd.push(pollfd {
+                    fd: general_socket.as_raw_fd(),
+                    events: POLLIN,
+                    revents: 0,
+                });
+            }
+
+            self.pollfd.push(pollfd {
+                fd: self.stdin.0,
+                events: POLLIN,
+                revents: 0,
+            });
+
+            // SAFETY: Polls the given pollfds above and requires a valid number to be passed.
+            // A negative timeout means that it will wait until at least one of the pollfds is
+            // ready.
+            //
+            // Will return -1 on error, otherwise the number of ready pollfds. This can never be
+            // zero as a non-empty set of pollfds is passed.
+            //
+            // On EINTR polling should be retried.
+            unsafe {
+                loop {
+                    let res = poll(self.pollfd[..].as_mut_ptr(), self.pollfd.len() as _, -1);
+                    if res == -1 {
+                        let err = std::io::Error::last_os_error();
+                        if err.kind() == std::io::ErrorKind::Interrupted {
+                            continue;
+                        }
+                        bail!(source: err, "Failed polling");
+                    }
+                    assert_ne!(res, 0);
+                    break;
+                }
+            }
+
+            // Check for errors or hangup first
+            for (idx, pfd) in self.pollfd.iter().enumerate() {
+                if pfd.revents & (POLLERR | POLLNVAL) != 0 {
+                    bail!(
+                        "Poll error on {} for interface {}",
+                        Self::fd_name(idx, self.pollfd.len()),
+                        idx / 2
+                    );
+                }
+
+                if pfd.revents & POLLHUP != 0 {
+                    bail!(
+                        "Hang up during polling on {} for interface {}",
+                        Self::fd_name(idx, self.pollfd.len()),
+                        idx / 2
+                    );
+                }
+            }
+
+            self.results_cache.clear();
+            // SAFETY: References have the same memory representation independent of lifetime
+            let ready_sockets = unsafe {
+                mem::transmute::<
+                    &mut Vec<(usize, SocketType, &'static UdpSocket)>,
+                    &mut Vec<(usize, SocketType, &'a UdpSocket)>,
+                >(&mut self.results_cache)
+            };
+
+            for (idx, pfd) in self.pollfd.iter().enumerate() {
+                if pfd.revents & POLLIN != 0 {
+                    if idx == self.pollfd.len() - 1 {
+                        break;
+                    }
+                    if idx % 2 == 0 {
+                        ready_sockets.push((
+                            idx / 2,
+                            SocketType::EventSocket,
+                            &self.sockets[idx / 2].0,
+                        ));
+                    } else {
+                        ready_sockets.push((
+                            idx / 2,
+                            SocketType::GeneralSocket,
+                            &self.sockets[idx / 2].1,
+                        ));
+                    }
+                }
+            }
+
+            Ok(PollResult {
+                ready_sockets: &*ready_sockets,
+                sockets: &self.sockets,
+                stdin: if self.pollfd[self.pollfd.len() - 1].revents & POLLIN != 0 {
+                    Some(&self.stdin)
+                } else {
+                    None
+                },
+                stdout: &self.stdout,
+            })
+        }
+    }
+
+    /// Raw, unbuffered handle to `stdin`.
+    ///
+    /// This implements the `Read` trait for reading.
+    pub struct Stdin(RawFd);
+
+    impl Stdin {
+        fn acquire() -> Self {
+            Stdin(STDIN_FILENO)
+        }
+    }
+
+    impl Read for Stdin {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            <&Stdin as Read>::read(&mut &*self, buf)
+        }
+    }
+
+    impl Read for &Stdin {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            // SAFETY: read() requires a valid fd and a mutable buffer with the given size.
+            // The fd is valid by construction as is the buffer.
+            //
+            // read() will return the number of bytes read or a negative value on errors.
+            let res = unsafe { read(self.0, buf.as_mut_ptr(), buf.len()) };
+
+            if res < 0 {
+                Err(std::io::Error::last_os_error())
+            } else {
+                Ok(res as usize)
+            }
+        }
+    }
+
+    /// Raw, unbuffered handle to `stdout`.
+    ///
+    /// This implements the `Write` trait for writing.
+    pub struct Stdout(RawFd);
+
+    impl Stdout {
+        fn acquire() -> Self {
+            Stdout(STDOUT_FILENO)
+        }
+    }
+
+    impl Write for Stdout {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            <&Stdout as Write>::write(&mut &*self, buf)
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            <&Stdout as Write>::flush(&mut &*self)
+        }
+    }
+
+    impl Write for &Stdout {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            // SAFETY: write() requires a valid fd and a mutable buffer with the given size.
+            // The fd is valid by construction as is the buffer.
+            //
+            // write() will return the number of bytes written or a negative value on errors.
+            let res = unsafe { write(self.0, buf.as_ptr(), buf.len()) };
+
+            if res == -1 {
+                Err(std::io::Error::last_os_error())
+            } else {
+                Ok(res as usize)
+            }
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            Ok(())
+        }
+    }
+
+    /// Raw, unbuffered handle to `stderr`.
+    ///
+    /// This implements the `Write` trait for writing and is implemented as a singleton to allow
+    /// usage from everywhere at any time for logging purposes.
+    ///
+    /// This does not implement any locking so usage from multiple threads at once will likely
+    /// cause interleaved output.
+    pub struct Stderr(RawFd);
+
+    impl Stderr {
+        #[cfg(not(test))]
+        pub fn acquire() -> Self {
+            Stderr(STDERR_FILENO)
+        }
+    }
+
+    impl Write for Stderr {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            <&Stderr as Write>::write(&mut &*self, buf)
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            <&Stderr as Write>::flush(&mut &*self)
+        }
+    }
+
+    impl Write for &Stderr {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            // SAFETY: write() requires a valid fd and a mutable buffer with the given size.
+            // The fd is valid by construction as is the buffer.
+            //
+            // write() will return the number of bytes written or a negative value on errors.
+            let res = unsafe { write(self.0, buf.as_ptr(), buf.len()) };
+
+            if res == -1 {
+                Err(std::io::Error::last_os_error())
+            } else {
+                Ok(res as usize)
+            }
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            Ok(())
+        }
+    }
+}
+
+#[cfg(windows)]
+mod imp {
+    use super::{PollResult, SocketType};
+
+    use std::{
+        cmp,
+        io::{self, Read, Write},
+        mem,
+        net::UdpSocket,
+        os::windows::{io::AsRawSocket, raw::HANDLE},
+        ptr,
+        sync::{Arc, Condvar, Mutex},
+        thread,
+    };
+
+    use crate::{
+        bail,
+        error::{Context, Error},
+        ffi::windows::*,
+    };
+
+    /// Inputs and outputs, and allowing to poll the inputs for available data.
+    ///
+    /// This carries the event/general UDP socket and stdin/stdout.
+    pub struct Poll {
+        sockets: Vec<(UdpSocket, UdpSocket)>,
+        events: Vec<(EventHandle, EventHandle)>,
+        stdin: Stdin,
+        stdout: Stdout,
+        handles: Vec<HANDLE>,
+        results_cache: Vec<(usize, SocketType, &'static UdpSocket)>,
+    }
+
+    /// Helper struct for a WSA event.
+    struct EventHandle(HANDLE);
+
+    impl EventHandle {
+        fn new() -> io::Result<Self> {
+            // SAFETY: WSACreateEvent() returns 0 on error or otherwise a valid WSA event
+            // that has to be closed again later.
+            unsafe {
+                let event = WSACreateEvent();
+                if event.is_null() || event == INVALID_HANDLE_VALUE {
+                    Err(io::Error::from_raw_os_error(WSAGetLastError()))
+                } else {
+                    Ok(EventHandle(event))
+                }
+            }
+        }
+    }
+
+    impl Drop for EventHandle {
+        fn drop(&mut self) {
+            // SAFETY: The event is valid by construction and dropped at most once, so can be
+            // safely closed here..
+            //
+            // The return value is intentionally ignored as nothing else can be done
+            // on errors anyway.
+            unsafe {
+                let _ = WSACloseEvent(self.0);
+            }
+        }
+    }
+
+    #[cfg(test)]
+    pub struct Pipe {
+        read: HANDLE,
+        write: HANDLE,
+    }
+
+    #[cfg(test)]
+    impl Drop for Pipe {
+        fn drop(&mut self) {
+            // SAFETY: Both handles are by construction valid up there.
+            unsafe {
+                CloseHandle(self.read);
+                CloseHandle(self.write);
+            }
+        }
+    }
+
+    #[cfg(test)]
+    impl Pipe {
+        fn new() -> io::Result<Self> {
+            // SAFETY: On success returns a non-zero integer and stores read/write handles in the
+            // two out pointers, which will have to be closed again later.
+            unsafe {
+                let mut readpipe = mem::MaybeUninit::uninit();
+                let mut writepipe = mem::MaybeUninit::uninit();
+
+                let res = CreatePipe(
+                    readpipe.as_mut_ptr(),
+                    writepipe.as_mut_ptr(),
+                    ptr::null_mut(),
+                    0,
+                );
+
+                if res != 0 {
+                    Ok(Self {
+                        read: readpipe.assume_init(),
+                        write: writepipe.assume_init(),
+                    })
+                } else {
+                    Err(io::Error::last_os_error())
+                }
+            }
+        }
+    }
+
+    #[cfg(test)]
+    impl Read for &Pipe {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            // SAFETY: Reads the given number of bytes into the buffer from the stdin handle.
+            unsafe {
+                let mut lpnumberofbytesread = mem::MaybeUninit::uninit();
+                let res = ReadFile(
+                    self.read,
+                    buf.as_mut_ptr(),
+                    cmp::min(buf.len() as u32, u32::MAX) as u32,
+                    lpnumberofbytesread.as_mut_ptr(),
+                    ptr::null_mut(),
+                );
+
+                if res == 0 {
+                    Err(io::Error::last_os_error())
+                } else {
+                    Ok(lpnumberofbytesread.assume_init() as usize)
+                }
+            }
+        }
+    }
+
+    #[cfg(test)]
+    impl Write for Pipe {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            // SAFETY: Writes the given number of bytes to stdout or at most u32::MAX. On error
+            // zero is returned, otherwise the number of bytes written is set accordingly and
+            // returned.
+            unsafe {
+                let mut lpnumberofbyteswritten = mem::MaybeUninit::uninit();
+                let res = WriteFile(
+                    self.write,
+                    buf.as_ptr(),
+                    cmp::min(buf.len() as u32, u32::MAX) as u32,
+                    lpnumberofbyteswritten.as_mut_ptr(),
+                    ptr::null_mut(),
+                );
+
+                if res == 0 {
+                    Err(io::Error::last_os_error())
+                } else {
+                    Ok(lpnumberofbyteswritten.assume_init() as usize)
+                }
+            }
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            Ok(())
+        }
+    }
+
+    impl Poll {
+        /// Internal constructor.
+        pub fn new_internal(
+            sockets: Vec<(UdpSocket, UdpSocket)>,
+            stdin: Stdin,
+            stdout: Stdout,
+        ) -> Result<Self, Error> {
+            // Create event objects for the readability of the sockets.
+            let events = sockets
+                .iter()
+                .map(|(_event_socket, _general_socket)| -> Result<_, Error> {
+                    Ok((
+                        EventHandle::new().context("Failed creating WSA event")?,
+                        EventHandle::new().context("Failed creating WSA event")?,
+                    ))
+                })
+                .collect::<Result<Vec<_>, Error>>()?;
+
+            for ((event_socket, general_socket), (event_socket_event, general_socket_event)) in
+                Iterator::zip(sockets.iter(), events.iter())
+            {
+                // SAFETY: WSAEventSelect() requires a valid socket and WSA event, which are both
+                // passed here, and the bitflag of events that should be selected for.
+                //
+                // On error a non-zero value is returned.
+                unsafe {
+                    if WSAEventSelect(event_socket.as_raw_socket(), event_socket_event.0, FD_READ)
+                        != 0
+                    {
+                        bail!(
+                            source: io::Error::from_raw_os_error(WSAGetLastError()),
+                            "Failed selecting for read events on event socket"
+                        );
+                    }
+
+                    if WSAEventSelect(
+                        general_socket.as_raw_socket(),
+                        general_socket_event.0,
+                        FD_READ,
+                    ) != 0
+                    {
+                        bail!(
+                            source: io::Error::from_raw_os_error(WSAGetLastError()),
+                            "Failed selecting for read events on general socket"
+                        );
+                    }
+                }
+            }
+
+            let n_sockets = sockets.len();
+
+            Ok(Self {
+                sockets,
+                events,
+                stdin,
+                stdout,
+                handles: Vec::with_capacity(n_sockets * 2 + 1),
+                results_cache: Vec::with_capacity(1),
+            })
+        }
+
+        /// Create a new `Poll` instance from the two sockets.
+        pub fn new(sockets: Vec<(UdpSocket, UdpSocket)>) -> Result<Self, Error> {
+            let stdin = Stdin::acquire().context("Failure acquiring stdin handle")?;
+            let stdout = Stdout::acquire().context("Failed acquiring stdout handle")?;
+
+            Self::new_internal(sockets, stdin, stdout)
+        }
+
+        #[cfg(test)]
+        /// Create a new `Poll` instance for testing purposes.
+        ///
+        /// The returned `Pipe`s are for stdin and stdout.
+        pub fn new_test(
+            event_socket: UdpSocket,
+            general_socket: UdpSocket,
+        ) -> Result<(Self, Pipe, Pipe), Error> {
+            let stdin_pipe = Pipe::new().unwrap();
+            let stdout_pipe = Pipe::new().unwrap();
+
+            let stdin =
+                Stdin::from_handle(stdin_pipe.read).context("Failure acquiring stdin handle")?;
+            let stdout =
+                Stdout::from_handle(stdout_pipe.write).context("Failed acquiring stdout handle")?;
+
+            let poll = Self::new_internal(vec![(event_socket, general_socket)], stdin, stdout)?;
+
+            Ok((poll, stdin_pipe, stdout_pipe))
+        }
+
+        /// Reference to the event socket.
+        #[allow(unused)]
+        pub fn event_socket(&self, iface: usize) -> &UdpSocket {
+            &self.sockets[iface].0
+        }
+
+        /// Reference to the general socket.
+        #[allow(unused)]
+        pub fn general_socket(&self, iface: usize) -> &UdpSocket {
+            &self.sockets[iface].1
+        }
+
+        /// Reference to stdin for reading.
+        #[allow(unused)]
+        pub fn stdin(&self) -> &Stdin {
+            &self.stdin
+        }
+
+        /// Reference to stdout for writing.
+        pub fn stdout(&self) -> &Stdout {
+            &self.stdout
+        }
+
+        /// Poll the event socket, general socket and stdin for available data to read.
+        ///
+        /// This blocks until at least one input has data available.
+        pub fn poll<'a>(&'a mut self) -> Result<PollResult<'a>, Error> {
+            self.handles.clear();
+
+            for (event_socket_event, general_socket_event) in &self.events {
+                self.handles.push(event_socket_event.0);
+                self.handles.push(general_socket_event.0);
+            }
+
+            self.handles.push(
+                // If stdin is a pipe then we use the signalling event, otherwise stdin itself.
+                if let Some(ref thread_state) = self.stdin.thread_state {
+                    thread_state.event
+                } else {
+                    self.stdin.handle
+                },
+            );
+
+            // If stdin is a pipe and currently no data is pending on it then signal
+            // the reading thread to try reading one byte and blocking for that long.
+            if let Some(ref mut thread_state) = self.stdin.thread_state {
+                let mut guard = thread_state.buffer.lock().unwrap();
+                if !guard.buffer_filled && !guard.fill_buffer {
+                    guard.fill_buffer = true;
+                    // SAFETY: The thread's event is valid by construction until the thread
+                    // is stopped, and can be reset at any time.
+                    unsafe {
+                        ResetEvent(thread_state.event);
+                    }
+                    thread_state.buffer_cond.notify_one();
+                }
+            }
+
+            // SAFETY: Wait for the socket/stdin objects to become ready. This requires a valid
+            // array of valid handles and the corresponding length, whether it should wait for all
+            // handles (no), and a timeout (infinity).
+            //
+            // On error u32::MAX is returned, otherwise an index into the array of handles is
+            // returned for the handle that became ready.
+            let res = unsafe {
+                let res = WaitForMultipleObjects(
+                    self.handles.len() as _,
+                    self.handles[..].as_ptr(),
+                    0,
+                    u32::MAX,
+                );
+                if res == u32::MAX {
+                    bail!(
+                        source: io::Error::from_raw_os_error(WSAGetLastError()),
+                        "Failed waiting for events"
+                    );
+                }
+
+                assert!(
+                    (0..self.handles.len()).contains(&(res as usize)),
+                    "Unexpected WaitForMultipleObjects() return value {}",
+                    res,
+                );
+
+                res as usize
+            };
+
+            self.results_cache.clear();
+            // SAFETY: References have the same memory representation independent of lifetime
+            let ready_sockets = unsafe {
+                mem::transmute::<
+                    &mut Vec<(usize, SocketType, &'static UdpSocket)>,
+                    &mut Vec<(usize, SocketType, &'a UdpSocket)>,
+                >(&mut self.results_cache)
+            };
+
+            // For the sockets, enumerate the events that woke up the waiting, collect any errors
+            // and reset the event objects.
+            if res < self.handles.len() - 1 {
+                let (socket, event) = if res % 2 == 0 {
+                    (&self.sockets[res / 2].0, &self.events[res / 2].0)
+                } else {
+                    (&self.sockets[res / 2].1, &self.events[res / 2].1)
+                };
+
+                // SAFETY: Requires a valid socket and event, which is given by construction here.
+                // The passed in memory for the network events will be filled if no error happens,
+                // and the function returns a non-zero value if an error has happened.
+                let networkevents = unsafe {
+                    let mut networkevents = mem::MaybeUninit::uninit();
+                    if WSAEnumNetworkEvents(
+                        socket.as_raw_socket(),
+                        event.0,
+                        networkevents.as_mut_ptr(),
+                    ) != 0
+                    {
+                        bail!(
+                            source: io::Error::from_raw_os_error(WSAGetLastError()),
+                            "Failed enumerating network events on {} socket for interface {}",
+                            if res % 2 == 0 { "event" } else { "general" },
+                            res / 2,
+                        );
+                    }
+
+                    networkevents.assume_init()
+                };
+
+                if networkevents.ierrorcode[FD_READ_BIT] != 0 {
+                    bail!(
+                        source: io::Error::from_raw_os_error(networkevents.ierrorcode[FD_READ_BIT]),
+                        "Error on {} socket for interface {} while waiting for events",
+                        if res == 0 { "event" } else { "general" },
+                        res / 2,
+                    );
+                }
+
+                // FIXME: This seems to happen every now and then although it shouldn't, and in
+                // that case a packet always seems to be queued up on the socket. As the sockets
+                // are non-blocking it also wouldn't be a problem otherwise, so let's just log this
+                // here and ignore it.
+                if networkevents.lnetworkevents & FD_READ == 0 {
+                    debug!(
+                        "Socket {} woke up but has neither an error nor a FD_READ event",
+                        res
+                    );
+                }
+                ready_sockets.push((
+                    res / 2,
+                    if res % 2 == 0 {
+                        SocketType::EventSocket
+                    } else {
+                        SocketType::GeneralSocket
+                    },
+                    socket,
+                ));
+            }
+
+            Ok(PollResult {
+                ready_sockets: &*ready_sockets,
+                sockets: &self.sockets,
+                stdin: if res == self.handles.len() - 1 {
+                    Some(&self.stdin)
+                } else {
+                    None
+                },
+                stdout: &self.stdout,
+            })
+        }
+    }
+
+    /// Raw, unbuffered handle to `stdin`.
+    ///
+    /// This implements the `Read` trait for reading.
+    pub struct Stdin {
+        handle: HANDLE,
+        thread_state: Option<Arc<StdinThreadState>>,
+        join_handle: Option<thread::JoinHandle<()>>,
+    }
+
+    struct StdinThreadState {
+        buffer: Mutex<StdinBuffer>,
+        buffer_cond: Condvar,
+        event: HANDLE,
+        handle: HANDLE,
+    }
+
+    unsafe impl Send for StdinThreadState {}
+    unsafe impl Sync for StdinThreadState {}
+
+    struct StdinBuffer {
+        buffer: [u8; 1],
+        error: Option<io::Error>,
+        buffer_filled: bool,
+        fill_buffer: bool,
+        shutdown: bool,
+    }
+
+    impl Drop for Stdin {
+        fn drop(&mut self) {
+            // If stdin was a pipe and a thread was started to check for read-readiness
+            // then stop this thread now and release its resources.
+            if let Some(ref thread_state) = self.thread_state {
+                let mut guard = thread_state.buffer.lock().unwrap();
+                guard.shutdown = true;
+                thread_state.buffer_cond.notify_one();
+                drop(guard);
+                let _ = self.join_handle.take().unwrap().join();
+
+                // SAFETY: The thread is stopped now so the event is not used by anything else
+                // anymore and can safely be closed now.
+                //
+                // The return value is explicitly ignored because nothing can be done on error
+                // anyway.
+                unsafe {
+                    let _ = CloseHandle(thread_state.event);
+                }
+            }
+        }
+    }
+
+    impl Stdin {
+        fn acquire() -> Result<Self, Error> {
+            // SAFETY: GetStdHandle returns a borrowed handle, or 0 if none is set or -1 if an
+            // error has happened.
+            let handle = unsafe {
+                let handle = GetStdHandle(STD_INPUT_HANDLE);
+                if handle.is_null() {
+                    bail!("No stdin handle set");
+                } else if handle == INVALID_HANDLE_VALUE {
+                    bail!(source: io::Error::last_os_error(), "Can't get stdin handle");
+                }
+
+                handle
+            };
+
+            Self::from_handle(handle)
+        }
+
+        fn from_handle(handle: HANDLE) -> Result<Self, Error> {
+            // SAFETY: GetFileType() is safe to call on any valid handle.
+            let type_ = unsafe { GetFileType(handle) };
+
+            if type_ == FILE_TYPE_CHAR {
+                // Set the console to raw mode and flush any pending input.
+                //
+                // SAFETY: Calling this on non-console handles will cause an error but otherwise
+                // have no negative effects. We can safely change the console mode here as nothing
+                // else is accessing the console.
+                unsafe {
+                    let _ = SetConsoleMode(handle, 0);
+                    let _ = FlushConsoleInputBuffer(handle);
+                }
+
+                Ok(Stdin {
+                    handle,
+                    thread_state: None,
+                    join_handle: None,
+                })
+            } else if type_ == FILE_TYPE_PIPE {
+                // XXX: Because g_spawn() creates the overridden pipes with _pipe(), they're
+                //        1. Full duplex, so WaitForMultipleObjects() always considers them ready as you can write
+                //        2. Not overlapped so only synchronous IO can be used
+                //      To work around this we're creating a thread here that just reads synchronously
+                //      from stdin to signal ready-ness.
+
+                // SAFETY: Creating an event handle with all-zero parameters is valid and on error
+                // a NULL handle will be returned. Otherwise a valid event handle is returned that
+                // needs to be closed again later, which happens as part of the StdinThreadState
+                // Drop implementation.
+                let event = unsafe {
+                    let event = CreateEventA(ptr::null(), 0, 0, ptr::null());
+                    if event.is_null() {
+                        bail!(
+                            source: io::Error::last_os_error(),
+                            "Failed creating event handle"
+                        );
+                    }
+
+                    event
+                };
+                let thread_state = Arc::new(StdinThreadState {
+                    buffer: Mutex::new(StdinBuffer {
+                        buffer: [0],
+                        error: None,
+                        buffer_filled: false,
+                        fill_buffer: true,
+                        shutdown: false,
+                    }),
+                    buffer_cond: Condvar::new(),
+                    event,
+                    handle,
+                });
+
+                let join_handle = thread::spawn({
+                    let thread_state = thread_state.clone();
+                    move || Self::stdin_readiness_thread(&thread_state)
+                });
+
+                Ok(Stdin {
+                    handle,
+                    thread_state: Some(thread_state),
+                    join_handle: Some(join_handle),
+                })
+            } else {
+                bail!("unhandled stdin handle type {:x}", type_);
+            }
+        }
+
+        /// Thread function to signal readiness of stdin.
+        ///
+        /// This thread tries to read a single byte and buffers it, then signals an event
+        /// object and waits for reading to finish and a new call to `poll()` to
+        /// start trying to read a single byte again.
+        fn stdin_readiness_thread(thread_state: &StdinThreadState) {
+            loop {
+                let mut buffer = [0u8];
+                // SAFETY: Reads one byte from the handle synchronously. Nothing else is currently
+                // reading from the handle as this thread is waiting below on the condition
+                // variable as long as a single byte was read already, and only wakes up again if a
+                // full packet was read from stdin and the other thread is waiting on the event
+                // handle again.
+                let res = unsafe {
+                    let mut bytes_read = mem::MaybeUninit::uninit();
+                    let res = ReadFile(
+                        thread_state.handle,
+                        buffer[..].as_mut_ptr(),
+                        buffer.len() as u32,
+                        bytes_read.as_mut_ptr(),
+                        ptr::null_mut(),
+                    );
+                    if res == 0 {
+                        Err(io::Error::last_os_error())
+                    } else {
+                        Ok(bytes_read.assume_init())
+                    }
+                };
+
+                let mut guard = thread_state.buffer.lock().unwrap();
+                assert!(!guard.buffer_filled);
+                assert!(guard.fill_buffer);
+                if guard.shutdown {
+                    break;
+                }
+                guard.buffer_filled = true;
+                guard.fill_buffer = false;
+                match res {
+                    Err(err) => {
+                        guard.error = Some(err);
+                    }
+                    Ok(bytes_read) => {
+                        guard.buffer[0] = buffer[0];
+                        assert_eq!(bytes_read, 1);
+                    }
+                }
+
+                // SAFETY: Signalling an event is valid from any thread at any time and the event
+                // handle is valid by construction.
+                unsafe {
+                    SetEvent(thread_state.event);
+                }
+                while !guard.shutdown && !guard.fill_buffer {
+                    guard = thread_state.buffer_cond.wait(guard).unwrap();
+                }
+                if guard.shutdown {
+                    break;
+                }
+            }
+        }
+    }
+
+    impl Read for Stdin {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            <&Stdin as Read>::read(&mut &*self, buf)
+        }
+    }
+
+    impl Read for &Stdin {
+        fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
+            if buf.is_empty() {
+                return Ok(0);
+            }
+
+            // If a read byte is pending from the readiness signalling thread then
+            // read that first here before reading any remaining data.
+            let mut already_read = 0;
+            if let Some(ref thread_state) = self.thread_state {
+                let mut guard = thread_state.buffer.lock().unwrap();
+                assert!(!guard.fill_buffer);
+                if guard.buffer_filled {
+                    guard.buffer_filled = false;
+                    if let Some(err) = guard.error.take() {
+                        return Err(err);
+                    }
+                    buf[0] = guard.buffer[0];
+                    if buf.len() == 1 {
+                        return Ok(1);
+                    }
+                    buf = &mut buf[1..];
+                    already_read = 1;
+                }
+            }
+
+            // SAFETY: Reads the given number of bytes into the buffer from the stdin handle.
+            // The other thread is not currently reading as checked above, and would only be
+            // triggered to read again by this thread once poll() is called.
+            unsafe {
+                let mut lpnumberofbytesread = mem::MaybeUninit::uninit();
+                let res = ReadFile(
+                    self.handle,
+                    buf.as_mut_ptr(),
+                    cmp::min(buf.len() as u32, u32::MAX) as u32,
+                    lpnumberofbytesread.as_mut_ptr(),
+                    ptr::null_mut(),
+                );
+
+                if res == 0 {
+                    Err(io::Error::last_os_error())
+                } else {
+                    Ok(lpnumberofbytesread.assume_init() as usize + already_read)
+                }
+            }
+        }
+    }
+
+    /// Raw, unbuffered handle to `stdout`.
+    ///
+    /// This implements the `Write` trait for writing.
+    pub struct Stdout(HANDLE);
+
+    impl Stdout {
+        fn acquire() -> Result<Self, Error> {
+            // SAFETY: GetStdHandle returns a borrowed handle, or 0 if none is set or -1 if an
+            // error has happened.
+            let handle = unsafe {
+                let handle = GetStdHandle(STD_OUTPUT_HANDLE);
+                if handle.is_null() {
+                    bail!("No stdout handle set");
+                } else if handle == INVALID_HANDLE_VALUE {
+                    bail!(
+                        source: io::Error::last_os_error(),
+                        "Can't get stdout handle"
+                    );
+                }
+
+                handle
+            };
+
+            Self::from_handle(handle)
+        }
+
+        fn from_handle(handle: HANDLE) -> Result<Self, Error> {
+            // SAFETY: GetFileType() is safe to call on any valid handle.
+            let type_ = unsafe { GetFileType(handle) };
+
+            if type_ == FILE_TYPE_CHAR {
+                // Set the console to raw mode.
+                //
+                // SAFETY: Calling this on non-console handles will cause an error but otherwise
+                // have no negative effects. We can safely change the console mode here as nothing
+                // else is accessing the console.
+                unsafe {
+                    let _ = SetConsoleMode(handle, 0);
+                }
+            } else if type_ != FILE_TYPE_PIPE {
+                bail!("Unsupported stdout handle type {:x}", type_);
+            }
+
+            Ok(Stdout(handle))
+        }
+    }
+
+    impl Write for Stdout {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            <&Stdout as Write>::write(&mut &*self, buf)
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            <&Stdout as Write>::flush(&mut &*self)
+        }
+    }
+
+    impl Write for &Stdout {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            // SAFETY: Writes the given number of bytes to stdout or at most u32::MAX. On error
+            // zero is returned, otherwise the number of bytes written is set accordingly and
+            // returned.
+            unsafe {
+                let mut lpnumberofbyteswritten = mem::MaybeUninit::uninit();
+                let res = WriteFile(
+                    self.0,
+                    buf.as_ptr(),
+                    cmp::min(buf.len() as u32, u32::MAX) as u32,
+                    lpnumberofbyteswritten.as_mut_ptr(),
+                    ptr::null_mut(),
+                );
+
+                if res == 0 {
+                    Err(io::Error::last_os_error())
+                } else {
+                    Ok(lpnumberofbyteswritten.assume_init() as usize)
+                }
+            }
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            Ok(())
+        }
+    }
+
+    /// Raw, unbuffered handle to `stderr`.
+    ///
+    /// This implements the `Write` trait for writing and is implemented as a singleton to allow
+    /// usage from everywhere at any time for logging purposes.
+    ///
+    /// This does not implement any locking so usage from multiple threads at once will likely
+    /// cause interleaved output.
+    pub struct Stderr(HANDLE);
+
+    impl Stderr {
+        #[cfg(not(test))]
+        pub fn acquire() -> Self {
+            use std::sync::Once;
+
+            struct SyncHandle(HANDLE);
+            // SAFETY: This is a single-threaded application and even otherwise writing from
+            // multiple threads at once to a pipe is safe and will only cause interleaved output.
+            unsafe impl Send for SyncHandle {}
+            unsafe impl Sync for SyncHandle {}
+
+            static mut STDERR: SyncHandle = SyncHandle(INVALID_HANDLE_VALUE);
+            static STDERR_ONCE: Once = Once::new();
+
+            STDERR_ONCE.call_once(|| {
+                // SAFETY: GetStdHandle returns a borrowed handle, or 0 if none is set or -1 if an
+                // error has happened.
+                let handle = unsafe {
+                    let handle = GetStdHandle(STD_ERROR_HANDLE);
+                    if handle.is_null() {
+                        return;
+                    } else if handle == INVALID_HANDLE_VALUE {
+                        return;
+                    }
+
+                    handle
+                };
+
+                // SAFETY: GetFileType() is safe to call on any valid handle.
+                let type_ = unsafe { GetFileType(handle) };
+
+                if type_ == FILE_TYPE_CHAR {
+                    // Set the console to raw mode.
+                    //
+                    // SAFETY: Calling this on non-console handles will cause an error but otherwise
+                    // have no negative effects. We can safely change the console mode here as nothing
+                    // else is accessing the console.
+                    unsafe {
+                        let _ = SetConsoleMode(handle, 0);
+                    }
+                } else if type_ != FILE_TYPE_PIPE {
+                    return;
+                }
+
+                // SAFETY: Only accessed in this function and multiple mutable accesses are
+                // prevented by the `Once`.
+                unsafe {
+                    STDERR.0 = handle;
+                }
+            });
+
+            // SAFETY: Only accesses immutably here and all mutable accesses are serialized above
+            // by the `Once`.
+            Stderr(unsafe { STDERR.0 })
+        }
+    }
+
+    impl Write for Stderr {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            <&Stderr as Write>::write(&mut &*self, buf)
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            <&Stderr as Write>::flush(&mut &*self)
+        }
+    }
+
+    impl Write for &Stderr {
+        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+            if self.0 == INVALID_HANDLE_VALUE {
+                return Ok(buf.len());
+            }
+
+            // SAFETY: Writes the given number of bytes to stderr or at most u32::MAX. On error
+            // zero is returned, otherwise the number of bytes written is set accordingly and
+            // returned.
+            unsafe {
+                let mut lpnumberofbyteswritten = mem::MaybeUninit::uninit();
+                let res = WriteFile(
+                    self.0,
+                    buf.as_ptr(),
+                    cmp::min(buf.len() as u32, u32::MAX) as u32,
+                    lpnumberofbyteswritten.as_mut_ptr(),
+                    ptr::null_mut(),
+                );
+
+                if res == 0 {
+                    Err(io::Error::last_os_error())
+                } else {
+                    Ok(lpnumberofbyteswritten.assume_init() as usize)
+                }
+            }
+        }
+
+        fn flush(&mut self) -> io::Result<()> {
+            Ok(())
+        }
+    }
+}
+
+// `Stderr` is not used when tests are enabled as no logging is performed to stderr.
+#[cfg_attr(test, allow(unused_imports))]
+pub use self::imp::Stderr;
+pub use self::imp::{Poll, Stdin, Stdout};
+
+#[cfg(test)]
+mod test {
+    #[test]
+    fn test_poll() {
+        use super::{Poll, SocketType};
+
+        use std::io::prelude::*;
+
+        let event_socket = std::net::UdpSocket::bind(std::net::SocketAddr::from((
+            std::net::Ipv4Addr::LOCALHOST,
+            0,
+        )))
+        .unwrap();
+        let event_port = event_socket.local_addr().unwrap().port();
+
+        let general_socket = std::net::UdpSocket::bind(std::net::SocketAddr::from((
+            std::net::Ipv4Addr::LOCALHOST,
+            0,
+        )))
+        .unwrap();
+        let general_port = general_socket.local_addr().unwrap().port();
+
+        let send_socket = std::net::UdpSocket::bind(std::net::SocketAddr::from((
+            std::net::Ipv4Addr::LOCALHOST,
+            0,
+        )))
+        .unwrap();
+
+        let (mut poll, mut stdin, _stdout) = Poll::new_test(event_socket, general_socket).unwrap();
+
+        let mut buf = [0u8; 4];
+
+        for _ in 0..10 {
+            send_socket
+                .send_to(&[1, 2, 3, 4], (std::net::Ipv4Addr::LOCALHOST, event_port))
+                .unwrap();
+            let res = poll.poll().unwrap();
+            assert_eq!(res.ready_sockets().len(), 1);
+            assert_eq!(res.ready_sockets()[0].0, 0);
+            assert_eq!(res.ready_sockets()[0].1, SocketType::EventSocket);
+            assert_eq!(res.ready_sockets()[0].2.recv(&mut buf).unwrap(), 4);
+            assert_eq!(buf, [1, 2, 3, 4]);
+
+            send_socket
+                .send_to(&[1, 2, 3, 4], (std::net::Ipv4Addr::LOCALHOST, general_port))
+                .unwrap();
+            let res = poll.poll().unwrap();
+
+            assert_eq!(res.ready_sockets().len(), 1);
+            assert_eq!(res.ready_sockets()[0].0, 0);
+            assert_eq!(res.ready_sockets()[0].1, SocketType::GeneralSocket);
+            assert_eq!(res.ready_sockets()[0].2.recv(&mut buf).unwrap(), 4);
+            assert_eq!(buf, [1, 2, 3, 4]);
+
+            stdin.write_all(&[1, 2, 3, 4]).unwrap();
+            let res = poll.poll().unwrap();
+            assert!(res.ready_sockets().is_empty());
+            {
+                let mut stdin = res.stdin();
+                let stdin = stdin.as_mut().unwrap();
+                stdin.read_exact(&mut buf).unwrap();
+                assert_eq!(buf, [1, 2, 3, 4]);
+            }
+        }
+
+        drop(poll);
+    }
+}
diff --git a/libs/gst/helpers/ptp/log.rs b/libs/gst/helpers/ptp/log.rs
new file mode 100644
index 0000000..fbc33b4
--- /dev/null
+++ b/libs/gst/helpers/ptp/log.rs
@@ -0,0 +1,109 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+#[cfg(not(test))]
+use crate::io::Stderr;
+#[cfg(not(test))]
+use std::io::{self, Cursor, Write};
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+#[repr(u8)]
+#[allow(dead_code)]
+pub enum LogLevel {
+    Error = 1,
+    Warning = 2,
+    _Fixme = 3,
+    Info = 4,
+    Debug = 5,
+    _Log = 6,
+    Trace = 7,
+}
+
+/*
+ * - 1 byte GstDebugLevel
+ * - 2 byte BE filename length
+ * - filename UTF-8 string
+ * - 2 byte BE module path length
+ * - module path UTF-8 string
+ * - 4 byte BE line number
+ * - remainder is UTF-8 string
+*/
+#[cfg(test)]
+pub fn log(
+    _level: LogLevel,
+    _file: &str,
+    _module_path: &str,
+    _line: u32,
+    _args: std::fmt::Arguments,
+) {
+}
+
+#[cfg(not(test))]
+pub fn log(level: LogLevel, file: &str, module_path: &str, line: u32, args: std::fmt::Arguments) {
+    let mut stderr = Stderr::acquire();
+    let mut buffer = [0u8; 8192];
+    let mut cursor = Cursor::new(&mut buffer[..]);
+
+    // Silently ignore errors. What was written to the buffer was written and if there's more data
+    // than fits it will simply be cut off in the end.
+    let _ = (|| -> Result<(), io::Error> {
+        cursor.write_all(&[0u8, 0u8])?;
+        cursor.write_all(&[level as u8])?;
+        cursor.write_all(&(file.len() as u16).to_be_bytes())?;
+        cursor.write_all(file.as_bytes())?;
+        cursor.write_all(&(module_path.len() as u16).to_be_bytes())?;
+        cursor.write_all(module_path.as_bytes())?;
+        cursor.write_all(&line.to_be_bytes())?;
+        cursor.write_fmt(args)?;
+
+        Ok(())
+    })();
+
+    let pos = cursor.position() as u16;
+    if pos < 2 {
+        return;
+    }
+
+    cursor.set_position(0);
+    let _ = cursor.write_all(&(pos - 2).to_be_bytes());
+
+    let _ = stderr.write_all(&buffer[..pos as usize]);
+}
+
+#[allow(unused_macros)]
+macro_rules! error {
+    ($format:expr $(, $arg:expr)* $(,)?) => {{
+        $crate::log::log($crate::log::LogLevel::Error, file!(), module_path!(), line!(), format_args!($format, $($arg),*));
+    }};
+}
+#[allow(unused_macros)]
+macro_rules! warn {
+    ($format:expr $(, $arg:expr)* $(,)?) => {{
+        $crate::log::log($crate::log::LogLevel::Warning, file!(), module_path!(), line!(), format_args!($format, $($arg),*));
+    }};
+}
+#[allow(unused_macros)]
+macro_rules! info {
+    ($format:expr $(, $arg:expr)* $(,)?) => {{
+        $crate::log::log($crate::log::LogLevel::Info, file!(), module_path!(), line!(), format_args!($format, $($arg),*));
+    }};
+}
+#[allow(unused_macros)]
+macro_rules! debug {
+    ($format:expr $(, $arg:expr)* $(,)?) => {{
+        $crate::log::log($crate::log::LogLevel::Debug, file!(), module_path!(), line!(), format_args!($format, $($arg),*));
+    }};
+}
+#[allow(unused_macros)]
+macro_rules! trace {
+    ($format:expr $(, $arg:expr)* $(,)?) => {{
+        $crate::log::log($crate::log::LogLevel::Trace, file!(), module_path!(), line!(), format_args!($format, $($arg),*));
+    }};
+}
diff --git a/libs/gst/helpers/ptp/main.rs b/libs/gst/helpers/ptp/main.rs
new file mode 100644
index 0000000..e550f53
--- /dev/null
+++ b/libs/gst/helpers/ptp/main.rs
@@ -0,0 +1,422 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+//! Helper process that runs setuid root or with appropriate privileges to
+//! listen on ports < 1024, do multicast operations and get MAC addresses of
+//! interfaces. Privileges are dropped after these operations are done.
+//!
+//! It listens on the PTP multicast group on port 319 and 320 and forwards
+//! everything received there to stdout, while forwarding everything received
+//! on stdin to those sockets.
+//! Additionally it provides the MAC address of a network interface via stdout
+
+use std::{
+    io::{Read, Write},
+    net::{Ipv4Addr, UdpSocket},
+};
+
+#[macro_use]
+mod log;
+
+mod args;
+mod clock;
+mod error;
+mod ffi;
+mod io;
+mod net;
+mod parse;
+mod privileges;
+mod rand;
+mod thread;
+
+use error::{Context, Error};
+use parse::{PtpClockIdentity, PtpMessagePayload, PtpMessageType, ReadBytesBEExt, WriteBytesBEExt};
+use rand::rand;
+
+/// PTP Multicast group.
+const PTP_MULTICAST_ADDR: Ipv4Addr = Ipv4Addr::new(224, 0, 1, 129);
+/// PTP Event message port.
+const PTP_EVENT_PORT: u16 = 319;
+/// PTP General message port.
+const PTP_GENERAL_PORT: u16 = 320;
+
+/// StdIO Message Types.
+/// PTP message for the event socket.
+const MSG_TYPE_EVENT: u8 = 0;
+/// PTP message for the general socket.
+const MSG_TYPE_GENERAL: u8 = 1;
+/// Clock ID message
+const MSG_TYPE_CLOCK_ID: u8 = 2;
+/// Send time ACK message
+const MSG_TYPE_SEND_TIME_ACK: u8 = 3;
+
+/// Create a new `UdpSocket` for the given port and configure it for PTP.
+fn create_socket(port: u16, iface: &net::InterfaceInfo, ttl: u32) -> Result<UdpSocket, Error> {
+    let socket = net::create_udp_socket(&Ipv4Addr::UNSPECIFIED, port, Some(iface))
+        .with_context(|| format!("Failed to bind socket to port {}", port))?;
+
+    socket
+        .set_nonblocking(true)
+        .context("Failed setting socket non-blocking")?;
+    socket
+        .set_ttl(ttl)
+        .context("Failed setting TTL on socket")?;
+    socket
+        .set_multicast_ttl_v4(ttl)
+        .context("Failed to set multicast TTL on socket")?;
+
+    Ok(socket)
+}
+
+/// Retrieve the list of interfaces based on the available ones and the arguments.
+fn list_interfaces(args: &args::Args) -> Result<Vec<net::InterfaceInfo>, Error> {
+    let mut ifaces = net::query_interfaces().context("Failed to query network interfaces")?;
+    if ifaces.is_empty() {
+        bail!("No suitable network interfaces for PTP found");
+    }
+
+    if !args.interfaces.is_empty() {
+        ifaces.retain(|iface| {
+            for filter_iface in &args.interfaces {
+                if &iface.name == filter_iface {
+                    return true;
+                }
+                if let Some(ref other_name) = iface.other_name {
+                    if other_name == filter_iface {
+                        return true;
+                    }
+                }
+                if let Ok(addr) = filter_iface.parse::<Ipv4Addr>() {
+                    if addr == iface.ip_addr {
+                        return true;
+                    }
+                }
+            }
+
+            info!("Interface {} filtered out", iface.name);
+
+            false
+        });
+
+        if ifaces.is_empty() {
+            bail!("None of the selected network interfaces found");
+        }
+        if ifaces.len() != args.interfaces.len() {
+            bail!("Not all selected network interfaces found");
+        }
+    }
+
+    Ok(ifaces)
+}
+
+fn run() -> Result<(), Error> {
+    let args = args::parse_args().context("Failed parsing commandline parameters")?;
+
+    let ifaces = list_interfaces(&args).context("Failed listing interfaces")?;
+
+    let mut sockets = vec![];
+    for iface in &ifaces {
+        info!("Binding to interface {}", iface.name);
+
+        let event_socket = create_socket(PTP_EVENT_PORT, iface, args.ttl)
+            .context("Failed creating event socket")?;
+        let general_socket = create_socket(PTP_GENERAL_PORT, iface, args.ttl)
+            .context("Failed creating general socket")?;
+
+        for socket in [&event_socket, &general_socket].iter() {
+            net::join_multicast_v4(socket, &PTP_MULTICAST_ADDR, iface)
+                .context("Failed to join multicast group")?;
+        }
+
+        sockets.push((event_socket, general_socket));
+    }
+
+    let clock_id = if args.clock_id == 0 {
+        ifaces
+            .iter()
+            .find_map(|iface| iface.hw_addr)
+            .map(|hw_addr| {
+                [
+                    hw_addr[0], hw_addr[1], hw_addr[2], 0xff, 0xfe, hw_addr[3], hw_addr[4],
+                    hw_addr[5],
+                ]
+            })
+            .unwrap_or_else(rand)
+    } else {
+        args.clock_id.to_be_bytes()
+    };
+    info!("Using clock ID {:?}", clock_id);
+
+    thread::set_priority().context("Failed to set thread priority")?;
+
+    privileges::drop().context("Failed dropping privileges")?;
+
+    let mut poll = io::Poll::new(sockets).context("Failed creating poller")?;
+
+    // Write clock ID first
+    {
+        let mut clock_id_data = [0u8; 3 + 8];
+        {
+            let mut buf = &mut clock_id_data[..];
+            buf.write_u16be(8).expect("Too small clock ID buffer");
+            buf.write_u8(MSG_TYPE_CLOCK_ID)
+                .expect("Too small clock ID buffer");
+            buf.write_all(&clock_id).expect("Too small clock ID buffer");
+            assert!(buf.is_empty(), "Too big clock ID buffer");
+        }
+
+        poll.stdout()
+            .write_all(&clock_id_data)
+            .context("Failed writing to stdout")?;
+    }
+
+    // Now read-write from stdin/stdout and the sockets
+    //
+    // We assume that stdout never blocks and stdin receives a complete valid packet whenever it is
+    // ready and never blocks in the middle of a packet.
+    let mut socket_buffer = [0u8; 8192];
+    let mut stdinout_buffer = [0u8; 8192 + 4 + 8];
+
+    loop {
+        let poll_res = poll.poll().context("Failed polling")?;
+
+        // If any of the sockets are ready, continue reading packets from them until no more
+        // packets are left and directly forward them to stdout.
+        'next_socket: for (idx, type_, socket) in poll_res.ready_sockets() {
+            let idx = *idx;
+            let type_ = *type_;
+
+            // Read all available packets from the socket before going to the next socket.
+            'next_packet: loop {
+                let res = socket.recv_from(&mut socket_buffer);
+
+                let (read, addr) = match res {
+                    Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {
+                        continue 'next_socket;
+                    }
+                    Err(err) => {
+                        bail!(
+                            source: err,
+                            "Failed reading from {:?} socket for interface {}",
+                            type_,
+                            idx,
+                        );
+                    }
+                    Ok((read, addr)) => (read, addr),
+                };
+
+                let recv_time = clock::time();
+                if args.verbose {
+                    trace!(
+                        "Received {} bytes from {:?} socket for interface {} from {} at {}",
+                        read,
+                        type_,
+                        idx,
+                        addr,
+                        recv_time,
+                    );
+                }
+
+                let buf = &socket_buffer[..read];
+
+                // Check if this is a valid PTP message, that it is not a PTP message sent from
+                // our own clock ID and in case of a DELAY_RESP that it is for our clock id.
+                let ptp_message = match parse::PtpMessage::parse(buf) {
+                    Ok(msg) => msg,
+                    Err(err) => {
+                        warn!("Received invalid PTP message: {}", err);
+                        continue 'next_packet;
+                    }
+                };
+
+                if args.verbose {
+                    trace!("Received PTP message {:#?}", ptp_message);
+                }
+
+                // The delay request is the only message that is sent
+                // from PTP clock implementation, if others are added
+                // additional match arms should be added.
+                match ptp_message.message_type {
+                    PtpMessageType::DELAY_REQ => {
+                        if args.verbose {
+                            trace!("Ignoring our own PTP message");
+                        }
+                        continue 'next_packet;
+                    }
+                    _ => (),
+                }
+
+                if let PtpMessagePayload::DelayResp {
+                    requesting_port_identity: PtpClockIdentity { clock_identity, .. },
+                    ..
+                } = ptp_message.message_payload
+                {
+                    if clock_identity != u64::from_be_bytes(clock_id) {
+                        if args.verbose {
+                            trace!("Ignoring PTP DELAY_RESP message for a different clock");
+                        }
+                        continue 'next_packet;
+                    }
+                }
+
+                {
+                    let mut buf = &mut stdinout_buffer[..(read + 4 + 8)];
+                    buf.write_u16be(read as u16 + 1 + 8)
+                        .expect("Too small stdout buffer");
+                    buf.write_u8(if type_ == io::SocketType::EventSocket {
+                        MSG_TYPE_EVENT
+                    } else {
+                        MSG_TYPE_GENERAL
+                    })
+                    .expect("Too small stdout buffer");
+                    buf.write_u8(idx as u8).expect("Too small stdout buffer");
+                    buf.write_u64be(recv_time).expect("Too small stdout buffer");
+                    buf.write_all(&socket_buffer[..read])
+                        .expect("Too small stdout buffer");
+                    assert!(buf.is_empty(), "Too big stdout buffer",);
+                }
+
+                let buf = &stdinout_buffer[..(read + 4 + 8)];
+                poll_res
+                    .stdout()
+                    .write_all(buf)
+                    .context("Failed writing to stdout")?;
+            }
+        }
+
+        // After handling the sockets check if a packet is available on stdin, read it and forward
+        // it to the corresponding socket.
+        if let Some(ref mut stdin) = poll_res.stdin() {
+            stdin
+                .read_exact(&mut stdinout_buffer[0..3])
+                .context("Failed reading packet header from stdin")?;
+
+            let size = u16::from_be_bytes([stdinout_buffer[0], stdinout_buffer[1]]);
+            if size as usize > stdinout_buffer.len() {
+                bail!("Invalid packet size on stdin {}", size);
+            }
+            let type_ = stdinout_buffer[2];
+
+            stdin
+                .read_exact(&mut stdinout_buffer[0..size as usize])
+                .context("Failed reading packet body from stdin")?;
+
+            if type_ != MSG_TYPE_EVENT && type_ != MSG_TYPE_GENERAL {
+                warn!("Unexpected stdin message type {}", type_);
+                continue;
+            }
+
+            if size < 1 + 8 + 34 {
+                bail!("Invalid packet body size");
+            }
+
+            let buf = &mut &stdinout_buffer[..(size as usize)];
+
+            let idx = buf.read_u8().expect("Too small stdin buffer");
+            if idx as usize >= ifaces.len() {
+                warn!("Unexpected stdin message interface index {}", idx);
+                continue;
+            }
+
+            if args.verbose {
+                trace!(
+                    "Received {} bytes for {} socket for interface {} from stdin",
+                    size,
+                    if type_ == MSG_TYPE_EVENT {
+                        "event"
+                    } else {
+                        "general"
+                    },
+                    idx,
+                );
+            }
+
+            let main_send_time = buf.read_u64be().expect("Too small stdin buffer");
+
+            // We require that the main process only ever sends valid PTP messages with the clock
+            // ID assigned by this process.
+            let ptp_message =
+                parse::PtpMessage::parse(buf).context("Parsing PTP message from main process")?;
+            if ptp_message.source_port_identity.clock_identity != u64::from_be_bytes(clock_id) {
+                bail!("PTP message with unexpected clock identity on stdin");
+            }
+
+            if args.verbose {
+                trace!("Received PTP message from stdin {:#?}", ptp_message);
+            }
+
+            let send_time = clock::time();
+            match type_ {
+                MSG_TYPE_EVENT => poll_res
+                    .event_socket(idx as usize)
+                    .send_to(buf, (PTP_MULTICAST_ADDR, PTP_EVENT_PORT)),
+                MSG_TYPE_GENERAL => poll_res
+                    .general_socket(idx as usize)
+                    .send_to(buf, (PTP_MULTICAST_ADDR, PTP_GENERAL_PORT)),
+                _ => unreachable!(),
+            }
+            .with_context(|| {
+                format!(
+                    "Failed sending to {} socket",
+                    if type_ == MSG_TYPE_EVENT {
+                        "event"
+                    } else {
+                        "general"
+                    }
+                )
+            })?;
+
+            if args.verbose {
+                trace!(
+                    "Sending SEND_TIME_ACK for message type {}, domain number {}, seqnum {} received at {} at {}",
+                    u8::from(ptp_message.message_type),
+                    ptp_message.domain_number,
+                    ptp_message.sequence_id,
+                    main_send_time,
+                    send_time,
+                );
+            }
+
+            {
+                let mut buf = &mut stdinout_buffer[..(3 + 12)];
+                buf.write_u16be(12).expect("Too small stdout buffer");
+                buf.write_u8(MSG_TYPE_SEND_TIME_ACK)
+                    .expect("Too small stdout buffer");
+                buf.write_u64be(send_time).expect("Too small stdout buffer");
+                buf.write_u8(ptp_message.message_type.into())
+                    .expect("Too small stdout buffer");
+                buf.write_u8(ptp_message.domain_number)
+                    .expect("Too small stdout buffer");
+                buf.write_u16be(ptp_message.sequence_id)
+                    .expect("Too small stdout buffer");
+                assert!(buf.is_empty(), "Too big stdout buffer",);
+            }
+
+            let buf = &stdinout_buffer[..(3 + 12)];
+            poll_res
+                .stdout()
+                .write_all(buf)
+                .context("Failed writing to stdout")?;
+        }
+    }
+}
+
+/// Custom panic hook so we can print them to stderr in a format the main process understands
+fn panic_hook(info: &std::panic::PanicInfo) {
+    error!("Panicked. {}", info);
+}
+
+fn main() {
+    std::panic::set_hook(Box::new(panic_hook));
+
+    if let Err(err) = run() {
+        error!("Exited with error: {:?}", err);
+    }
+}
diff --git a/libs/gst/helpers/ptp/meson.build b/libs/gst/helpers/ptp/meson.build
new file mode 100644
index 0000000..97c258c
--- /dev/null
+++ b/libs/gst/helpers/ptp/meson.build
@@ -0,0 +1,125 @@
+# Check PTP support
+ptp_helper_option = get_option('ptp-helper')
+
+if ptp_helper_option.disabled()
+  subdir_done()
+endif
+
+if host_system not in ['linux', 'freebsd', 'openbsd', 'netbsd', 'dragonfly', 'darwin', 'sunos', 'solaris', 'illumos', 'windows', 'gnu']
+  if ptp_helper_option.enabled()
+    error('PTP not supported on this OS')
+  endif
+  subdir_done()
+endif
+
+have_rust = add_languages('rust', native : false, required : false)
+if not have_rust
+  if ptp_helper_option.enabled()
+    error('PTP not supported without Rust compiler')
+  endif
+  subdir_done()
+endif
+
+rustc = meson.get_compiler('rust')
+
+if rustc.get_id() not in ['rustc', 'clippy-driver rustc']
+  warning('PTP support is only tested with rustc, found different compiler @0@ @1@'.format(rustc.get_id(), rustc.version()))
+endif
+
+# We currently need at least Rust 1.48 on all platforms but Windows.
+# On Windows some 1.54 API is used that would otherwise complicate things
+# unncecessarily.
+rust_req = '1.48'
+if host_system == 'windows'
+  rust_req = '1.54'
+endif
+
+if rustc.get_id() in ['rustc', 'clippy-driver rustc'] and not rustc.version().version_compare('>=' + rust_req)
+  if ptp_helper_option.enabled()
+    error('PTP support requires at least Rust @0@ on this platform, found @1@'.format(rust_req, rustc.version()))
+  endif
+  subdir_done()
+endif
+
+cdata.set('HAVE_PTP', 1, description : 'PTP support available')
+
+ptp_helper_conf_data = configuration_data()
+rust_args = []
+
+setcap_prog = find_program('setcap', '/usr/sbin/setcap', '/sbin/setcap', required : false)
+cap_dep = dependency('libcap', required: false)
+
+# user/group to change to in gst-ptp-helper
+ptp_helper_setuid_user = get_option('ptp-helper-setuid-user')
+if ptp_helper_setuid_user != ''
+  ptp_helper_conf_data.set('PTP_HELPER_SETUID_USER', 'Some("@0@")'.format(ptp_helper_setuid_user))
+else
+  ptp_helper_conf_data.set('PTP_HELPER_SETUID_USER', 'None')
+endif
+ptp_helper_setuid_group = get_option('ptp-helper-setuid-group')
+if ptp_helper_setuid_group != ''
+  ptp_helper_conf_data.set('PTP_HELPER_SETUID_GROUP', 'Some("@0@")'.format(ptp_helper_setuid_group))
+else
+  ptp_helper_conf_data.set('PTP_HELPER_SETUID_GROUP', 'None')
+endif
+
+# how to install gst-ptp-helper
+with_ptp_helper_permissions = get_option('ptp-helper-permissions')
+if with_ptp_helper_permissions == 'auto'
+  if setcap_prog.found() and cap_dep.found()
+    with_ptp_helper_permissions = 'capabilities'
+  elif host_system == 'windows'
+    with_ptp_helper_permissions = 'none'
+  else
+    with_ptp_helper_permissions = 'setuid-root'
+  endif
+endif
+message('How to install gst-ptp-helper: ' + with_ptp_helper_permissions)
+
+if with_ptp_helper_permissions == 'none'
+  rust_args += ['--cfg', 'ptp_helper_permissions="none"']
+  # nothing to do
+elif with_ptp_helper_permissions == 'setuid-root'
+  rust_args += ['--cfg', 'ptp_helper_permissions="setuid-root"']
+elif with_ptp_helper_permissions == 'capabilities'
+  if not setcap_prog.found()
+    error('capabilities-based ptp-helper-permissions requested, but could not find setcap tool.')
+  elif not cap_dep.found()
+    error('capabilities-based ptp-helper-permissions requested, but could not find libcap.')
+  endif
+  rust_args += ['--cfg', 'ptp_helper_permissions="setcap"']
+else
+  error('Unexpected ptp helper permissions value: ' + with_ptp_helper_permissions)
+endif
+
+conf_lib_rs = configure_file(input : 'conf_lib.rs.in',
+                             output : 'conf_lib.rs',
+                             configuration: ptp_helper_conf_data)
+
+conf = static_library('gst_ptp_helper_conf', conf_lib_rs,
+  override_options : ['rust_std=2018'],
+  rust_crate_type : 'rlib')
+
+exe = executable('gst-ptp-helper', 'main.rs',
+  override_options : ['rust_std=2018'],
+  rust_args : ['-Cpanic=abort', rust_args],
+  dependencies : [cap_dep],
+  link_with : conf,
+  install_dir : helpers_install_dir,
+  install : true)
+
+exe_test = executable('gst-ptp-helper-test', 'main.rs',
+  override_options : ['rust_std=2018'],
+  rust_args : ['--test', rust_args],
+  dependencies : [cap_dep],
+  link_with : conf)
+
+test('gst-ptp-helper-test', exe_test, protocol : 'rust')
+
+if host_system != 'windows'
+  meson.add_install_script('ptp_helper_post_install.sh',
+      helpers_install_dir, with_ptp_helper_permissions,
+      setcap_prog.found() ? setcap_prog.full_path() : '')
+endif
+
+meson.add_devenv({'GST_PTP_HELPER': exe.full_path()})
diff --git a/libs/gst/helpers/ptp/net.rs b/libs/gst/helpers/ptp/net.rs
new file mode 100644
index 0000000..258abce
--- /dev/null
+++ b/libs/gst/helpers/ptp/net.rs
@@ -0,0 +1,1176 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+use std::net::Ipv4Addr;
+
+use crate::{bail, error::Error};
+
+#[derive(Debug)]
+/// Network interface information.
+pub struct InterfaceInfo {
+    /// Name of the interface
+    pub name: String,
+    /// Other name of the interface, if any
+    pub other_name: Option<String>,
+    /// Interface index
+    pub index: usize,
+    /// Unicast IPv4 address of the interface
+    pub ip_addr: Ipv4Addr,
+    /// Physical MAC address of the interface, if any
+    pub hw_addr: Option<[u8; 6]>,
+}
+
+#[cfg(unix)]
+mod imp {
+    use super::*;
+
+    use std::{ffi::CStr, io, marker, mem, net::UdpSocket, os::unix::io::AsRawFd, ptr};
+
+    use crate::{error::Context, ffi::unix::*};
+
+    /// Returns information for all non-loopback, multicast-capable network interfaces.
+    pub fn query_interfaces() -> Result<Vec<InterfaceInfo>, Error> {
+        struct Ifaddrs(*mut ifaddrs);
+
+        impl Ifaddrs {
+            fn new() -> io::Result<Self> {
+                loop {
+                    // SAFETY: Requires passing valid storage for the returned ifaddrs pointer and
+                    // returns -1 on errors. It might return NULL if there are no network interfaces.
+                    //
+                    // On error it might return EINTR in which case we should simply try again.
+                    unsafe {
+                        let mut ifaddrs = ptr::null_mut();
+                        if getifaddrs(&mut ifaddrs) == -1 {
+                            let err = io::Error::last_os_error();
+                            if err.kind() == std::io::ErrorKind::Interrupted {
+                                continue;
+                            }
+
+                            return Err(err);
+                        } else {
+                            return Ok(Self(ifaddrs));
+                        }
+                    }
+                }
+            }
+
+            fn iter(&self) -> IfaddrsIter {
+                IfaddrsIter {
+                    ptr: ptr::NonNull::new(self.0),
+                    phantom: marker::PhantomData,
+                }
+            }
+        }
+
+        impl Drop for Ifaddrs {
+            fn drop(&mut self) {
+                // SAFETY: The pointer is a valid ifaddrs pointer by construction and dropped only
+                // once, so freeing it here is OK. It might be NULL so check for that first.
+                unsafe {
+                    if !self.0.is_null() {
+                        freeifaddrs(self.0);
+                    }
+                }
+            }
+        }
+
+        struct IfaddrsIter<'a> {
+            ptr: Option<ptr::NonNull<ifaddrs>>,
+            phantom: marker::PhantomData<&'a Ifaddrs>,
+        }
+
+        impl<'a> Iterator for IfaddrsIter<'a> {
+            type Item = &'a ifaddrs;
+
+            fn next(&mut self) -> Option<Self::Item> {
+                match self.ptr {
+                    None => None,
+                    Some(ptr) => {
+                        // SAFETY: The pointer is a valid ifaddrs pointer by construction so
+                        // creating a reference to it is OK.
+                        let addr = unsafe { &*ptr.as_ptr() };
+                        self.ptr = ptr::NonNull::new(addr.ifa_next);
+                        Some(addr)
+                    }
+                }
+            }
+        }
+
+        let ifaddrs = Ifaddrs::new().context("Failed getting interface addresses")?;
+
+        let mut if_infos = Vec::<InterfaceInfo>::new();
+
+        for ifaddr in ifaddrs.iter() {
+            // SAFETY: ifa_name points to a NUL-terminated interface name string that is valid as
+            // long as its struct is
+            let name = unsafe { CStr::from_ptr(ifaddr.ifa_name) }.to_str().unwrap();
+
+            // Skip loopback interfaces, interfaces that are not up and interfaces that can't do
+            // multicast. These are all unusable for PTP purposes.
+            let flags = ifaddr.ifa_flags;
+            if flags & IFF_LOOPBACK != 0 {
+                debug!("Interface {} is loopback interface", name);
+                continue;
+            }
+            if flags & IFF_UP == 0 {
+                debug!("Interface {} is not up", name);
+                continue;
+            }
+            if flags & IFF_MULTICAST == 0 {
+                debug!("Interface {} does not support multicast", name);
+                continue;
+            }
+
+            // If the interface has no address then skip it. Only interfaces with IPv4 addresses
+            // are usable for PTP purposes.
+            if ifaddr.ifa_addr.is_null() {
+                debug!("Interface {} has no IPv4 address", name);
+                continue;
+            }
+
+            // Get the interface index from its name. If it has none then we can't use it to join
+            // the PTP multicast group reliable for this interface.
+            //
+            // SAFETY: Must be called with a valid, NUL-terminated string which is provided by
+            // ifa_name and will return the interface index or zero on error.
+            //
+            // On error it can return EINTR in which case we should try again.
+            let index = loop {
+                let index = unsafe { if_nametoindex(ifaddr.ifa_name) } as usize;
+                if index == 0 {
+                    let err = io::Error::last_os_error();
+                    if err.kind() == io::ErrorKind::Interrupted {
+                        continue;
+                    }
+                }
+                break index;
+            };
+            if index == 0 {
+                debug!("Interface {} has no valid interface index", name);
+                continue;
+            }
+
+            // Interfaces are listed multiple times here, once per address. We collect all IPv4 and
+            // MAC addresses for interfaces below.
+
+            // SAFETY: ifa_addr is a valid sockaddr pointer and was checked to be not NULL further
+            // above.
+            let sa_family = unsafe { (*ifaddr.ifa_addr).sa_family };
+
+            // If this interface has an IPv4 address then retrieve and store it here.
+            if sa_family == AF_INET as _ {
+                // SAFETY: If the address family is AF_INET then it is actually a valid sockaddr_in
+                // pointer and can be used as such.
+                let addr = unsafe { &*(ifaddr.ifa_addr as *const sockaddr_in) };
+                let ip_addr = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes());
+
+                debug!("Interface {} has IPv4 address {}", name, ip_addr);
+
+                if let Some(if_info) = if_infos.iter_mut().find(|info| info.name == name) {
+                    if if_info.ip_addr.is_broadcast() {
+                        if_info.ip_addr = ip_addr;
+                    }
+                } else {
+                    if_infos.push(InterfaceInfo {
+                        name: String::from(name),
+                        other_name: None,
+                        index,
+                        ip_addr,
+                        hw_addr: None,
+                    });
+                }
+            }
+
+            #[cfg(target_os = "linux")]
+            {
+                if sa_family == AF_PACKET as _ {
+                    // SAFETY: If the address family is AF_PACKET then it is actually a valid sockaddr_ll
+                    // pointer and can be used as such.
+                    let addr = unsafe { &*(ifaddr.ifa_addr as *const sockaddr_ll) };
+                    if addr.sll_halen == 6 {
+                        let mut hw_addr = [0u8; 6];
+                        hw_addr.copy_from_slice(&addr.sll_addr[0..6]);
+
+                        debug!("Interface {} has MAC address {:?}", name, hw_addr);
+
+                        if let Some(if_info) = if_infos.iter_mut().find(|info| info.name == name) {
+                            if if_info.hw_addr.is_none() {
+                                if_info.hw_addr = Some(hw_addr);
+                            }
+                        } else {
+                            if_infos.push(InterfaceInfo {
+                                name: String::from(name),
+                                other_name: None,
+                                index,
+                                ip_addr: Ipv4Addr::BROADCAST,
+                                hw_addr: Some(hw_addr),
+                            });
+                        }
+                    }
+                }
+            }
+            #[cfg(not(any(target_os = "linux", target_os = "hurd")))]
+            {
+                use std::slice;
+
+                if sa_family == AF_LINK as _ {
+                    // SAFETY: If the address family is AF_LINK then it is actually a valid sockaddr_dl
+                    // pointer and can be used as such.
+                    let addr = unsafe { &*(ifaddr.ifa_addr as *const sockaddr_dl) };
+                    if addr.sdl_nlen <= IF_NAMESIZE as u8 && addr.sdl_alen == 6 {
+                        let mut hw_addr = [0u8; 6];
+                        // SAFETY: There can be more than the given number of bytes stored and
+                        // this happens regularly on macOS at least. It is required that the
+                        // interface name is at most IF_NAMESIZE (checked just above).
+                        unsafe {
+                            let sdl_addr_ptr = addr.sdl_data.as_ptr() as *const u8;
+                            let sdl_addr =
+                                slice::from_raw_parts(sdl_addr_ptr.add(addr.sdl_nlen as usize), 6);
+                            hw_addr.copy_from_slice(sdl_addr);
+                        }
+
+                        debug!("Interface {} has MAC address {:?}", name, hw_addr);
+
+                        if let Some(if_info) = if_infos.iter_mut().find(|info| info.name == name) {
+                            if if_info.hw_addr.is_none() {
+                                if_info.hw_addr = Some(hw_addr);
+                            }
+                        } else {
+                            if_infos.push(InterfaceInfo {
+                                name: String::from(name),
+                                other_name: None,
+                                index,
+                                ip_addr: Ipv4Addr::BROADCAST,
+                                hw_addr: Some(hw_addr),
+                            });
+                        }
+                    }
+                }
+            }
+        }
+
+        if_infos.retain(|iface| !iface.ip_addr.is_broadcast());
+
+        Ok(if_infos)
+    }
+
+    /// Create an `UdpSocket` and bind it to the given address but set `SO_REUSEADDR` and/or
+    /// `SO_REUSEPORT` before doing so.
+    ///
+    /// `UdpSocket::bind()` does not allow setting custom options before binding.
+    pub fn create_udp_socket(
+        addr: &Ipv4Addr,
+        port: u16,
+        iface: Option<&InterfaceInfo>,
+    ) -> Result<UdpSocket, io::Error> {
+        use std::os::unix::io::FromRawFd;
+
+        /// Helper struct to keep a raw fd and close it on drop
+        struct Fd(i32);
+        impl Drop for Fd {
+            fn drop(&mut self) {
+                unsafe {
+                    // SAFETY: The integer is a valid fd by construction.
+                    let _ = close(self.0);
+                }
+            }
+        }
+
+        // SAFETY: Calling socket() is safe at any time and will simply fail if invalid parameters
+        // are passed.
+        let fd = unsafe {
+            #[cfg(any(
+                target_os = "linux",
+                target_os = "freebsd",
+                target_os = "openbsd",
+                target_os = "netbsd",
+                target_os = "dragonfly",
+                target_os = "solaris",
+                target_os = "illumos",
+                target_os = "hurd",
+            ))]
+            let ty = SOCK_DGRAM | SOCK_CLOEXEC;
+            #[cfg(target_os = "macos")]
+            let ty = SOCK_DGRAM;
+
+            let res = socket(AF_INET, ty, 0);
+            if res == -1 {
+                return Err(io::Error::last_os_error());
+            }
+            Fd(res)
+        };
+
+        // SAFETY: A valid socket fd is passed to ioctl() and setsockopt() and the parameters to
+        // setsockopt() are according to the type expected by SO_NOSIGPIPE.
+        #[cfg(target_os = "macos")]
+        unsafe {
+            let res = ioctl(fd.0, FIOCLEX);
+            if res == -1 {
+                return Err(io::Error::last_os_error());
+            }
+
+            let val = 1i32;
+            let res = setsockopt(
+                fd.0,
+                SOL_SOCKET,
+                SO_NOSIGPIPE,
+                &val as *const _ as *const _,
+                mem::size_of_val(&val) as _,
+            );
+            if res < 0 {
+                return Err(io::Error::last_os_error());
+            }
+        }
+
+        // SAFETY: A valid socket fd is passed here.
+        unsafe {
+            set_reuse(fd.0);
+            if let Some(iface) = iface {
+                bind_to_interface(fd.0, iface);
+            }
+        }
+
+        // SAFETY: A valid socket fd is passed together with a valid sockaddr_in and its size.
+        unsafe {
+            let addr = sockaddr_in {
+                sin_family: AF_INET as _,
+                sin_port: u16::to_be(port),
+                sin_addr: in_addr {
+                    s_addr: u32::from_ne_bytes(addr.octets()),
+                },
+                sin_zero: [0u8; 8],
+                #[cfg(any(
+                    target_os = "freebsd",
+                    target_os = "openbsd",
+                    target_os = "netbsd",
+                    target_os = "dragonfly",
+                    target_os = "macos",
+                    target_os = "hurd",
+                ))]
+                sin_len: mem::size_of::<sockaddr_in>() as _,
+            };
+            let res = bind(
+                fd.0,
+                &addr as *const _ as *const _,
+                mem::size_of_val(&addr) as _,
+            );
+            if res < 0 {
+                return Err(io::Error::last_os_error());
+            }
+        }
+
+        unsafe { Ok(UdpSocket::from_raw_fd(mem::ManuallyDrop::new(fd).0)) }
+    }
+
+    /// Join multicast address for a given interface.
+    pub fn join_multicast_v4(
+        socket: &UdpSocket,
+        addr: &Ipv4Addr,
+        iface: &InterfaceInfo,
+    ) -> Result<(), Error> {
+        #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "macos")))]
+        {
+            let mreqn = ip_mreqn {
+                imr_multiaddr: in_addr {
+                    s_addr: u32::from_ne_bytes(addr.octets()),
+                },
+                imr_address: in_addr {
+                    s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()),
+                },
+                imr_ifindex: iface.index as _,
+            };
+
+            // SAFETY: Requires a valid ip_mreq or ip_mreqn struct to be passed together
+            // with its size for checking which of the two it is. On errors a negative
+            // integer is returned.
+            unsafe {
+                if setsockopt(
+                    socket.as_raw_fd(),
+                    IPPROTO_IP,
+                    IP_ADD_MEMBERSHIP,
+                    &mreqn as *const _ as *const _,
+                    mem::size_of_val(&mreqn) as _,
+                ) < 0
+                {
+                    bail!(
+                        source: io::Error::last_os_error(),
+                        "Failed joining multicast group for interface {}",
+                        iface.name,
+                    );
+                }
+            }
+
+            #[cfg(not(any(target_os = "openbsd", target_os = "dragonfly", target_os = "netbsd")))]
+            {
+                let mreqn = ip_mreqn {
+                    imr_multiaddr: in_addr {
+                        s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()),
+                    },
+                    imr_address: in_addr {
+                        s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()),
+                    },
+                    imr_ifindex: iface.index as _,
+                };
+
+                // SAFETY: Requires a valid ip_mreq or ip_mreqn struct to be passed together
+                // with its size for checking which of the two it is. On errors a negative
+                // integer is returned.
+                unsafe {
+                    if setsockopt(
+                        socket.as_raw_fd(),
+                        IPPROTO_IP,
+                        IP_MULTICAST_IF,
+                        &mreqn as *const _ as *const _,
+                        mem::size_of_val(&mreqn) as _,
+                    ) < 0
+                    {
+                        bail!(
+                            source: io::Error::last_os_error(),
+                            "Failed joining multicast group for interface {}",
+                            iface.name,
+                        );
+                    }
+                }
+            }
+            #[cfg(any(target_os = "openbsd", target_os = "dragonfly"))]
+            {
+                let addr = in_addr {
+                    s_addr: u32::from_ne_bytes(iface.ip_addr.octets()),
+                };
+
+                // SAFETY: Requires a valid in_addr struct to be passed together with its size for
+                // checking which of the two it is. On errors a negative integer is returned.
+                unsafe {
+                    if setsockopt(
+                        socket.as_raw_fd(),
+                        IPPROTO_IP,
+                        IP_MULTICAST_IF,
+                        &addr as *const _ as *const _,
+                        mem::size_of_val(&addr) as _,
+                    ) < 0
+                    {
+                        bail!(
+                            source: io::Error::last_os_error(),
+                            "Failed joining multicast group for interface {}",
+                            iface.name,
+                        );
+                    }
+                }
+            }
+            #[cfg(target_os = "netbsd")]
+            {
+                let idx = (iface.index as u32).to_be();
+
+                // SAFETY: Requires a valid in_addr struct or interface index in network byte order
+                // to be passed together with its size for checking which of the two it is. On
+                // errors a negative integer is returned.
+                unsafe {
+                    if setsockopt(
+                        socket.as_raw_fd(),
+                        IPPROTO_IP,
+                        IP_MULTICAST_IF,
+                        &idx as *const _ as *const _,
+                        mem::size_of_val(&idx) as _,
+                    ) < 0
+                    {
+                        bail!(
+                            source: io::Error::last_os_error(),
+                            "Failed joining multicast group for interface {}",
+                            iface.name,
+                        );
+                    }
+                }
+            }
+
+            Ok(())
+        }
+
+        #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+        {
+            socket
+                .join_multicast_v4(addr, &iface.ip_addr)
+                .with_context(|| {
+                    format!(
+                        "Failed joining multicast group for interface {} at address {}",
+                        iface.name, iface.ip_addr
+                    )
+                })?;
+
+            let addr = in_addr {
+                s_addr: u32::from_ne_bytes(iface.ip_addr.octets()),
+            };
+
+            // SAFETY: Requires a valid in_addr struct to be passed together with its size for
+            // checking which of the two it is. On errors a negative integer is returned.
+            unsafe {
+                if setsockopt(
+                    socket.as_raw_fd(),
+                    IPPROTO_IP,
+                    IP_MULTICAST_IF,
+                    &addr as *const _ as *const _,
+                    mem::size_of_val(&addr) as _,
+                ) < 0
+                {
+                    bail!(
+                        source: io::Error::last_os_error(),
+                        "Failed setting multicast interface {}",
+                        iface.name,
+                    );
+                }
+            }
+
+            Ok(())
+        }
+
+        #[cfg(target_os = "macos")]
+        {
+            let mreq = ip_mreq {
+                imr_multiaddr: in_addr {
+                    s_addr: u32::from_ne_bytes(addr.octets()),
+                },
+                imr_address: in_addr {
+                    s_addr: u32::from_ne_bytes(iface.ip_addr.octets()),
+                },
+            };
+
+            let mreqn = ip_mreqn {
+                imr_multiaddr: in_addr {
+                    s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()),
+                },
+                imr_address: in_addr {
+                    s_addr: u32::from_ne_bytes(Ipv4Addr::UNSPECIFIED.octets()),
+                },
+                imr_ifindex: iface.index as _,
+            };
+
+            // SAFETY: Requires a valid ip_mreq struct to be passed together with its size for checking
+            // validity. On errors a negative integer is returned.
+            unsafe {
+                if setsockopt(
+                    socket.as_raw_fd(),
+                    IPPROTO_IP,
+                    IP_ADD_MEMBERSHIP,
+                    &mreq as *const _ as *const _,
+                    mem::size_of_val(&mreq) as _,
+                ) < 0
+                {
+                    bail!(
+                        source: io::Error::last_os_error(),
+                        "Failed joining multicast group for interface {}",
+                        iface.name,
+                    );
+                }
+            }
+
+            // SAFETY: Requires a valid ip_mreqn struct to be passed together
+            // with its size for checking which of the two it is. On errors a negative
+            // integer is returned.
+            unsafe {
+                if setsockopt(
+                    socket.as_raw_fd(),
+                    IPPROTO_IP,
+                    IP_MULTICAST_IF,
+                    &mreqn as *const _ as *const _,
+                    mem::size_of_val(&mreqn) as _,
+                ) < 0
+                {
+                    bail!(
+                        source: io::Error::last_os_error(),
+                        "Failed joining multicast group for interface {}",
+                        iface.name,
+                    );
+                }
+            }
+
+            Ok(())
+        }
+    }
+
+    /// Allow multiple sockets to bind to the same address / port.
+    ///
+    /// This is best-effort and might not actually do anything.
+    ///
+    /// SAFETY: Must be called with a valid socket fd.
+    unsafe fn set_reuse(socket: i32) {
+        // SAFETY: SO_REUSEADDR takes an i32 value that can be 0/false or 1/true and
+        // enables the given feature on the socket.
+        //
+        // We explicitly ignore errors here. If it works, good, if it doesn't then not much
+        // lost other than the ability to run multiple processes at once.
+        unsafe {
+            let v = 1i32;
+            let res = setsockopt(
+                socket,
+                SOL_SOCKET,
+                SO_REUSEADDR,
+                &v as *const _ as *const _,
+                mem::size_of_val(&v) as u32,
+            );
+            if res < 0 {
+                warn!("Failed to set SO_REUSEADDR on socket");
+            }
+        }
+
+        #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+        {
+            // SAFETY: SO_REUSEPORT takes an i32 value that can be 0/false or 1/true and
+            // enables the given feature on the socket.
+            //
+            // We explicitly ignore errors here. If it works, good, if it doesn't then not much
+            // lost other than the ability to run multiple processes at once.
+            unsafe {
+                let v = 1i32;
+                let res = setsockopt(
+                    socket,
+                    SOL_SOCKET,
+                    SO_REUSEPORT,
+                    &v as *const _ as *const _,
+                    mem::size_of_val(&v) as u32,
+                );
+
+                if res < 0 {
+                    warn!("Failed to set SO_REUSEPORT on socket");
+                }
+            }
+        }
+    }
+
+    /// Bind the socket to a specific interface.
+    ///
+    /// This is best-effort and might not actually do anything.
+    ///
+    /// SAFETY: Must be called with a valid socket fd.
+    #[cfg_attr(not(target_os = "linux"), allow(unused_variables))]
+    unsafe fn bind_to_interface(socket: i32, iface: &InterfaceInfo) {
+        // On Linux, go one step further and bind the socket completely to the socket if we
+        // can, i.e. have the relevant permissions.
+        #[cfg(target_os = "linux")]
+        {
+            // SAFETY: The socket passed in must be valid and the SO_BINDTOIFINDEX socket option
+            // takes an `i32` that represents the interface index as parameter.
+            let res = unsafe {
+                let v = iface.index as i32;
+                setsockopt(
+                    socket,
+                    SOL_SOCKET,
+                    SO_BINDTOIFINDEX,
+                    &v as *const _ as *const _,
+                    mem::size_of_val(&v) as u32,
+                )
+            };
+
+            if res < 0 {
+                warn!("Failed to set SO_BINDTOIFINDEX on socket, trying SO_BINDTODEVICE");
+
+                if iface.name.len() >= 16 {
+                    warn!(
+                        "Interface name '{}' too long for SO_BINDTODEVICE",
+                        iface.name
+                    );
+                } else {
+                    // SAFETY: The socket passed in must be valid and the SO_BINDTODEVICE socket option
+                    // takes a NUL-terminated byte array of up to 16 bytes as parameter.
+                    unsafe {
+                        let mut v = [0u8; 16];
+
+                        v[..iface.name.len()].copy_from_slice(iface.name.as_bytes());
+
+                        let res = setsockopt(
+                            socket,
+                            SOL_SOCKET,
+                            SO_BINDTODEVICE,
+                            &v as *const _ as *const _,
+                            (iface.name.len() + 1) as u32,
+                        );
+
+                        if res < 0 {
+                            warn!("Failed to set SO_BINDTODEVICE on socket");
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[cfg(windows)]
+mod imp {
+    use super::*;
+
+    use std::{
+        ffi::{CStr, OsString},
+        io, marker, mem,
+        net::{Ipv4Addr, SocketAddr, UdpSocket},
+        os::{
+            raw::*,
+            windows::{ffi::OsStringExt, io::AsRawSocket, raw::SOCKET},
+        },
+        ptr, slice,
+    };
+
+    use crate::{error::Context, ffi::windows::*};
+
+    /// Returns information for all non-loopback, multicast-capable network interfaces.
+    pub fn query_interfaces() -> Result<Vec<InterfaceInfo>, Error> {
+        struct AdapterAddresses {
+            addresses: ptr::NonNull<IP_ADAPTER_ADDRESSES_LH>,
+            heap: isize,
+        }
+
+        impl AdapterAddresses {
+            fn new() -> io::Result<Self> {
+                // SAFETY: Gets the process's default heap and is safe to be called at any time.
+                let heap = unsafe { GetProcessHeap() };
+
+                // SAFETY: GetAdaptersAddresses() requires allocated memory to be passed in.
+                // In the beginning 16kB are allocated via HeapAlloc() from the default process's
+                // heap (see above), then passed to GetAdaptersAddresses().
+                //
+                // If this returns ERROR_NOT_ENOUGH_MEMORY then this was not enough memory and the
+                // required amount is returned as out parameter. In that case we loop up to 10
+                // times, reallocate memory via HeapReAlloc() and try again.
+                //
+                // On other errors the memory is freed before returning via HeapFree(), or when 10
+                // iterations were reached.
+                unsafe {
+                    let mut alloc_len = 16_384;
+                    let mut tries = 0;
+                    let mut addresses: *mut IP_ADAPTER_ADDRESSES_LH = ptr::null_mut();
+
+                    loop {
+                        if tries > 10 {
+                            HeapFree(heap, 0, addresses as *mut _);
+                            return Err(io::Error::from(io::ErrorKind::OutOfMemory));
+                        }
+
+                        if addresses.is_null() {
+                            addresses = HeapAlloc(heap, 0, alloc_len as usize) as *mut _;
+                        } else {
+                            addresses =
+                                HeapReAlloc(heap, 0, addresses as *mut _, alloc_len as usize)
+                                    as *mut _;
+                        }
+                        if addresses.is_null() {
+                            return Err(io::Error::from(io::ErrorKind::OutOfMemory));
+                        }
+
+                        let res = GetAdaptersAddresses(
+                            AF_INET,
+                            GAA_FLAG_SKIP_ANYCAST
+                                | GAA_FLAG_SKIP_MULTICAST
+                                | GAA_FLAG_SKIP_DNS_SERVER,
+                            ptr::null_mut(),
+                            addresses,
+                            &mut alloc_len,
+                        );
+
+                        if res == 0 {
+                            return Ok(AdapterAddresses {
+                                heap,
+                                addresses: ptr::NonNull::new_unchecked(addresses),
+                            });
+                        } else if res == ERROR_NOT_ENOUGH_MEMORY {
+                            tries += 1;
+                            continue;
+                        } else {
+                            HeapFree(heap, 0, addresses as *mut _);
+                            return Err(io::Error::from_raw_os_error(res as i32));
+                        }
+                    }
+                }
+            }
+
+            fn iter(&self) -> AdapterAddressesIter {
+                AdapterAddressesIter {
+                    ptr: Some(self.addresses),
+                    phantom: marker::PhantomData,
+                }
+            }
+        }
+
+        impl Drop for AdapterAddresses {
+            fn drop(&mut self) {
+                // SAFETY: The pointer is a valid IP_ADAPTER_ADDRESSES_LH pointer by construction
+                // and dropped only once, so freeing it here is OK. It might be NULL so check for
+                // that first.
+                //
+                // Heap is the process's heap as set in the constructor above.
+                unsafe {
+                    HeapFree(self.heap, 0, self.addresses.as_ptr() as *mut _);
+                }
+            }
+        }
+
+        struct AdapterAddressesIter<'a> {
+            ptr: Option<ptr::NonNull<IP_ADAPTER_ADDRESSES_LH>>,
+            phantom: marker::PhantomData<&'a AdapterAddresses>,
+        }
+
+        impl<'a> Iterator for AdapterAddressesIter<'a> {
+            type Item = &'a IP_ADAPTER_ADDRESSES_LH;
+
+            fn next(&mut self) -> Option<Self::Item> {
+                match self.ptr {
+                    None => None,
+                    Some(ptr) => {
+                        // SAFETY: The pointer is a valid IP_ADAPTER_ADDRESSES_LH pointer by
+                        // construction so creating a reference to it is OK.
+                        let addr = unsafe { &*ptr.as_ptr() };
+                        self.ptr = ptr::NonNull::new(addr.next);
+                        Some(addr)
+                    }
+                }
+            }
+        }
+
+        struct UnicastAddressesIter<'a> {
+            ptr: Option<ptr::NonNull<IP_ADAPTER_UNICAST_ADDRESS_LH>>,
+            phantom: marker::PhantomData<&'a IP_ADAPTER_ADDRESSES_LH>,
+        }
+
+        impl<'a> UnicastAddressesIter<'a> {
+            fn new(addresses: &'a IP_ADAPTER_ADDRESSES_LH) -> Self {
+                Self {
+                    ptr: ptr::NonNull::new(addresses.firstunicastaddress),
+                    phantom: marker::PhantomData,
+                }
+            }
+        }
+
+        impl<'a> Iterator for UnicastAddressesIter<'a> {
+            type Item = &'a IP_ADAPTER_UNICAST_ADDRESS_LH;
+
+            fn next(&mut self) -> Option<Self::Item> {
+                match self.ptr {
+                    None => None,
+                    Some(ptr) => {
+                        let addr = unsafe { &*ptr.as_ptr() };
+                        self.ptr = ptr::NonNull::new(addr.next);
+                        Some(addr)
+                    }
+                }
+            }
+        }
+
+        let addresses = AdapterAddresses::new().context("Failed getting adapter addresses")?;
+        let mut if_infos = Vec::<InterfaceInfo>::new();
+        for address in addresses.iter() {
+            // SAFETY: adaptername points to a NUL-terminated ASCII name string that is valid
+            // as long as its struct is
+            let adaptername = unsafe { CStr::from_ptr(address.adaptername as *const c_char) }
+                .to_str()
+                .unwrap();
+
+            // Skip adapters that are receive-only, can't do multicast or don't have IPv4 support
+            // as they're not usable in a PTP context.
+            if address.flags & ADAPTER_FLAG_RECEIVE_ONLY != 0 {
+                debug!("Interface {} is receive-only interface", adaptername);
+                continue;
+            }
+            if address.flags & ADAPTER_FLAG_NO_MULTICAST != 0 {
+                debug!("Interface {} does not support multicast", adaptername);
+                continue;
+            }
+            if address.flags & ADAPTER_FLAG_IPV4_ENABLED == 0 {
+                debug!("Interface {} has no IPv4 address", adaptername);
+                continue;
+            }
+
+            // Skip adapters that are loopback or not up.
+            if address.iftype == IF_TYPE_SOFTWARE_LOOPBACK {
+                debug!("Interface {} is loopback interface", adaptername);
+                continue;
+            }
+            if address.operstatus != IF_OPER_STATUS_UP {
+                debug!("Interface {} is not up", adaptername);
+                continue;
+            }
+
+            // SAFETY: Both fields of the union are always valid
+            let index = unsafe { address.anonymous.anonymous.ifindex } as usize;
+            // Skip adapters that have no valid interface index as they can't be used to join the
+            // PTP multicast group reliably for this interface only.
+            if index == 0 {
+                debug!("Interface {} has no valid interface index", adaptername);
+                continue;
+            }
+
+            // SAFETY: friendlyname is a NUL-terminated UCS2/wide string or NULL.
+            let friendlyname = unsafe {
+                if !address.friendlyname.is_null() {
+                    let len = {
+                        let mut len = 0;
+                        while *address.friendlyname.add(len) != 0 {
+                            len += 1;
+                        }
+                        len
+                    };
+
+                    let f = slice::from_raw_parts(address.friendlyname, len);
+                    let f = OsString::from_wide(f);
+                    Some(String::from(f.to_str().unwrap()))
+                } else {
+                    None
+                }
+            };
+
+            let mut hw_addr = None;
+            if address.physicaladdresslength == 6 {
+                let mut addr = [0u8; 6];
+                addr.copy_from_slice(&address.physicaladdress[..6]);
+                hw_addr = Some(addr);
+            }
+
+            let ip_addr = UnicastAddressesIter::new(address).find_map(|addr| {
+                if addr.address.lpsocketaddr.is_null() {
+                    return None;
+                }
+
+                // SAFETY: lpsocketaddr is a valid, non-NULL socket address and its family
+                // field can be read to distinguish IPv4 and other socket addresses
+                if unsafe { (*addr.address.lpsocketaddr).sa_family } != AF_INET as u16 {
+                    return None;
+                }
+
+                Some(Ipv4Addr::from(
+                    // SAFETY: lpsocketaddr is a valid, non-NULL IPv4 socket address as checked
+                    // above and can be dereferenced as such.
+                    unsafe {
+                        (*addr.address.lpsocketaddr)
+                            .in_addr
+                            .S_un
+                            .S_addr
+                            .to_ne_bytes()
+                    },
+                ))
+            });
+
+            if let Some(ip_addr) = ip_addr {
+                if_infos.push(InterfaceInfo {
+                    name: String::from(adaptername),
+                    other_name: friendlyname,
+                    index,
+                    ip_addr,
+                    hw_addr,
+                });
+            } else {
+                debug!("Interface {} has no IPv4 address", adaptername);
+            }
+        }
+
+        Ok(if_infos)
+    }
+
+    /// Create an `UdpSocket` and bind it to the given address but set `SO_REUSEADDR` and/or
+    /// `SO_REUSEPORT` before doing so.
+    ///
+    /// `UdpSocket::bind()` does not allow setting custom options before binding.
+    pub fn create_udp_socket(
+        addr: &Ipv4Addr,
+        port: u16,
+        _iface: Option<&InterfaceInfo>,
+    ) -> Result<UdpSocket, io::Error> {
+        use std::os::windows::io::FromRawSocket;
+
+        // XXX: Make sure Rust std is calling WSAStartup()
+        let _ = UdpSocket::bind(SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)))?;
+
+        /// Helper struct to keep a raw socket and close it on drop
+        struct Socket(SOCKET);
+        impl Drop for Socket {
+            fn drop(&mut self) {
+                unsafe {
+                    // SAFETY: The socket is valid by construction.
+                    let _ = closesocket(self.0);
+                }
+            }
+        }
+
+        // SAFETY: Calling WSASocketW() is safe at any time and will simply fail if invalid parameters
+        // are passed or something else goes wrong.
+        let socket = unsafe {
+            let res = WSASocketW(
+                AF_INET as _,
+                SOCK_DGRAM as _,
+                0,
+                ptr::null_mut(),
+                0,
+                WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT,
+            );
+            if res == INVALID_SOCKET {
+                return Err(io::Error::from_raw_os_error(WSAGetLastError()));
+            }
+            Socket(res)
+        };
+
+        // SAFETY: A valid socket is passed here.
+        unsafe {
+            set_reuse(socket.0);
+        }
+
+        // SAFETY: A valid socket fd is passed together with a valid SOCKADDR and its size.
+        unsafe {
+            let addr = SOCKADDR {
+                sa_family: AF_INET as _,
+                sin_port: u16::to_be(port),
+                in_addr: IN_ADDR {
+                    S_un: IN_ADDR_0 {
+                        S_addr: u32::from_ne_bytes(addr.octets()),
+                    },
+                },
+                sin_zero: [0; 8],
+            };
+            let res = bind(socket.0, &addr, mem::size_of_val(&addr) as _);
+            if res < 0 {
+                return Err(io::Error::from_raw_os_error(WSAGetLastError()));
+            }
+        }
+
+        unsafe { Ok(UdpSocket::from_raw_socket(mem::ManuallyDrop::new(socket).0)) }
+    }
+
+    // Join multicast address for a given interface.
+    pub fn join_multicast_v4(
+        socket: &UdpSocket,
+        addr: &Ipv4Addr,
+        iface: &InterfaceInfo,
+    ) -> Result<(), Error> {
+        let mreq = IP_MREQ {
+            imr_multiaddr: IN_ADDR {
+                S_un: IN_ADDR_0 {
+                    S_addr: u32::from_ne_bytes(addr.octets()),
+                },
+            },
+            imr_address: IN_ADDR {
+                S_un: IN_ADDR_0 {
+                    S_addr: u32::from_ne_bytes(Ipv4Addr::new(0, 0, 0, iface.index as u8).octets()),
+                },
+            },
+        };
+
+        // SAFETY: Requires a valid ip_mreq struct to be passed together with its size for checking
+        // validity. On errors a negative integer is returned.
+        unsafe {
+            if setsockopt(
+                socket.as_raw_socket(),
+                IPPROTO_IP as i32,
+                IP_ADD_MEMBERSHIP as i32,
+                &mreq as *const _ as *const _,
+                mem::size_of_val(&mreq) as _,
+            ) < 0
+            {
+                bail!(
+                    source: io::Error::from_raw_os_error(WSAGetLastError()),
+                    "Failed joining multicast group for interface {}",
+                    iface.name,
+                );
+            }
+        }
+
+        let addr = IN_ADDR {
+            S_un: IN_ADDR_0 {
+                S_addr: u32::from_ne_bytes(Ipv4Addr::new(0, 0, 0, iface.index as u8).octets()),
+            },
+        };
+
+        // SAFETY: Requires a valid IN_ADDR struct to be passed together with its size for checking
+        // which of the two it is. On errors a negative integer is returned.
+        unsafe {
+            if setsockopt(
+                socket.as_raw_socket(),
+                IPPROTO_IP as i32,
+                IP_MULTICAST_IF as i32,
+                &addr as *const _ as *const _,
+                mem::size_of_val(&addr) as _,
+            ) < 0
+            {
+                bail!(
+                    source: io::Error::last_os_error(),
+                    "Failed joining multicast group for interface {}",
+                    iface.name,
+                );
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Allow multiple sockets to bind to the same address / port.
+    ///
+    /// This is best-effort and might not actually do anything.
+    ///
+    /// SAFETY: Must be called with a valid socket.
+    unsafe fn set_reuse(socket: SOCKET) {
+        // SAFETY: SO_REUSEADDR takes an i32 value that can be 0/false or 1/true and
+        // enables the given feature on the socket.
+        //
+        // We explicitly ignore errors here. If it works, good, if it doesn't then not much
+        // lost other than the ability to run multiple processes at once.
+        unsafe {
+            let v = 1i32;
+            let res = setsockopt(
+                socket,
+                SOL_SOCKET as i32,
+                SO_REUSEADDR as i32,
+                &v as *const _ as *const _,
+                mem::size_of_val(&v) as _,
+            );
+            if res < 0 {
+                warn!("Failed to set SO_REUSEADDR on socket");
+            }
+        }
+    }
+}
+
+pub use imp::*;
+
+#[cfg(test)]
+mod test {
+    #[test]
+    fn test_query_interfaces() {
+        let ifaces = super::query_interfaces().unwrap();
+        for iface in ifaces {
+            assert!(!iface.name.is_empty());
+            assert_ne!(iface.index, 0);
+            assert!(!iface.ip_addr.is_unspecified());
+        }
+    }
+
+    #[test]
+    fn test_create_socket_join_multicast() {
+        let ifaces = super::query_interfaces().unwrap();
+        let iface = if ifaces.is_empty() {
+            return;
+        } else {
+            &ifaces[0]
+        };
+
+        let socket = super::create_udp_socket(&std::net::Ipv4Addr::UNSPECIFIED, 0, None).unwrap();
+        super::join_multicast_v4(&socket, &std::net::Ipv4Addr::new(224, 0, 0, 1), iface).unwrap();
+
+        let local_addr = socket.local_addr().unwrap();
+
+        let socket2 = std::net::UdpSocket::bind(std::net::SocketAddr::from((
+            std::net::Ipv4Addr::UNSPECIFIED,
+            0,
+        )))
+        .unwrap();
+        socket2
+            .send_to(
+                &[1, 2, 3, 4],
+                std::net::SocketAddr::from((std::net::Ipv4Addr::LOCALHOST, local_addr.port())),
+            )
+            .unwrap();
+        let mut buf = [0u8; 4];
+        socket.recv(&mut buf).unwrap();
+        assert_eq!(buf, [1, 2, 3, 4]);
+    }
+}
diff --git a/libs/gst/helpers/ptp/parse.rs b/libs/gst/helpers/ptp/parse.rs
new file mode 100644
index 0000000..c59ae69
--- /dev/null
+++ b/libs/gst/helpers/ptp/parse.rs
@@ -0,0 +1,605 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+#![allow(unused)]
+
+use std::io;
+
+pub trait ReadBytesBEExt: io::Read {
+    #[inline]
+    fn read_u8(&mut self) -> io::Result<u8> {
+        let mut buf = [0u8; 1];
+        self.read_exact(&mut buf)?;
+        Ok(buf[0])
+    }
+
+    #[inline]
+    fn read_i8(&mut self) -> io::Result<i8> {
+        let mut buf = [0u8; 1];
+        self.read_exact(&mut buf)?;
+        Ok(buf[0] as i8)
+    }
+
+    #[inline]
+    fn read_u16be(&mut self) -> io::Result<u16> {
+        let mut buf = [0u8; 2];
+        self.read_exact(&mut buf)?;
+        Ok(u16::from_be_bytes(buf))
+    }
+
+    #[inline]
+    fn read_i16be(&mut self) -> io::Result<i16> {
+        let mut buf = [0u8; 2];
+        self.read_exact(&mut buf)?;
+        Ok(u16::from_be_bytes(buf) as i16)
+    }
+
+    #[inline]
+    fn read_u32be(&mut self) -> io::Result<u32> {
+        let mut buf = [0u8; 4];
+        self.read_exact(&mut buf)?;
+        Ok(u32::from_be_bytes(buf))
+    }
+
+    #[inline]
+    fn read_i32be(&mut self) -> io::Result<i32> {
+        let mut buf = [0u8; 4];
+        self.read_exact(&mut buf)?;
+        Ok(u32::from_be_bytes(buf) as i32)
+    }
+
+    #[inline]
+    fn read_u64be(&mut self) -> io::Result<u64> {
+        let mut buf = [0u8; 8];
+        self.read_exact(&mut buf)?;
+        Ok(u64::from_be_bytes(buf))
+    }
+
+    #[inline]
+    fn read_i64be(&mut self) -> io::Result<i64> {
+        let mut buf = [0u8; 8];
+        self.read_exact(&mut buf)?;
+        Ok(u64::from_be_bytes(buf) as i64)
+    }
+}
+
+impl<T> ReadBytesBEExt for T where T: io::Read {}
+
+pub trait WriteBytesBEExt: io::Write {
+    #[inline]
+    fn write_u8(&mut self, v: u8) -> io::Result<()> {
+        self.write_all(&[v])?;
+        Ok(())
+    }
+
+    #[inline]
+    fn write_i8(&mut self, v: i8) -> io::Result<()> {
+        self.write_all(&[v as u8])?;
+        Ok(())
+    }
+
+    #[inline]
+    fn write_u16be(&mut self, v: u16) -> io::Result<()> {
+        self.write_all(&v.to_be_bytes())?;
+        Ok(())
+    }
+
+    #[inline]
+    fn write_i16be(&mut self, v: i16) -> io::Result<()> {
+        self.write_all(&v.to_be_bytes())?;
+        Ok(())
+    }
+
+    #[inline]
+    fn write_u32be(&mut self, v: u32) -> io::Result<()> {
+        self.write_all(&v.to_be_bytes())?;
+        Ok(())
+    }
+
+    #[inline]
+    fn write_i32be(&mut self, v: i32) -> io::Result<()> {
+        self.write_all(&v.to_be_bytes())?;
+        Ok(())
+    }
+
+    #[inline]
+    fn write_u64be(&mut self, v: u64) -> io::Result<()> {
+        self.write_all(&v.to_be_bytes())?;
+        Ok(())
+    }
+
+    #[inline]
+    fn write_i64be(&mut self, v: i64) -> io::Result<()> {
+        self.write_all(&v.to_be_bytes())?;
+        Ok(())
+    }
+}
+
+impl<T> WriteBytesBEExt for T where T: io::Write {}
+
+#[derive(Debug)]
+pub struct PtpMessage {
+    pub transport_specific: u8,
+    pub message_type: PtpMessageType,
+    pub version_ptp: u8,
+    pub domain_number: u8,
+    pub flag_field: u16,
+    pub correction_field: i64,
+    pub source_port_identity: PtpClockIdentity,
+    pub sequence_id: u16,
+    pub control_field: u8,
+    pub log_message_interval: i8,
+    pub message_payload: PtpMessagePayload,
+}
+
+impl PtpMessage {
+    pub fn parse(mut data: &[u8]) -> io::Result<PtpMessage> {
+        if data.len() < 34 {
+            return Err(io::Error::new(
+                io::ErrorKind::InvalidInput,
+                format!("Too short PTP message {} < 34", data.len()),
+            ));
+        }
+
+        let b = data.read_u8()?;
+        let transport_specific = b >> 4;
+        let message_type = PtpMessageType(b & 0x0f);
+
+        let b = data.read_u8()?;
+        let version_ptp = b & 0x0f;
+        if version_ptp != 2 {
+            return Err(io::Error::new(
+                io::ErrorKind::InvalidData,
+                format!("Unsupported PTP version {}", version_ptp),
+            ));
+        }
+
+        let message_length = data.read_u16be()?;
+        if data.len() + 4 < message_length as usize {
+            return Err(io::Error::new(
+                io::ErrorKind::InvalidInput,
+                format!(
+                    "Too short PTP message {} < {}",
+                    data.len() + 4,
+                    message_length
+                ),
+            ));
+        }
+
+        let domain_number = data.read_u8()?;
+        data = &data[1..];
+
+        let flag_field = data.read_u16be()?;
+        let correction_field = data.read_i64be()?;
+        data = &data[4..];
+
+        let clock_identity = data.read_u64be()?;
+        let port_number = data.read_u16be()?;
+
+        let sequence_id = data.read_u16be()?;
+        let control_field = data.read_u8()?;
+        let log_message_interval = data.read_i8()?;
+
+        let message_payload = match message_type {
+            PtpMessageType::ANNOUNCE => {
+                if data.len() < 20 {
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        format!("Too short PTP SYNC message {} < 20", data.len(),),
+                    ));
+                }
+
+                let origin_timestamp = PtpTimestamp {
+                    seconds_field: ((data.read_u32be()? as u64) << 16)
+                        | (data.read_u16be()? as u64),
+                    nanoseconds_field: data.read_u32be()?,
+                };
+
+                let current_utc_offset = data.read_i16be()?;
+                data = &data[1..];
+
+                let grandmaster_priority_1 = data.read_u8()?;
+                let grandmaster_clock_quality = PtpClockQuality {
+                    clock_class: data.read_u8()?,
+                    clock_accuracy: data.read_u8()?,
+                    offset_scaled_log_variance: data.read_u16be()?,
+                };
+                let grandmaster_priority_2 = data.read_u8()?;
+
+                let grandmaster_identity = data.read_u64be()?;
+                let steps_removed = data.read_u16be()?;
+                let time_source = data.read_u8()?;
+
+                PtpMessagePayload::Announce {
+                    origin_timestamp,
+                    current_utc_offset,
+                    grandmaster_priority_1,
+                    grandmaster_clock_quality,
+                    grandmaster_priority_2,
+                    grandmaster_identity,
+                    steps_removed,
+                    time_source,
+                }
+            }
+            PtpMessageType::SYNC => {
+                if data.len() < 10 {
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        format!("Too short PTP SYNC message {} < 20", data.len(),),
+                    ));
+                }
+
+                let origin_timestamp = PtpTimestamp {
+                    seconds_field: ((data.read_u32be()? as u64) << 16)
+                        | (data.read_u16be()? as u64),
+                    nanoseconds_field: data.read_u32be()?,
+                };
+
+                PtpMessagePayload::Sync { origin_timestamp }
+            }
+            PtpMessageType::FOLLOW_UP => {
+                if data.len() < 10 {
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        format!("Too short PTP SYNC message {} < 20", data.len(),),
+                    ));
+                }
+
+                let precise_origin_timestamp = PtpTimestamp {
+                    seconds_field: ((data.read_u32be()? as u64) << 16)
+                        | (data.read_u16be()? as u64),
+                    nanoseconds_field: data.read_u32be()?,
+                };
+
+                PtpMessagePayload::FollowUp {
+                    precise_origin_timestamp,
+                }
+            }
+            PtpMessageType::DELAY_REQ => {
+                if data.len() < 10 {
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        format!("Too short PTP SYNC message {} < 20", data.len(),),
+                    ));
+                }
+
+                let origin_timestamp = PtpTimestamp {
+                    seconds_field: ((data.read_u32be()? as u64) << 16)
+                        | (data.read_u16be()? as u64),
+                    nanoseconds_field: data.read_u32be()?,
+                };
+
+                PtpMessagePayload::DelayReq { origin_timestamp }
+            }
+            PtpMessageType::DELAY_RESP => {
+                if data.len() < 20 {
+                    return Err(io::Error::new(
+                        io::ErrorKind::InvalidInput,
+                        format!("Too short PTP SYNC message {} < 20", data.len(),),
+                    ));
+                }
+
+                let receive_timestamp = PtpTimestamp {
+                    seconds_field: ((data.read_u32be()? as u64) << 16)
+                        | (data.read_u16be()? as u64),
+                    nanoseconds_field: data.read_u32be()?,
+                };
+                let clock_identity = data.read_u64be()?;
+                let port_number = data.read_u16be()?;
+
+                PtpMessagePayload::DelayResp {
+                    receive_timestamp,
+                    requesting_port_identity: PtpClockIdentity {
+                        clock_identity,
+                        port_number,
+                    },
+                }
+            }
+            _ => PtpMessagePayload::Other(message_type.0),
+        };
+
+        Ok(PtpMessage {
+            transport_specific,
+            message_type,
+            version_ptp,
+            domain_number,
+            flag_field,
+            correction_field,
+            source_port_identity: PtpClockIdentity {
+                clock_identity,
+                port_number,
+            },
+            sequence_id,
+            control_field,
+            log_message_interval,
+            message_payload,
+        })
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct PtpMessageType(u8);
+
+impl PtpMessageType {
+    pub const SYNC: PtpMessageType = PtpMessageType(0x0);
+    pub const DELAY_REQ: PtpMessageType = PtpMessageType(0x1);
+    pub const P_DELAY_REQ: PtpMessageType = PtpMessageType(0x2);
+    pub const P_DELAY_RESP: PtpMessageType = PtpMessageType(0x3);
+    pub const FOLLOW_UP: PtpMessageType = PtpMessageType(0x8);
+    pub const DELAY_RESP: PtpMessageType = PtpMessageType(0x9);
+    pub const P_DELAY_RESP_FOLLOW_UP: PtpMessageType = PtpMessageType(0xA);
+    pub const ANNOUNCE: PtpMessageType = PtpMessageType(0xB);
+    pub const SIGNALING: PtpMessageType = PtpMessageType(0xC);
+    pub const MANAGEMENT: PtpMessageType = PtpMessageType(0xD);
+}
+
+impl From<u8> for PtpMessageType {
+    fn from(v: u8) -> PtpMessageType {
+        PtpMessageType(v)
+    }
+}
+
+impl From<PtpMessageType> for u8 {
+    fn from(v: PtpMessageType) -> u8 {
+        v.0
+    }
+}
+
+#[derive(Debug)]
+pub enum PtpMessagePayload {
+    Announce {
+        origin_timestamp: PtpTimestamp,
+        current_utc_offset: i16,
+        grandmaster_priority_1: u8,
+        grandmaster_clock_quality: PtpClockQuality,
+        grandmaster_priority_2: u8,
+        grandmaster_identity: u64,
+        steps_removed: u16,
+        time_source: u8,
+    },
+    Sync {
+        origin_timestamp: PtpTimestamp,
+    },
+    FollowUp {
+        precise_origin_timestamp: PtpTimestamp,
+    },
+    DelayReq {
+        origin_timestamp: PtpTimestamp,
+    },
+    DelayResp {
+        receive_timestamp: PtpTimestamp,
+        requesting_port_identity: PtpClockIdentity,
+    },
+    Other(u8),
+}
+
+impl PtpMessagePayload {
+    #[allow(unused)]
+    pub fn type_(&self) -> PtpMessageType {
+        match self {
+            PtpMessagePayload::Sync { .. } => PtpMessageType::SYNC,
+            PtpMessagePayload::Announce { .. } => PtpMessageType::ANNOUNCE,
+            PtpMessagePayload::FollowUp { .. } => PtpMessageType::FOLLOW_UP,
+            PtpMessagePayload::DelayReq { .. } => PtpMessageType::DELAY_REQ,
+            PtpMessagePayload::DelayResp { .. } => PtpMessageType::DELAY_RESP,
+            PtpMessagePayload::Other(v) => PtpMessageType(*v),
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct PtpClockIdentity {
+    pub clock_identity: u64,
+    pub port_number: u16,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct PtpTimestamp {
+    pub seconds_field: u64,
+    pub nanoseconds_field: u32,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct PtpClockQuality {
+    pub clock_class: u8,
+    pub clock_accuracy: u8,
+    pub offset_scaled_log_variance: u16,
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_parse_sync() {
+        let sync = [
+            0x00, 0x02, 0x00, 0x2c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x56, 0x80, 0xff, 0xfe, 0x05, 0x7e, 0x77,
+            0x00, 0x01, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x64, 0x6b, 0x39, 0x5b, 0x06, 0xee,
+            0x6e, 0xf3,
+        ];
+
+        let msg = PtpMessage::parse(&sync).unwrap();
+        assert_eq!(msg.transport_specific, 0);
+        assert_eq!(msg.message_type, PtpMessageType::SYNC);
+        assert_eq!(msg.version_ptp, 2);
+        assert_eq!(msg.domain_number, 0);
+        assert_eq!(msg.flag_field, 0x0200);
+        assert_eq!(msg.correction_field, 0);
+        assert_eq!(msg.source_port_identity.clock_identity, 1753730941874175607);
+        assert_eq!(msg.source_port_identity.port_number, 1);
+        assert_eq!(msg.sequence_id, 76);
+        assert_eq!(msg.control_field, 0x00);
+        assert_eq!(msg.log_message_interval, 0);
+
+        match msg.message_payload {
+            PtpMessagePayload::Sync { origin_timestamp } => {
+                assert_eq!(origin_timestamp.seconds_field, 1684748635);
+                assert_eq!(origin_timestamp.nanoseconds_field, 116289267);
+            }
+            _ => unreachable!(),
+        }
+    }
+
+    #[test]
+    fn test_parse_follow_up() {
+        let follow_up = [
+            0x08, 0x02, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x56, 0x80, 0xff, 0xfe, 0x05, 0x7e, 0x77,
+            0x00, 0x01, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x00, 0x64, 0x6b, 0x39, 0x5b, 0x06, 0xef,
+            0x0d, 0x58,
+        ];
+
+        let msg = PtpMessage::parse(&follow_up).unwrap();
+        assert_eq!(msg.transport_specific, 0);
+        assert_eq!(msg.message_type, PtpMessageType::FOLLOW_UP);
+        assert_eq!(msg.version_ptp, 2);
+        assert_eq!(msg.domain_number, 0);
+        assert_eq!(msg.flag_field, 0x0000);
+        assert_eq!(msg.correction_field, 0);
+        assert_eq!(msg.source_port_identity.clock_identity, 1753730941874175607);
+        assert_eq!(msg.source_port_identity.port_number, 1);
+        assert_eq!(msg.sequence_id, 76);
+        assert_eq!(msg.control_field, 0x02);
+        assert_eq!(msg.log_message_interval, 0);
+
+        match msg.message_payload {
+            PtpMessagePayload::FollowUp {
+                precise_origin_timestamp,
+            } => {
+                assert_eq!(precise_origin_timestamp.seconds_field, 1684748635);
+                assert_eq!(precise_origin_timestamp.nanoseconds_field, 116329816);
+            }
+            _ => unreachable!(),
+        }
+    }
+
+    #[test]
+    fn test_parse_announce() {
+        let announce = [
+            0x0b, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x56, 0x80, 0xff, 0xfe, 0x05, 0x7e, 0x77,
+            0x00, 0x01, 0x00, 0x25, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0d, 0xfe, 0xff, 0xff, 0x80, 0x18, 0x56, 0x80,
+            0xff, 0xfe, 0x05, 0x7e, 0x77, 0x00, 0x00, 0xa0,
+        ];
+
+        let msg = PtpMessage::parse(&announce).unwrap();
+        assert_eq!(msg.transport_specific, 0);
+        assert_eq!(msg.message_type, PtpMessageType::ANNOUNCE);
+        assert_eq!(msg.version_ptp, 2);
+        assert_eq!(msg.domain_number, 0);
+        assert_eq!(msg.flag_field, 0x0000);
+        assert_eq!(msg.correction_field, 0);
+        assert_eq!(msg.source_port_identity.clock_identity, 1753730941874175607);
+        assert_eq!(msg.source_port_identity.port_number, 1);
+        assert_eq!(msg.sequence_id, 37);
+        assert_eq!(msg.control_field, 0x05);
+        assert_eq!(msg.log_message_interval, 1);
+
+        match msg.message_payload {
+            PtpMessagePayload::Announce {
+                origin_timestamp,
+                current_utc_offset,
+                grandmaster_priority_1,
+                grandmaster_clock_quality,
+                grandmaster_priority_2,
+                grandmaster_identity,
+                steps_removed,
+                time_source,
+            } => {
+                assert_eq!(origin_timestamp.seconds_field, 0);
+                assert_eq!(origin_timestamp.nanoseconds_field, 0);
+                assert_eq!(current_utc_offset, 0);
+                assert_eq!(grandmaster_priority_1, 128);
+                assert_eq!(grandmaster_clock_quality.clock_class, 13);
+                assert_eq!(grandmaster_clock_quality.clock_accuracy, 254);
+                assert_eq!(grandmaster_clock_quality.offset_scaled_log_variance, 65535);
+                assert_eq!(grandmaster_priority_2, 128);
+                assert_eq!(grandmaster_identity, 1753730941874175607);
+                assert_eq!(steps_removed, 0);
+                assert_eq!(time_source, 160);
+            }
+            _ => unreachable!(),
+        }
+    }
+
+    #[test]
+    fn test_parse_delay_req() {
+        let delay_req = [
+            0x01, 0x02, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x5e, 0xd3, 0xff, 0xfe, 0xe5, 0x88, 0xd6,
+            0xbb, 0x60, 0x00, 0x01, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00,
+        ];
+
+        let msg = PtpMessage::parse(&delay_req).unwrap();
+        assert_eq!(msg.transport_specific, 0);
+        assert_eq!(msg.message_type, PtpMessageType::DELAY_REQ);
+        assert_eq!(msg.version_ptp, 2);
+        assert_eq!(msg.domain_number, 0);
+        assert_eq!(msg.flag_field, 0x0000);
+        assert_eq!(msg.correction_field, 0);
+        assert_eq!(
+            msg.source_port_identity.clock_identity,
+            15591132056449812694,
+        );
+        assert_eq!(msg.source_port_identity.port_number, 47968);
+        assert_eq!(msg.sequence_id, 1);
+        assert_eq!(msg.control_field, 0x01);
+        assert_eq!(msg.log_message_interval, 0x7F);
+
+        match msg.message_payload {
+            PtpMessagePayload::DelayReq { origin_timestamp } => {
+                assert_eq!(origin_timestamp.seconds_field, 0);
+                assert_eq!(origin_timestamp.nanoseconds_field, 0);
+            }
+            _ => unreachable!(),
+        }
+    }
+    #[test]
+    fn test_parse_delay_resp() {
+        let delay_resp = [
+            0x09, 0x02, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x56, 0x80, 0xff, 0xfe, 0x05, 0x7e, 0x77,
+            0x00, 0x01, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x64, 0x6b, 0x39, 0x5a, 0x07, 0x9f,
+            0x83, 0x65, 0xd8, 0x5e, 0xd3, 0xff, 0xfe, 0xe5, 0x88, 0xd6, 0xbb, 0x60,
+        ];
+
+        let msg = PtpMessage::parse(&delay_resp).unwrap();
+        assert_eq!(msg.transport_specific, 0);
+        assert_eq!(msg.message_type, PtpMessageType::DELAY_RESP);
+        assert_eq!(msg.version_ptp, 2);
+        assert_eq!(msg.domain_number, 0);
+        assert_eq!(msg.flag_field, 0x0000);
+        assert_eq!(msg.correction_field, 0);
+        assert_eq!(msg.source_port_identity.clock_identity, 1753730941874175607,);
+        assert_eq!(msg.source_port_identity.port_number, 1);
+        assert_eq!(msg.sequence_id, 1);
+        assert_eq!(msg.control_field, 0x03);
+        assert_eq!(msg.log_message_interval, 0);
+
+        match msg.message_payload {
+            PtpMessagePayload::DelayResp {
+                receive_timestamp,
+                requesting_port_identity,
+            } => {
+                assert_eq!(receive_timestamp.seconds_field, 1684748634);
+                assert_eq!(receive_timestamp.nanoseconds_field, 127894373,);
+                assert_eq!(
+                    requesting_port_identity.clock_identity,
+                    15591132056449812694
+                );
+                assert_eq!(requesting_port_identity.port_number, 47968);
+            }
+            _ => unreachable!(),
+        }
+    }
+}
diff --git a/libs/gst/helpers/ptp/privileges.rs b/libs/gst/helpers/ptp/privileges.rs
new file mode 100644
index 0000000..7ab5677
--- /dev/null
+++ b/libs/gst/helpers/ptp/privileges.rs
@@ -0,0 +1,245 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+use crate::error::Error;
+
+#[cfg(ptp_helper_permissions = "setcap")]
+mod setcap {
+    use super::*;
+
+    use crate::{error::Context, ffi::unix::setcaps::*};
+    use std::io;
+
+    struct Cap(cap_t);
+
+    impl Drop for Cap {
+        fn drop(&mut self) {
+            // SAFETY: The capabilities are valid by construction and are only dropped
+            // once here.
+            unsafe {
+                let _ = cap_free(self.0);
+            }
+        }
+    }
+
+    impl Cap {
+        /// Get the current process' capabilities.
+        fn get_proc() -> io::Result<Self> {
+            //  SAFETY: Get the current capabilities of the process. This returns NULL on error or
+            //  otherwise newly allocated capabilities that have to be freed again in the end. For
+            //  that purpose we wrap them in the Cap struct.
+            unsafe {
+                let c = cap_get_proc();
+                if c.is_null() {
+                    return Err(io::Error::last_os_error());
+                }
+
+                Ok(Cap(c))
+            }
+        }
+
+        /// Clear all capabilities.
+        fn clear(&mut self) -> io::Result<()> {
+            // SAFETY: Clearing all current capabilities. This requires a valid capabilities
+            // pointer, which we have at this point by construction.
+            unsafe {
+                if cap_clear(self.0) != 0 {
+                    return Err(io::Error::last_os_error());
+                }
+            }
+
+            Ok(())
+        }
+
+        /// Set current process' capabilities.
+        fn set_proc(&self) -> io::Result<()> {
+            // SAFETY: Setting the current process's capabilities, which is only affecting the
+            // current thread unfortunately. At this point, no other threads were started yet so
+            // this is not a problem. Also the capabilities pointer is still valid by construction.
+            unsafe {
+                if cap_set_proc(self.0) != 0 {
+                    return Err(io::Error::last_os_error());
+                }
+            }
+            Ok(())
+        }
+    }
+
+    /// Drop all current capabilities of the process.
+    pub fn drop() -> Result<(), Error> {
+        let mut c = Cap::get_proc().context("Failed to get current process capabilities")?;
+        c.clear().context("Failed to clear capabilities")?;
+        c.set_proc()
+            .context("Failed to set current process capabilities")?;
+
+        Ok(())
+    }
+
+    #[cfg(test)]
+    mod test {
+        #[test]
+        fn test_get_set_same_and_clear_cap() {
+            let mut c = super::Cap::get_proc().unwrap();
+            // Setting the same capabilities should always succeed
+            c.set_proc().unwrap();
+            c.clear().unwrap();
+        }
+    }
+}
+
+#[cfg(ptp_helper_permissions = "setuid-root")]
+mod setuid_root {
+    use super::*;
+
+    use crate::{bail, error::Context, ffi::unix::setuid_root::*};
+    use std::{ffi::CString, io};
+
+    /// Retrieve UID and GID for the given username.
+    fn get_uid_gid_for_user(name: &str) -> io::Result<(uid_t, gid_t)> {
+        let name_cstr = CString::new(name).unwrap();
+
+        loop {
+            // SAFETY: getpwnam() requires a NUL-terminated user name string and
+            // returns either the user information in static storage, or NULL on error.
+            // In case of EINTR, getting the user information can be retried.
+            //
+            // The user information is stored in static storage so might change if something
+            // else calls related functions. As this is the only thread up to this point and we
+            // just extract two integers from it there is no such possibility.
+            unsafe {
+                let pw = getpwnam(name_cstr.as_ptr());
+                if pw.is_null() {
+                    let err = io::Error::last_os_error();
+                    if err.kind() == io::ErrorKind::Interrupted {
+                        continue;
+                    }
+                    if err.raw_os_error() == Some(0) {
+                        return Err(io::Error::from(io::ErrorKind::NotFound));
+                    }
+
+                    return Err(err);
+                }
+                return Ok(((*pw).pw_uid, (*pw).pw_gid));
+            }
+        }
+    }
+
+    /// Retrieve GID for the given group name.
+    fn get_gid_for_group(name: &str) -> io::Result<gid_t> {
+        let name_cstr = CString::new(name).unwrap();
+        loop {
+            // SAFETY: getgrnam() requires a NUL-terminated group name string and
+            // returns either the group information in static storage, or NULL on error.
+            // In case of EINTR, getting the group information can be retried.
+            //
+            // The user information is stored in static storage so might change if something
+            // else calls related functions. As this is the only thread up to this point and we
+            // just extract two integers from it there is no such possibility.
+            unsafe {
+                let grp = getgrnam(name_cstr.as_ptr());
+                if grp.is_null() {
+                    let err = io::Error::last_os_error();
+                    if err.kind() == io::ErrorKind::Interrupted {
+                        continue;
+                    }
+                    if err.raw_os_error() == Some(0) {
+                        return Err(io::Error::from(io::ErrorKind::NotFound));
+                    }
+
+                    return Err(err);
+                }
+
+                return Ok((*grp).gr_gid);
+            }
+        }
+    }
+
+    #[cfg(test)]
+    mod test {
+        #[test]
+        fn test_get_uid_gid_for_user() {
+            match super::get_uid_gid_for_user("root") {
+                Ok(_) => (),
+                Err(err) if err.kind() != std::io::ErrorKind::NotFound => {
+                    panic!("{}", err);
+                }
+                _ => (),
+            }
+        }
+
+        #[test]
+        fn test_get_gid_for_group() {
+            match super::get_gid_for_group("root") {
+                Ok(_) => (),
+                Err(err) if err.kind() != std::io::ErrorKind::NotFound => {
+                    panic!("{}", err);
+                }
+                _ => (),
+            }
+        }
+    }
+
+    /// Drop the process's UID/GID from root to the configured user/group or the user "nobody".
+    pub fn drop() -> Result<(), Error> {
+        let username = gst_ptp_helper_conf::PTP_HELPER_SETUID_USER.unwrap_or("nobody");
+
+        let (uid, gid) = get_uid_gid_for_user(username)
+            .with_context(|| format!("Failed to get user information for {}", username))?;
+        let gid = if let Some(group) = gst_ptp_helper_conf::PTP_HELPER_SETUID_GROUP {
+            get_gid_for_group(group)
+                .with_context(|| format!("Failed to get group information for {}", group))?
+        } else {
+            gid
+        };
+
+        // SAFETY: This function can be called at any time and never fails.
+        let old_gid = unsafe { getgid() };
+
+        // SAFETY: Changes the effective group id of the process and return zero on success.
+        unsafe {
+            if setgid(gid) != 0 {
+                bail!(
+                    source: io::Error::last_os_error(),
+                    "Failed to set group id {} for process",
+                    gid,
+                );
+            }
+        }
+
+        // SAFETY: Changes the effective user id of the process and return zero on success.
+        // On errors, try resetting to the old gid just to be sure.
+        unsafe {
+            if setuid(uid) != 0 {
+                let err = io::Error::last_os_error();
+                let _ = setgid(old_gid);
+                bail!(source: err, "Failed to set user id {} for process", uid);
+            }
+        }
+
+        Ok(())
+    }
+}
+
+/// Drop all additional permissions / capabilities the current process might have as they're not
+/// needed anymore.
+///
+/// This does nothing if no such mechanism is implemented / selected for the target platform.
+pub fn drop() -> Result<(), Error> {
+    #[cfg(ptp_helper_permissions = "setcap")]
+    {
+        setcap::drop()?;
+    }
+    #[cfg(ptp_helper_permissions = "setuid-root")]
+    {
+        setuid_root::drop()?;
+    }
+
+    Ok(())
+}
diff --git a/libs/gst/helpers/ptp_helper_post_install.sh b/libs/gst/helpers/ptp/ptp_helper_post_install.sh
similarity index 80%
rename from libs/gst/helpers/ptp_helper_post_install.sh
rename to libs/gst/helpers/ptp/ptp_helper_post_install.sh
index 4370acd..2ed427e 100755
--- a/libs/gst/helpers/ptp_helper_post_install.sh
+++ b/libs/gst/helpers/ptp/ptp_helper_post_install.sh
@@ -17,8 +17,8 @@ case "$with_ptp_helper_permissions" in
     ls -l "$ptp_helper"
     ;;
   capabilities)
-    echo "Calling $setcap cap_net_bind_service,cap_net_admin+ep $ptp_helper"
-    $setcap cap_net_bind_service,cap_net_admin+ep "$ptp_helper" || true
+    echo "Calling $setcap cap_sys_nice,cap_net_bind_service,cap_net_admin+ep $ptp_helper"
+    $setcap cap_sys_nice,cap_net_bind_service,cap_net_admin+ep "$ptp_helper" || true
     ;;
   none)
     echo "No perms/caps to set for $ptp_helper"
diff --git a/libs/gst/helpers/ptp/rand.rs b/libs/gst/helpers/ptp/rand.rs
new file mode 100644
index 0000000..7b811e9
--- /dev/null
+++ b/libs/gst/helpers/ptp/rand.rs
@@ -0,0 +1,246 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+#[cfg(unix)]
+mod unix {
+    use std::io;
+
+    #[cfg(target_os = "linux")]
+    /// Try using the getrandom syscall on Linux.
+    pub fn getrandom() -> io::Result<[u8; 8]> {
+        use std::io::Read;
+
+        use crate::ffi::unix::linux::*;
+
+        // Depends on us knowing the syscall number
+        if SYS_getrandom == 0 {
+            // FIXME: Use Unsupported once we can depend on 1.53
+            return Err(io::Error::from(io::ErrorKind::NotFound));
+        }
+
+        struct GetRandom;
+
+        impl Read for GetRandom {
+            fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+                // SAFETY: `getrandom` syscall fills up to the requested amount of bytes of
+                // the provided memory and returns the number of bytes or a negative value
+                // on errors.
+                unsafe {
+                    let res = syscall(SYS_getrandom, buf.as_mut_ptr(), buf.len(), 0u32);
+                    if res < 0 {
+                        Err(std::io::Error::last_os_error())
+                    } else {
+                        Ok(res as usize)
+                    }
+                }
+            }
+        }
+
+        let mut r = [0u8; 8];
+        GetRandom.read_exact(&mut r)?;
+
+        Ok(r)
+    }
+
+    /// Try reading random numbers from /dev/urandom.
+    pub fn dev_urandom() -> io::Result<[u8; 8]> {
+        use crate::ffi::unix::*;
+        use std::{io::Read, os::raw::c_int};
+
+        struct Fd(c_int);
+
+        impl Drop for Fd {
+            fn drop(&mut self) {
+                // SAFETY: The fd is valid by construction below and closed by this at
+                // most once.
+                unsafe {
+                    // Return value is intentionally ignored as there's nothing that
+                    // can be done on errors anyway.
+                    let _ = close(self.0);
+                }
+            }
+        }
+
+        impl Read for Fd {
+            fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+                // SAFETY: read() requires a valid fd and a mutable buffer with the given size.
+                // The fd is valid by construction as is the buffer.
+                //
+                // read() will return the number of bytes read or a negative value on errors.
+                let res = unsafe { read(self.0, buf.as_mut_ptr(), buf.len()) };
+                if res < 0 {
+                    Err(std::io::Error::last_os_error())
+                } else {
+                    Ok(res as usize)
+                }
+            }
+        }
+
+        let mut fd = loop {
+            // SAFETY: open() requires a NUL-terminated file path and will
+            // return an integer in any case. A negative value is an invalid fd
+            // and signals an error. On EINTR, opening can be retried.
+            let fd = unsafe { open(b"/dev/urandom\0".as_ptr(), O_RDONLY) };
+            if fd < 0 {
+                let err = std::io::Error::last_os_error();
+                if err.kind() == std::io::ErrorKind::Interrupted {
+                    continue;
+                }
+
+                return Err(err);
+            }
+
+            break Fd(fd);
+        };
+
+        let mut r = [0u8; 8];
+        fd.read_exact(&mut r)?;
+
+        Ok(r)
+    }
+
+    #[cfg(test)]
+    mod test {
+        #[test]
+        fn test_dev_urandom() {
+            match super::dev_urandom() {
+                Ok(n) => {
+                    assert_ne!(n, [0u8; 8]);
+                }
+                Err(err) if err.kind() != std::io::ErrorKind::NotFound => {
+                    panic!("{}", err);
+                }
+                _ => (),
+            }
+        }
+
+        #[cfg(target_os = "linux")]
+        #[test]
+        fn test_getrandom() {
+            match super::getrandom() {
+                Ok(n) => {
+                    assert_ne!(n, [0u8; 8]);
+                }
+                // FIXME: Use Unsupported once we can depend on 1.53
+                Err(err) if err.kind() != std::io::ErrorKind::NotFound => {
+                    panic!("{}", err);
+                }
+                _ => (),
+            }
+        }
+    }
+}
+
+#[cfg(windows)]
+mod windows {
+    use std::io;
+
+    /// Call BCryptGenRandom(), which is available since Windows Vista.
+    pub fn bcrypt_gen_random() -> io::Result<[u8; 8]> {
+        // SAFETY: BCryptGenRandom() fills the provided memory with the requested number of bytes
+        // and returns 0 on success. In that case, all memory was written and is initialized now.
+        unsafe {
+            use std::{mem, ptr};
+
+            use crate::ffi::windows::*;
+
+            let mut r = mem::MaybeUninit::<[u8; 8]>::uninit();
+            let res = BCryptGenRandom(
+                ptr::null_mut(),
+                r.as_mut_ptr() as *mut u8,
+                8,
+                BCRYPT_USE_SYSTEM_PREFERRED_RNG,
+            );
+            if res == 0 {
+                Ok(r.assume_init())
+            } else {
+                Err(io::Error::from_raw_os_error(res as i32))
+            }
+        }
+    }
+
+    #[cfg(test)]
+    mod test {
+        #[test]
+        fn test_bcrypt_gen_random() {
+            let n = super::bcrypt_gen_random().unwrap();
+            assert_ne!(n, [0u8; 8]);
+        }
+    }
+}
+
+/// As fallback use a combination of the process ID and the current system time.
+fn fallback_rand() -> [u8; 8] {
+    let now = std::time::SystemTime::now()
+        .duration_since(std::time::SystemTime::UNIX_EPOCH)
+        .unwrap()
+        .as_nanos()
+        .to_be_bytes();
+    let pid = std::process::id().to_be_bytes();
+    [
+        now[0] ^ now[15] ^ pid[0],
+        now[1] ^ now[14] ^ pid[1],
+        now[2] ^ now[13] ^ pid[2],
+        now[3] ^ now[12] ^ pid[3],
+        now[4] ^ now[11] ^ pid[0],
+        now[5] ^ now[10] ^ pid[1],
+        now[6] ^ now[9] ^ pid[2],
+        now[7] ^ now[8] ^ pid[3],
+    ]
+}
+
+/// Returns a random'ish 64 bit value.
+pub fn rand() -> [u8; 8] {
+    #[cfg(unix)]
+    {
+        // Try getrandom syscall or otherwise first on Linux
+        #[cfg(target_os = "linux")]
+        {
+            if let Ok(r) = unix::getrandom() {
+                return r;
+            }
+        }
+
+        if let Ok(r) = unix::dev_urandom() {
+            return r;
+        }
+    }
+    #[cfg(windows)]
+    {
+        if let Ok(r) = windows::bcrypt_gen_random() {
+            return r;
+        }
+    }
+
+    fallback_rand()
+}
+
+#[cfg(test)]
+mod test {
+    // While not a very useful test for randomness, we're mostly interested here
+    // in whether the memory is initialized correctly and nothing crashes because
+    // of the usage of unsafe code above. If the memory was not initialized fully
+    // then this test would fail in e.g. valgrind.
+    //
+    // Technically, all zeroes could be returned as a valid random number but that's
+    // extremely unlikely and more likely a bug in the code above.
+
+    #[test]
+    fn test_rand() {
+        let n = super::rand();
+        assert_ne!(n, [0u8; 8]);
+    }
+
+    #[test]
+    fn test_fallback_rand() {
+        let n = super::fallback_rand();
+        assert_ne!(n, [0u8; 8]);
+    }
+}
diff --git a/libs/gst/helpers/ptp/thread.rs b/libs/gst/helpers/ptp/thread.rs
new file mode 100644
index 0000000..eff363d
--- /dev/null
+++ b/libs/gst/helpers/ptp/thread.rs
@@ -0,0 +1,54 @@
+// GStreamer
+//
+// Copyright (C) 2015-2023 Sebastian Dröge <sebastian@centricular.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at
+// <https://mozilla.org/MPL/2.0/>.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+use crate::error::Error;
+
+pub fn set_priority() -> Result<(), Error> {
+    #[cfg(unix)]
+    {
+        use std::io;
+
+        use crate::{bail, ffi::unix::*};
+
+        // SAFETY: Setting the process priority can happen at any time. A negative
+        // priority require special permissions, which should've been given to the process.
+        //
+        // On error it returns a negative value.
+        unsafe {
+            if setpriority(PRIO_PROCESS, 0, -5) < 0 {
+                bail!(
+                    source: io::Error::last_os_error(),
+                    "Failed to set process priority"
+                );
+            }
+        }
+    }
+    #[cfg(windows)]
+    {
+        use std::io;
+
+        use crate::{bail, ffi::windows::*};
+
+        // SAFETY: Getting a handle to the current thread is safe at any time
+        let thread = unsafe { GetCurrentThread() };
+
+        // SAFETY: SetThreadPriority() requires a valid thread handle, which was given above,
+        // and will return 0 on errors.
+        unsafe {
+            if SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL) == 0 {
+                bail!(
+                    source: io::Error::last_os_error(),
+                    "Failed to set thread priority"
+                );
+            }
+        }
+    }
+    Ok(())
+}
diff --git a/libs/gst/net/gstnetclientclock.c b/libs/gst/net/gstnetclientclock.c
index 6c55f0a..0601cb1 100644
--- a/libs/gst/net/gstnetclientclock.c
+++ b/libs/gst/net/gstnetclientclock.c
@@ -137,12 +137,14 @@ struct _GstNetClientInternalClock
   GSocketAddress *servaddr;
   GCancellable *cancel;
   gboolean made_cancel_fd;
+  gboolean marked_corrupted;
 
   GstClockTime timeout_expiration;
   GstClockTime roundtrip_limit;
   GstClockTime rtt_avg;
   GstClockTime minimum_update_interval;
   GstClockTime last_remote_poll_interval;
+  GstClockTime last_remote_time;
   GstClockTime remote_avg_old;
   guint skipped_updates;
   GstClockTime last_rtts[MEDIAN_PRE_FILTERING_WINDOW];
@@ -230,6 +232,7 @@ gst_net_client_internal_clock_init (GstNetClientInternalClock * self)
   self->last_remote_poll_interval = GST_CLOCK_TIME_NONE;
   self->skipped_updates = 0;
   self->last_rtts_missing = MEDIAN_PRE_FILTERING_WINDOW;
+  self->marked_corrupted = FALSE;
   self->remote_avg_old = 0;
 }
 
@@ -328,6 +331,7 @@ gst_net_client_internal_clock_constructed (GObject * object)
 
   if (!gst_net_client_internal_clock_start (self)) {
     g_warning ("failed to start clock '%s'", GST_OBJECT_NAME (self));
+    self->marked_corrupted = TRUE;
   }
 
   /* all systems go, cap'n */
@@ -374,6 +378,11 @@ gst_net_client_internal_clock_observe_times (GstNetClientInternalClock * self,
       G_GUINT64_FORMAT " local2 %" G_GUINT64_FORMAT, local_1, remote_1,
       remote_2, local_2);
 
+  /* if we are ahead of time the time server may have been reset */
+  if (self->last_remote_time > remote_1 || self->marked_corrupted)
+    goto corrupted;
+  self->last_remote_time = remote_1;
+
   /* If the server told us a poll interval and it's bigger than the
    * one configured via the property, use the server's */
   if (self->last_remote_poll_interval != GST_CLOCK_TIME_NONE &&
@@ -649,6 +658,14 @@ bogus_observation:
   /* Schedule a new packet again soon */
   self->timeout_expiration = gst_util_get_timestamp () + (GST_SECOND / 4);
   return;
+
+corrupted:
+  if (!self->marked_corrupted) {
+    GST_ERROR_OBJECT (self, "Remote clock time reverted, mark clock invalid");
+    self->marked_corrupted = TRUE;
+  }
+  GST_OBJECT_UNLOCK (self);
+  return;
 }
 
 static gpointer
@@ -1178,35 +1195,44 @@ static void
 gst_net_client_clock_finalize (GObject * object)
 {
   GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object);
-  GList *l;
 
-  if (self->priv->synced_id)
-    g_signal_handler_disconnect (self->priv->internal_clock,
-        self->priv->synced_id);
-  self->priv->synced_id = 0;
+  if (self->priv->internal_clock) {
+    GList *l;
 
-  G_LOCK (clocks_lock);
-  for (l = clocks; l; l = l->next) {
-    ClockCache *cache = l->data;
+    if (self->priv->synced_id)
+      g_signal_handler_disconnect (self->priv->internal_clock,
+          self->priv->synced_id);
+    self->priv->synced_id = 0;
 
-    if (cache->clock == self->priv->internal_clock) {
-      cache->clocks = g_list_remove (cache->clocks, self);
+    G_LOCK (clocks_lock);
+    for (l = clocks; l; l = l->next) {
+      ClockCache *cache = l->data;
 
-      if (cache->clocks) {
-        update_clock_cache (cache);
-      } else {
-        GstClock *sysclock = gst_system_clock_obtain ();
-        GstClockTime time = gst_clock_get_time (sysclock) + 60 * GST_SECOND;
+      if (cache->clock == self->priv->internal_clock) {
+        cache->clocks = g_list_remove (cache->clocks, self);
 
-        cache->remove_id = gst_clock_new_single_shot_id (sysclock, time);
-        gst_clock_id_wait_async (cache->remove_id, remove_clock_cache, cache,
-            NULL);
-        gst_object_unref (sysclock);
+        if (cache->clocks) {
+          update_clock_cache (cache);
+        } else {
+          GstClock *sysclock = gst_system_clock_obtain ();
+          GstClockTime time = gst_clock_get_time (sysclock);
+          GstNetClientInternalClock *internal_clock =
+              GST_NET_CLIENT_INTERNAL_CLOCK (cache->clock);
+
+          /* only defer deletion if the clock is not marked corrupted */
+          if (!internal_clock->marked_corrupted)
+            time += 60 * GST_SECOND;
+
+          cache->remove_id = gst_clock_new_single_shot_id (sysclock, time);
+          gst_clock_id_wait_async (cache->remove_id, remove_clock_cache, cache,
+              NULL);
+          gst_object_unref (sysclock);
+        }
+        break;
       }
-      break;
     }
+    G_UNLOCK (clocks_lock);
   }
-  G_UNLOCK (clocks_lock);
 
   g_free (self->priv->address);
   self->priv->address = NULL;
@@ -1353,7 +1379,6 @@ static void
 gst_net_client_clock_constructed (GObject * object)
 {
   GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object);
-  GstClock *internal_clock;
   GList *l;
   ClockCache *cache = NULL;
 
@@ -1365,6 +1390,9 @@ gst_net_client_clock_constructed (GObject * object)
     GstNetClientInternalClock *internal_clock =
         GST_NET_CLIENT_INTERNAL_CLOCK (tmp->clock);
 
+    if (internal_clock->marked_corrupted)
+      continue;
+
     if (strcmp (internal_clock->address, self->priv->address) == 0 &&
         internal_clock->port == self->priv->port) {
       cache = tmp;
@@ -1378,34 +1406,49 @@ gst_net_client_clock_constructed (GObject * object)
   }
 
   if (!cache) {
-    cache = g_new0 (ClockCache, 1);
+    GstNetClientInternalClock *internal_clock;
 
-    cache->clock =
+    internal_clock =
         g_object_new (GST_TYPE_NET_CLIENT_INTERNAL_CLOCK, "address",
         self->priv->address, "port", self->priv->port, "is-ntp",
         self->priv->is_ntp, NULL);
-    gst_object_ref_sink (cache->clock);
-    clocks = g_list_prepend (clocks, cache);
+    gst_object_ref_sink (internal_clock);
+
+    if (internal_clock->marked_corrupted) {
+      GST_WARNING_OBJECT (self, "Internal clock couldn't start");
+      gst_object_unref (internal_clock);
+    } else {
+      cache = g_new0 (ClockCache, 1);
 
-    /* Not actually leaked but is cached for a while before being disposed,
-     * see gst_net_client_clock_finalize, so pretend it is to not confuse
-     * tests. */
-    GST_OBJECT_FLAG_SET (cache->clock, GST_OBJECT_FLAG_MAY_BE_LEAKED);
+      cache->clock = GST_CLOCK (internal_clock);
+      clocks = g_list_prepend (clocks, cache);
+
+      /* Not actually leaked but is cached for a while before being disposed,
+       * see gst_net_client_clock_finalize, so pretend it is to not confuse
+       * tests. */
+      GST_OBJECT_FLAG_SET (cache->clock, GST_OBJECT_FLAG_MAY_BE_LEAKED);
+    }
   }
 
-  cache->clocks = g_list_prepend (cache->clocks, self);
+  if (cache) {
+    cache->clocks = g_list_prepend (cache->clocks, self);
 
-  GST_OBJECT_LOCK (cache->clock);
-  if (gst_clock_is_synced (cache->clock))
-    gst_clock_set_synced (GST_CLOCK (self), TRUE);
-  self->priv->synced_id =
-      g_signal_connect (cache->clock, "synced",
-      G_CALLBACK (gst_net_client_clock_synced_cb), self);
-  GST_OBJECT_UNLOCK (cache->clock);
+    GST_OBJECT_LOCK (cache->clock);
+    if (gst_clock_is_synced (cache->clock))
+      gst_clock_set_synced (GST_CLOCK (self), TRUE);
+    self->priv->synced_id =
+        g_signal_connect (cache->clock, "synced",
+        G_CALLBACK (gst_net_client_clock_synced_cb), self);
+    GST_OBJECT_UNLOCK (cache->clock);
+
+    self->priv->internal_clock = cache->clock;
+  }
 
   G_UNLOCK (clocks_lock);
 
-  self->priv->internal_clock = internal_clock = cache->clock;
+  /* Mark clock as unsynced if creation of the internal clock failed */
+  if (!cache)
+    gst_clock_set_synced (GST_CLOCK (self), FALSE);
 
   /* all systems go, cap'n */
 }
@@ -1415,6 +1458,9 @@ gst_net_client_clock_get_internal_time (GstClock * clock)
 {
   GstNetClientClock *self = GST_NET_CLIENT_CLOCK (clock);
 
+  if (!self->priv->internal_clock)
+    return self->priv->base_time;
+
   if (!gst_clock_is_synced (self->priv->internal_clock)) {
     GstClockTime now = gst_clock_get_internal_time (self->priv->internal_clock);
     return gst_clock_adjust_with_calibration (self->priv->internal_clock, now,
diff --git a/libs/gst/net/gstptp_private.h b/libs/gst/net/gstptp_private.h
deleted file mode 100644
index 18e0e07..0000000
--- a/libs/gst/net/gstptp_private.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __GST_PTP_PRIVATE_H__
-#define __GST_PTP_PRIVATE_H__
-
-#include <glib.h>
-
-enum
-{
-  TYPE_EVENT,
-  TYPE_GENERAL,
-  TYPE_CLOCK_ID
-};
-
-typedef struct
-{
-  guint16 size;
-  guint8 type;
-} StdIOHeader;
-
-#endif /* __GST_PTP_PRIVATE_H__ */
diff --git a/libs/gst/net/gstptpclock.c b/libs/gst/net/gstptpclock.c
index 018e810..1a17f03 100644
--- a/libs/gst/net/gstptpclock.c
+++ b/libs/gst/net/gstptpclock.c
@@ -49,31 +49,35 @@
  * Since: 1.6
  *
  */
+#define _GNU_SOURCE 1
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "gstptpclock.h"
 
-#include "gstptp_private.h"
+#include <gio/gio.h>
+
+#include <gst/base/base.h>
 
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
 #ifdef G_OS_WIN32
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <processthreadsapi.h>  /* GetCurrentProcessId */
 #endif
-#include <sys/types.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#elif defined(G_OS_WIN32)
-#include <io.h>
 #endif
 
-#include <gst/base/base.h>
+#ifdef G_OS_WIN32
+#include <windows.h>
+static HMODULE gstnet_dll_handle = NULL;
+#endif
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
 
 GST_DEBUG_CATEGORY_STATIC (ptp_debug);
 #define GST_CAT_DEFAULT (ptp_debug)
@@ -233,6 +237,28 @@ typedef struct
   } message_specific;
 } PtpMessage;
 
+typedef enum
+{
+  TYPE_EVENT = 0,               /* 8-bit interface index, 64-bit monotonic clock time and PTP message is payload */
+  TYPE_GENERAL = 1,             /* 8-bit interface index, 64-bit monotonic clock time and PTP message is payload */
+  TYPE_CLOCK_ID = 2,            /* 64-bit clock ID is payload */
+  TYPE_SEND_TIME_ACK = 3,       /* 64-bit monotonic clock time, 8-bit message type, 8-bit domain number and 16-bit sequence number is payload */
+} StdIOMessageType;
+
+/* 2 byte BE payload size plus 1 byte message type */
+#define STDIO_MESSAGE_HEADER_SIZE (3)
+
+/* 2 byte BE payload size. Payload format:
+ * - 1 byte GstDebugLevel
+ * - 2 byte BE filename length
+ * - filename UTF-8 string
+ * - 2 byte BE module path length
+ * - module path UTF-8 string
+ * - 4 byte BE line number
+ * - remainder is UTF-8 string
+ */
+#define STDERR_MESSAGE_HEADER_SIZE (2)
+
 static GMutex ptp_lock;
 static GCond ptp_cond;
 static gboolean initted = FALSE;
@@ -241,20 +267,45 @@ static gboolean supported = TRUE;
 #else
 static gboolean supported = FALSE;
 #endif
-static GPid ptp_helper_pid;
+static GSubprocess *ptp_helper_process;
+static GInputStream *stdout_pipe;
+static GInputStream *stderr_pipe;
+static GOutputStream *stdin_pipe;
+static guint8 stdio_header[STDIO_MESSAGE_HEADER_SIZE];  /* buffer for reading the message header */
+static guint8 stdout_buffer[8192];      /* buffer for reading the message payload */
+static guint8 stderr_header[STDERR_MESSAGE_HEADER_SIZE];        /* buffer for reading the message header */
+static guint8 stderr_buffer[8192];      /* buffer for reading the message payload */
 static GThread *ptp_helper_thread;
 static GMainContext *main_context;
 static GMainLoop *main_loop;
-static GIOChannel *stdin_channel, *stdout_channel;
 static GRand *delay_req_rand;
 static GstClock *observation_system_clock;
 static PtpClockIdentity ptp_clock_id = { GST_PTP_CLOCK_ID_NONE, 0 };
 
+#define CUR_STDIO_HEADER_SIZE (GST_READ_UINT16_BE (stdio_header))
+#define CUR_STDIO_HEADER_TYPE ((StdIOMessageType) stdio_header[2])
+
+#define CUR_STDERR_HEADER_SIZE (GST_READ_UINT16_BE (stderr_header))
+
 typedef struct
 {
+  PtpClockIdentity master_clock_identity;
+  guint8 iface_idx;
+
+  GstClockTime announce_interval;       /* last interval we received */
+  GQueue announce_messages;
+  guint64 timed_out_sync;       /* how often did this sender continously time out a FOLLOW_UP */
+  guint64 timed_out_delay_resp; /* how often did this sender continously time out a DELAY_RESP */
+} PtpAnnounceSender;
+
+typedef struct
+{
+  PtpAnnounceSender *sender;
+
   GstClockTime receive_time;
 
   PtpClockIdentity master_clock_identity;
+  guint8 iface_idx;
 
   guint8 grandmaster_priority_1;
   PtpClockQuality grandmaster_clock_quality;
@@ -266,26 +317,18 @@ typedef struct
   guint16 sequence_id;
 } PtpAnnounceMessage;
 
-typedef struct
-{
-  PtpClockIdentity master_clock_identity;
-
-  GstClockTime announce_interval;       /* last interval we received */
-  GQueue announce_messages;
-} PtpAnnounceSender;
-
 typedef struct
 {
   guint domain;
-  PtpClockIdentity master_clock_identity;
 
-  guint16 sync_seqnum;
+  guint32 sync_seqnum;
   GstClockTime sync_recv_time_local;    /* t2 */
   GstClockTime sync_send_time_remote;   /* t1, might be -1 if FOLLOW_UP pending */
   GstClockTime follow_up_recv_time_local;
 
   GSource *timeout_source;
-  guint16 delay_req_seqnum;
+  guint8 iface_idx;
+  guint32 delay_req_seqnum;
   GstClockTime delay_req_send_time_local;       /* t3, -1 if we wait for FOLLOW_UP */
   GstClockTime delay_req_recv_time_remote;      /* t4, -1 if we wait */
   GstClockTime delay_resp_recv_time_local;
@@ -318,15 +361,18 @@ typedef struct
   /* Last selected master clock */
   gboolean have_master_clock;
   PtpClockIdentity master_clock_identity;
+  guint8 iface_idx;
   guint64 grandmaster_identity;
 
   /* Last SYNC or FOLLOW_UP timestamp we received */
   GstClockTime last_ptp_sync_time;
+  GstClockTime last_ptp_sync_time_local;
   GstClockTime sync_interval;
 
   GstClockTime mean_path_delay;
   GstClockTime last_delay_req, min_delay_req_interval;
   guint16 last_delay_req_seqnum;
+  GstClockTime last_ptp_delay_resp_time_local;
 
   GstClockTime last_path_delays[MEDIAN_PRE_FILTERING_WINDOW];
   gint last_path_delays_missing;
@@ -336,6 +382,11 @@ typedef struct
   GstClock *domain_clock;
 } PtpDomainData;
 
+// The lists domain_clocks and domain_data are same but the former is protected
+// by the domain_clocks_lock.
+// It is needed because sometimes other threads than the PTP thread will need
+// to access the list, and without a mutex it might happen that the original
+// list (domain_data) is modified at the same time (prepending a new domain).
 static GList *domain_data;
 static GMutex domain_clocks_lock;
 static GList *domain_clocks;
@@ -346,6 +397,11 @@ static GHookList domain_stats_hooks;
 static gint domain_stats_n_hooks;
 static gboolean domain_stats_hooks_initted = FALSE;
 
+/* Only ever accessed from the PTP thread */
+/* PTPD in hybrid mode (default) sends multicast PTP messages with an invalid
+ * logMessageInterval. We work around this here and warn once */
+static gboolean ptpd_hybrid_workaround_warned_once = FALSE;
+
 /* Converts log2 seconds to GstClockTime */
 static GstClockTime
 log2_to_clock_time (gint l)
@@ -650,21 +706,36 @@ parse_ptp_message (PtpMessage * msg, const guint8 * data, gsize size)
 
 static gint
 compare_announce_message (const PtpAnnounceMessage * a,
-    const PtpAnnounceMessage * b)
+    const PtpAnnounceMessage * b, gboolean skip_tiebreakers)
 {
   /* IEEE 1588 Figure 27 */
   if (a->grandmaster_identity == b->grandmaster_identity) {
-    if (a->steps_removed + 1 < b->steps_removed)
+    // Random threshold of 4 timeouts to completely ignore all steps removed
+    if (a->sender->timed_out_delay_resp + a->sender->timed_out_sync + 4 <
+        b->sender->timed_out_delay_resp + b->sender->timed_out_sync)
       return -1;
-    else if (a->steps_removed > b->steps_removed + 1)
+    if (a->sender->timed_out_delay_resp + a->sender->timed_out_sync >
+        b->sender->timed_out_delay_resp + b->sender->timed_out_sync + 4)
       return 1;
 
-    /* Error cases are filtered out earlier */
     if (a->steps_removed < b->steps_removed)
       return -1;
     else if (a->steps_removed > b->steps_removed)
       return 1;
 
+    // If both are the same number of steps removed, prefer the clock with
+    // fewer timeouts before going to the tie breakers based on clock
+    // identities and interface indices
+    if (a->sender->timed_out_delay_resp + a->sender->timed_out_sync <
+        b->sender->timed_out_delay_resp + b->sender->timed_out_sync)
+      return -1;
+    if (a->sender->timed_out_delay_resp + a->sender->timed_out_sync >
+        b->sender->timed_out_delay_resp + b->sender->timed_out_sync)
+      return 1;
+
+    if (skip_tiebreakers)
+      return 0;
+
     /* Error cases are filtered out earlier */
     if (a->master_clock_identity.clock_identity <
         b->master_clock_identity.clock_identity)
@@ -680,8 +751,11 @@ compare_announce_message (const PtpAnnounceMessage * a,
     else if (a->master_clock_identity.port_number >
         b->master_clock_identity.port_number)
       return 1;
-    else
-      g_assert_not_reached ();
+
+    if (a->iface_idx < b->iface_idx)
+      return -1;
+    else if (a->iface_idx > b->iface_idx)
+      return 1;
 
     return 0;
   }
@@ -770,20 +844,70 @@ select_best_master_clock (PtpDomainData * domain, GstClockTime now)
   for (l = qualified_messages; l; l = l->next) {
     PtpAnnounceMessage *msg = l->data;
 
-    if (!best || compare_announce_message (msg, best) < 0)
+    if (!best || compare_announce_message (msg, best, FALSE) < 0)
       best = msg;
   }
+
+  GST_DEBUG ("Found master clock for domain %u: 0x%016" G_GINT64_MODIFIER
+      "x %u on interface %u with grandmaster clock 0x%016" G_GINT64_MODIFIER
+      "x", domain->domain, best->master_clock_identity.clock_identity,
+      best->master_clock_identity.port_number, best->iface_idx,
+      best->grandmaster_identity);
+
+  // Check if the newly selected best clock and the previous one are
+  // equivalent except for tiebreakers. In that case, don't actually switch
+  // to avoid switching regularly between clocks.
+  if (domain->have_master_clock &&
+      (compare_clock_identity (&domain->master_clock_identity,
+              &best->master_clock_identity) != 0
+          || domain->iface_idx != best->iface_idx)
+      ) {
+    // Find announce sender for the currently selected clock
+    for (l = domain->announce_senders; l; l = l->next) {
+      PtpAnnounceSender *sender = l->data;
+
+      if (compare_clock_identity (&domain->master_clock_identity,
+              &sender->master_clock_identity) == 0
+          && domain->iface_idx == sender->iface_idx) {
+
+        // Find qualified message for it (if there is none then it timed out)
+        for (m = qualified_messages; m; m = m->next) {
+          PtpAnnounceMessage *msg = m->data;
+
+          if (compare_clock_identity (&sender->master_clock_identity,
+                  &msg->master_clock_identity) == 0
+              && sender->iface_idx == msg->iface_idx) {
+
+            if (compare_announce_message (msg, best, TRUE) == 0) {
+              GST_DEBUG
+                  ("Currently selected master clock for domain %u is equivalent",
+                  domain->domain);
+              best = msg;
+            }
+
+            break;
+          }
+        }
+
+        break;
+      }
+    }
+  }
+
   g_clear_pointer (&qualified_messages, g_list_free);
 
   if (domain->have_master_clock
       && compare_clock_identity (&domain->master_clock_identity,
-          &best->master_clock_identity) == 0) {
+          &best->master_clock_identity) == 0
+      && domain->iface_idx == best->iface_idx) {
     GST_DEBUG ("Master clock in domain %u did not change", domain->domain);
   } else {
-    GST_DEBUG ("Selected master clock for domain %u: 0x%016" G_GINT64_MODIFIER
-        "x %u with grandmaster clock 0x%016" G_GINT64_MODIFIER "x",
-        domain->domain, best->master_clock_identity.clock_identity,
-        best->master_clock_identity.port_number, best->grandmaster_identity);
+    GST_DEBUG ("Selected new master clock for domain %u: 0x%016"
+        G_GINT64_MODIFIER "x %u on interface %u with grandmaster clock 0x%016"
+        G_GINT64_MODIFIER "x", domain->domain,
+        best->master_clock_identity.clock_identity,
+        best->master_clock_identity.port_number, best->iface_idx,
+        best->grandmaster_identity);
 
     domain->have_master_clock = TRUE;
     domain->grandmaster_identity = best->grandmaster_identity;
@@ -791,15 +915,19 @@ select_best_master_clock (PtpDomainData * domain, GstClockTime now)
     /* Opportunistic master clock selection likely gave us the same master
      * clock before, no need to reset all statistics */
     if (compare_clock_identity (&domain->master_clock_identity,
-            &best->master_clock_identity) != 0) {
+            &best->master_clock_identity) != 0
+        || domain->iface_idx != best->iface_idx) {
       memcpy (&domain->master_clock_identity, &best->master_clock_identity,
           sizeof (PtpClockIdentity));
+      domain->iface_idx = best->iface_idx;
       domain->mean_path_delay = 0;
       domain->last_delay_req = 0;
       domain->last_path_delays_missing = 9;
+      domain->last_ptp_delay_resp_time_local = 0;
       domain->min_delay_req_interval = 0;
       domain->sync_interval = 0;
       domain->last_ptp_sync_time = 0;
+      domain->last_ptp_sync_time_local = 0;
       domain->skipped_updates = 0;
       g_queue_foreach (&domain->pending_syncs, (GFunc) ptp_pending_sync_free,
           NULL);
@@ -823,7 +951,8 @@ select_best_master_clock (PtpDomainData * domain, GstClockTime now)
 }
 
 static void
-handle_announce_message (PtpMessage * msg, GstClockTime receive_time)
+handle_announce_message (PtpMessage * msg, guint8 iface_idx,
+    GstClockTime receive_time)
 {
   GList *l;
   PtpDomainData *domain = NULL;
@@ -883,7 +1012,7 @@ handle_announce_message (PtpMessage * msg, GstClockTime receive_time)
     PtpAnnounceSender *tmp = l->data;
 
     if (compare_clock_identity (&tmp->master_clock_identity,
-            &msg->source_port_identity) == 0) {
+            &msg->source_port_identity) == 0 && tmp->iface_idx == iface_idx) {
       sender = tmp;
       break;
     }
@@ -894,6 +1023,7 @@ handle_announce_message (PtpMessage * msg, GstClockTime receive_time)
 
     memcpy (&sender->master_clock_identity, &msg->source_port_identity,
         sizeof (PtpClockIdentity));
+    sender->iface_idx = iface_idx;
     g_queue_init (&sender->announce_messages);
     domain->announce_senders =
         g_list_prepend (domain->announce_senders, sender);
@@ -909,13 +1039,25 @@ handle_announce_message (PtpMessage * msg, GstClockTime receive_time)
       return;
   }
 
-  sender->announce_interval = log2_to_clock_time (msg->log_message_interval);
+  if (msg->log_message_interval == 0x7f) {
+    sender->announce_interval = 2 * GST_SECOND;
+
+    if (!ptpd_hybrid_workaround_warned_once) {
+      GST_WARNING ("Working around ptpd bug: ptpd sends multicast PTP packets "
+          "with invalid logMessageInterval");
+      ptpd_hybrid_workaround_warned_once = TRUE;
+    }
+  } else {
+    sender->announce_interval = log2_to_clock_time (msg->log_message_interval);
+  }
 
   announce = g_new0 (PtpAnnounceMessage, 1);
+  announce->sender = sender;
   announce->receive_time = receive_time;
   announce->sequence_id = msg->sequence_id;
   memcpy (&announce->master_clock_identity, &msg->source_port_identity,
       sizeof (PtpClockIdentity));
+  announce->iface_idx = iface_idx;
   announce->grandmaster_identity =
       msg->message_specific.announce.grandmaster_identity;
   announce->grandmaster_priority_1 =
@@ -939,19 +1081,22 @@ handle_announce_message (PtpMessage * msg, GstClockTime receive_time)
 static gboolean
 send_delay_req_timeout (PtpPendingSync * sync)
 {
-  StdIOHeader header = { 0, };
-  guint8 delay_req[44];
+  guint8 message[STDIO_MESSAGE_HEADER_SIZE + 1 + 8 + 44] = { 0, };
   GstByteWriter writer;
-  GIOStatus status;
   gsize written;
   GError *err = NULL;
-
-  header.type = TYPE_EVENT;
-  header.size = 44;
+  GstClockTime send_time;
 
   GST_TRACE ("Sending delay_req to domain %u", sync->domain);
 
-  gst_byte_writer_init_with_data (&writer, delay_req, 44, FALSE);
+  sync->delay_req_send_time_local = send_time =
+      gst_clock_get_time (observation_system_clock);
+
+  gst_byte_writer_init_with_data (&writer, message, sizeof (message), FALSE);
+  gst_byte_writer_put_uint16_be_unchecked (&writer, 1 + 8 + 44);
+  gst_byte_writer_put_uint8_unchecked (&writer, TYPE_EVENT);
+  gst_byte_writer_put_uint8_unchecked (&writer, sync->iface_idx);
+  gst_byte_writer_put_uint64_be_unchecked (&writer, send_time);
   gst_byte_writer_put_uint8_unchecked (&writer, PTP_MESSAGE_TYPE_DELAY_REQ);
   gst_byte_writer_put_uint8_unchecked (&writer, 2);
   gst_byte_writer_put_uint16_be_unchecked (&writer, 44);
@@ -969,48 +1114,20 @@ send_delay_req_timeout (PtpPendingSync * sync)
   gst_byte_writer_put_uint64_be_unchecked (&writer, 0);
   gst_byte_writer_put_uint16_be_unchecked (&writer, 0);
 
-  status =
-      g_io_channel_write_chars (stdout_channel, (gchar *) & header,
-      sizeof (header), &written, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    g_warning ("Failed to write to stdout: %s", err->message);
-    g_clear_error (&err);
-    return G_SOURCE_REMOVE;
-  } else if (status == G_IO_STATUS_EOF) {
-    g_message ("EOF on stdout");
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (status != G_IO_STATUS_NORMAL) {
-    g_warning ("Unexpected stdout write status: %d", status);
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (written != sizeof (header)) {
-    g_warning ("Unexpected write size: %" G_GSIZE_FORMAT, written);
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  }
-
-  sync->delay_req_send_time_local =
-      gst_clock_get_time (observation_system_clock);
+  if (!g_output_stream_write_all (stdin_pipe, message, sizeof (message),
+          &written, NULL, &err)) {
+    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CLOSED)
+        || g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) {
+      GST_ERROR ("Got EOF on stdout");
+    } else {
+      GST_ERROR ("Failed to write delay-req to stdin: %s", err->message);
+    }
 
-  status =
-      g_io_channel_write_chars (stdout_channel,
-      (const gchar *) delay_req, 44, &written, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    g_warning ("Failed to write to stdout: %s", err->message);
-    g_clear_error (&err);
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (status == G_IO_STATUS_EOF) {
     g_message ("EOF on stdout");
     g_main_loop_quit (main_loop);
     return G_SOURCE_REMOVE;
-  } else if (status != G_IO_STATUS_NORMAL) {
-    g_warning ("Unexpected stdout write status: %d", status);
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (written != 44) {
-    g_warning ("Unexpected write size: %" G_GSIZE_FORMAT, written);
+  } else if (written != sizeof (message)) {
+    GST_ERROR ("Unexpected write size: %" G_GSIZE_FORMAT, written);
     g_main_loop_quit (main_loop);
     return G_SOURCE_REMOVE;
   }
@@ -1032,6 +1149,7 @@ send_delay_req (PtpDomainData * domain, PtpPendingSync * sync)
   }
 
   domain->last_delay_req = now;
+  sync->iface_idx = domain->iface_idx;
   sync->delay_req_seqnum = domain->last_delay_req_seqnum++;
 
   /* IEEE 1588 9.5.11.2 */
@@ -1455,7 +1573,8 @@ out:
 }
 
 static void
-handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
+handle_sync_message (PtpMessage * msg, guint8 iface_idx,
+    GstClockTime receive_time)
 {
   GList *l;
   PtpDomainData *domain = NULL;
@@ -1497,21 +1616,36 @@ handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
 
   /* If we have a master clock, ignore this message if it's not coming from there */
   if (domain->have_master_clock
-      && compare_clock_identity (&domain->master_clock_identity,
-          &msg->source_port_identity) != 0)
+      && (compare_clock_identity (&domain->master_clock_identity,
+              &msg->source_port_identity) != 0
+          || domain->iface_idx != iface_idx)) {
+    GST_TRACE ("SYNC msg not from current clock master. Ignoring");
     return;
+  }
 
 #ifdef USE_OPPORTUNISTIC_CLOCK_SELECTION
   /* Opportunistic selection of master clock */
-  if (!domain->have_master_clock)
+  if (!domain->have_master_clock) {
     memcpy (&domain->master_clock_identity, &msg->source_port_identity,
         sizeof (PtpClockIdentity));
+    domain->iface_idx = iface_idx;
+  }
 #else
   if (!domain->have_master_clock)
     return;
 #endif
 
-  domain->sync_interval = log2_to_clock_time (msg->log_message_interval);
+  if (msg->log_message_interval == 0x7f) {
+    domain->sync_interval = GST_SECOND;
+
+    if (!ptpd_hybrid_workaround_warned_once) {
+      GST_WARNING ("Working around ptpd bug: ptpd sends multicast PTP packets "
+          "with invalid logMessageInterval");
+      ptpd_hybrid_workaround_warned_once = TRUE;
+    }
+  } else {
+    domain->sync_interval = log2_to_clock_time (msg->log_message_interval);
+  }
 
   /* Check if duplicated */
   for (l = domain->pending_syncs.head; l; l = l->next) {
@@ -1539,6 +1673,7 @@ handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
   sync->delay_req_send_time_local = GST_CLOCK_TIME_NONE;
   sync->delay_req_recv_time_remote = GST_CLOCK_TIME_NONE;
   sync->delay_resp_recv_time_local = GST_CLOCK_TIME_NONE;
+  sync->delay_req_seqnum = G_MAXUINT32;
 
   /* 0.5 correction factor for division later */
   sync->correction_field_sync = msg->correction_field;
@@ -1562,6 +1697,20 @@ handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
       return;
     }
     domain->last_ptp_sync_time = sync->sync_send_time_remote;
+    domain->last_ptp_sync_time_local = receive_time;
+
+    for (l = domain->announce_senders; l; l = l->next) {
+      PtpAnnounceSender *sender = l->data;
+
+      if (compare_clock_identity (&domain->master_clock_identity,
+              &sender->master_clock_identity) == 0
+          && domain->iface_idx == sender->iface_idx) {
+
+        sender->timed_out_sync = 0;
+
+        break;
+      }
+    }
 
     if (send_delay_req (domain, sync)) {
       /* Sent delay request */
@@ -1577,7 +1726,8 @@ handle_sync_message (PtpMessage * msg, GstClockTime receive_time)
 }
 
 static void
-handle_follow_up_message (PtpMessage * msg, GstClockTime receive_time)
+handle_follow_up_message (PtpMessage * msg, guint8 iface_idx,
+    GstClockTime receive_time)
 {
   GList *l;
   PtpDomainData *domain = NULL;
@@ -1607,8 +1757,9 @@ handle_follow_up_message (PtpMessage * msg, GstClockTime receive_time)
 
   /* If we have a master clock, ignore this message if it's not coming from there */
   if (domain->have_master_clock
-      && compare_clock_identity (&domain->master_clock_identity,
-          &msg->source_port_identity) != 0) {
+      && (compare_clock_identity (&domain->master_clock_identity,
+              &msg->source_port_identity) != 0
+          || domain->iface_idx != iface_idx)) {
     GST_TRACE ("FOLLOW_UP msg not from current clock master. Ignoring");
     return;
   }
@@ -1661,6 +1812,20 @@ handle_follow_up_message (PtpMessage * msg, GstClockTime receive_time)
     return;
   }
   domain->last_ptp_sync_time = sync->sync_send_time_remote;
+  domain->last_ptp_sync_time_local = receive_time;
+
+  for (l = domain->announce_senders; l; l = l->next) {
+    PtpAnnounceSender *sender = l->data;
+
+    if (compare_clock_identity (&domain->master_clock_identity,
+            &sender->master_clock_identity) == 0
+        && domain->iface_idx == sender->iface_idx) {
+
+      sender->timed_out_sync = 0;
+
+      break;
+    }
+  }
 
   if (send_delay_req (domain, sync)) {
     /* Sent delay request */
@@ -1673,12 +1838,20 @@ handle_follow_up_message (PtpMessage * msg, GstClockTime receive_time)
 }
 
 static void
-handle_delay_resp_message (PtpMessage * msg, GstClockTime receive_time)
+handle_delay_resp_message (PtpMessage * msg, guint8 iface_idx,
+    GstClockTime receive_time)
 {
   GList *l;
   PtpDomainData *domain = NULL;
   PtpPendingSync *sync = NULL;
 
+  /* Not for us */
+  if (msg->message_specific.delay_resp.
+      requesting_port_identity.clock_identity != ptp_clock_id.clock_identity
+      || msg->message_specific.delay_resp.
+      requesting_port_identity.port_number != ptp_clock_id.port_number)
+    return;
+
   /* Don't consider messages with the alternate master flag set */
   if ((msg->flag_field & 0x0100))
     return;
@@ -1697,19 +1870,25 @@ handle_delay_resp_message (PtpMessage * msg, GstClockTime receive_time)
 
   /* If we have a master clock, ignore this message if it's not coming from there */
   if (domain->have_master_clock
-      && compare_clock_identity (&domain->master_clock_identity,
-          &msg->source_port_identity) != 0)
+      && (compare_clock_identity (&domain->master_clock_identity,
+              &msg->source_port_identity) != 0
+          || domain->iface_idx != iface_idx)) {
+    GST_TRACE ("DELAY_RESP msg not from current clock master. Ignoring");
     return;
+  }
 
-  /* Not for us */
-  if (msg->message_specific.delay_resp.
-      requesting_port_identity.clock_identity != ptp_clock_id.clock_identity
-      || msg->message_specific.delay_resp.
-      requesting_port_identity.port_number != ptp_clock_id.port_number)
-    return;
+  if (msg->log_message_interval == 0x7f) {
+    domain->min_delay_req_interval = GST_SECOND;
 
-  domain->min_delay_req_interval =
-      log2_to_clock_time (msg->log_message_interval);
+    if (!ptpd_hybrid_workaround_warned_once) {
+      GST_WARNING ("Working around ptpd bug: ptpd sends multicast PTP packets "
+          "with invalid logMessageInterval");
+      ptpd_hybrid_workaround_warned_once = TRUE;
+    }
+  } else {
+    domain->min_delay_req_interval =
+        log2_to_clock_time (msg->log_message_interval);
+  }
 
   /* Check if we know about this one */
   for (l = domain->pending_syncs.head; l; l = l->next) {
@@ -1756,6 +1935,21 @@ handle_delay_resp_message (PtpMessage * msg, GstClockTime receive_time)
     return;
   }
 
+  domain->last_ptp_delay_resp_time_local = receive_time;
+
+  for (l = domain->announce_senders; l; l = l->next) {
+    PtpAnnounceSender *sender = l->data;
+
+    if (compare_clock_identity (&domain->master_clock_identity,
+            &sender->master_clock_identity) == 0
+        && domain->iface_idx == sender->iface_idx) {
+
+      sender->timed_out_delay_resp = 0;
+
+      break;
+    }
+  }
+
   if (update_mean_path_delay (domain, sync))
     update_ptp_time (domain, sync);
   g_queue_remove (&domain->pending_syncs, sync);
@@ -1763,7 +1957,8 @@ handle_delay_resp_message (PtpMessage * msg, GstClockTime receive_time)
 }
 
 static void
-handle_ptp_message (PtpMessage * msg, GstClockTime receive_time)
+handle_ptp_message (PtpMessage * msg, guint8 iface_idx,
+    GstClockTime receive_time)
 {
   /* Ignore our own messages */
   if (msg->source_port_identity.clock_identity == ptp_clock_id.clock_identity &&
@@ -1772,109 +1967,157 @@ handle_ptp_message (PtpMessage * msg, GstClockTime receive_time)
     return;
   }
 
-  GST_TRACE ("Message type %d receive_time %" GST_TIME_FORMAT,
-      msg->message_type, GST_TIME_ARGS (receive_time));
+  GST_TRACE ("Message type %d iface idx %d receive_time %" GST_TIME_FORMAT,
+      msg->message_type, iface_idx, GST_TIME_ARGS (receive_time));
   switch (msg->message_type) {
     case PTP_MESSAGE_TYPE_ANNOUNCE:
-      handle_announce_message (msg, receive_time);
+      handle_announce_message (msg, iface_idx, receive_time);
       break;
     case PTP_MESSAGE_TYPE_SYNC:
-      handle_sync_message (msg, receive_time);
+      handle_sync_message (msg, iface_idx, receive_time);
       break;
     case PTP_MESSAGE_TYPE_FOLLOW_UP:
-      handle_follow_up_message (msg, receive_time);
+      handle_follow_up_message (msg, iface_idx, receive_time);
       break;
     case PTP_MESSAGE_TYPE_DELAY_RESP:
-      handle_delay_resp_message (msg, receive_time);
+      handle_delay_resp_message (msg, iface_idx, receive_time);
       break;
     default:
       break;
   }
 }
 
-static gboolean
-have_stdin_data_cb (GIOChannel * channel, GIOCondition condition,
-    gpointer user_data)
+static void
+handle_send_time_ack (const guint8 * data, gsize size,
+    GstClockTime receive_time)
 {
-  GIOStatus status;
-  StdIOHeader header;
-  gchar buffer[8192];
-  GError *err = NULL;
-  gsize read;
+  GstByteReader breader;
+  GstClockTime helper_send_time;
+  guint8 message_type;
+  guint8 domain_number;
+  guint16 seqnum;
+  GList *l;
+  PtpDomainData *domain = NULL;
+  PtpPendingSync *sync = NULL;
 
-  if ((condition & G_IO_STATUS_EOF)) {
-    GST_ERROR ("Got EOF on stdin");
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
+  gst_byte_reader_init (&breader, data, size);
+  helper_send_time = gst_byte_reader_get_uint64_be_unchecked (&breader);
+  message_type = gst_byte_reader_get_uint8_unchecked (&breader);
+  domain_number = gst_byte_reader_get_uint8_unchecked (&breader);
+  seqnum = gst_byte_reader_get_uint16_be_unchecked (&breader);
+
+  GST_TRACE
+      ("Received SEND_TIME_ACK for message type %d, domain number %d, seqnum %d with send time %"
+      GST_TIME_FORMAT " at receive_time %" GST_TIME_FORMAT, message_type,
+      domain_number, seqnum, GST_TIME_ARGS (helper_send_time),
+      GST_TIME_ARGS (receive_time));
+
+  if (message_type != PTP_MESSAGE_TYPE_DELAY_REQ)
+    return;
+
+  for (l = domain_data; l; l = l->next) {
+    PtpDomainData *tmp = l->data;
+
+    if (domain_number == tmp->domain) {
+      domain = tmp;
+      break;
+    }
   }
 
-  status =
-      g_io_channel_read_chars (channel, (gchar *) & header, sizeof (header),
-      &read, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    GST_ERROR ("Failed to read from stdin: %s", err->message);
-    g_clear_error (&err);
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (status == G_IO_STATUS_EOF) {
-    GST_ERROR ("Got EOF on stdin");
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (status != G_IO_STATUS_NORMAL) {
-    GST_ERROR ("Unexpected stdin read status: %d", status);
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (read != sizeof (header)) {
-    GST_ERROR ("Unexpected read size: %" G_GSIZE_FORMAT, read);
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (header.size > 8192) {
-    GST_ERROR ("Unexpected size: %u", header.size);
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
+  if (!domain)
+    return;
+
+  /* Check if we know about this one */
+  for (l = domain->pending_syncs.head; l; l = l->next) {
+    PtpPendingSync *tmp = l->data;
+
+    if (tmp->delay_req_seqnum == seqnum) {
+      sync = tmp;
+      break;
+    }
   }
 
-  status = g_io_channel_read_chars (channel, buffer, header.size, &read, &err);
-  if (status == G_IO_STATUS_ERROR) {
-    GST_ERROR ("Failed to read from stdin: %s", err->message);
+  if (!sync)
+    return;
+
+  /* Got a DELAY_RESP for this already */
+  if (sync->delay_req_recv_time_remote != GST_CLOCK_TIME_NONE)
+    return;
+
+  if (helper_send_time != 0) {
+    GST_TRACE ("DELAY_REQ message took %" GST_STIME_FORMAT
+        " to helper process, SEND_TIME_ACK took %" GST_STIME_FORMAT
+        " from helper process",
+        GST_STIME_ARGS ((GstClockTimeDiff) (helper_send_time -
+                sync->delay_req_send_time_local)),
+        GST_STIME_ARGS (receive_time - helper_send_time));
+    sync->delay_req_send_time_local = helper_send_time;
+  }
+}
+
+static void have_stdout_header (GInputStream * stdout_pipe, GAsyncResult * res,
+    gpointer user_data);
+
+static void
+have_stdout_body (GInputStream * stdout_pipe, GAsyncResult * res,
+    gpointer user_data)
+{
+  GError *err = NULL;
+  gsize read;
+
+  /* Finish reading the body */
+  if (!g_input_stream_read_all_finish (stdout_pipe, res, &read, &err)) {
+    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
+        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) {
+      GST_ERROR ("Got EOF on stdout");
+    } else {
+      GST_ERROR ("Failed to read header from stdout: %s", err->message);
+    }
     g_clear_error (&err);
     g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (status == G_IO_STATUS_EOF) {
-    GST_ERROR ("EOF on stdin");
-    g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (status != G_IO_STATUS_NORMAL) {
-    GST_ERROR ("Unexpected stdin read status: %d", status);
+    return;
+  } else if (read == 0) {
+    GST_ERROR ("Got EOF on stdin");
     g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
-  } else if (read != header.size) {
+    return;
+  } else if (read != CUR_STDIO_HEADER_SIZE) {
     GST_ERROR ("Unexpected read size: %" G_GSIZE_FORMAT, read);
     g_main_loop_quit (main_loop);
-    return G_SOURCE_REMOVE;
+    return;
   }
 
-  switch (header.type) {
+  switch (CUR_STDIO_HEADER_TYPE) {
     case TYPE_EVENT:
     case TYPE_GENERAL:{
       GstClockTime receive_time = gst_clock_get_time (observation_system_clock);
+      guint8 iface_idx;
+      GstClockTime helper_receive_time;
       PtpMessage msg;
 
-      if (parse_ptp_message (&msg, (const guint8 *) buffer, header.size)) {
+      iface_idx = GST_READ_UINT8 (stdout_buffer);
+      helper_receive_time = GST_READ_UINT64_BE (stdout_buffer + 1);
+
+      if (parse_ptp_message (&msg, (const guint8 *) stdout_buffer + 1 + 8,
+              CUR_STDIO_HEADER_SIZE)) {
         dump_ptp_message (&msg);
-        handle_ptp_message (&msg, receive_time);
+        if (helper_receive_time != 0) {
+          GST_TRACE ("Message took %" GST_STIME_FORMAT " from helper process",
+              GST_STIME_ARGS ((GstClockTimeDiff) (receive_time -
+                      helper_receive_time)));
+          receive_time = helper_receive_time;
+        }
+        handle_ptp_message (&msg, iface_idx, receive_time);
       }
       break;
     }
-    default:
     case TYPE_CLOCK_ID:{
-      if (header.size != 8) {
-        GST_ERROR ("Unexpected clock id size (%u != 8)", header.size);
+      if (CUR_STDIO_HEADER_SIZE != 8) {
+        GST_ERROR ("Unexpected clock id size (%u != 8)", CUR_STDIO_HEADER_SIZE);
         g_main_loop_quit (main_loop);
-        return G_SOURCE_REMOVE;
+        return;
       }
       g_mutex_lock (&ptp_lock);
-      ptp_clock_id.clock_identity = GST_READ_UINT64_BE (buffer);
+      ptp_clock_id.clock_identity = GST_READ_UINT64_BE (stdout_buffer);
 #ifdef G_OS_WIN32
       ptp_clock_id.port_number = (guint16) GetCurrentProcessId ();
 #else
@@ -1886,9 +2129,202 @@ have_stdin_data_cb (GIOChannel * channel, GIOCondition condition,
       g_mutex_unlock (&ptp_lock);
       break;
     }
+    case TYPE_SEND_TIME_ACK:{
+      GstClockTime receive_time = gst_clock_get_time (observation_system_clock);
+
+      if (CUR_STDIO_HEADER_SIZE != 12) {
+        GST_ERROR ("Unexpected send time ack size (%u != 12)",
+            CUR_STDIO_HEADER_SIZE);
+        g_main_loop_quit (main_loop);
+        return;
+      }
+
+      handle_send_time_ack (stdout_buffer, CUR_STDIO_HEADER_SIZE, receive_time);
+      break;
+    }
+    default:
+      break;
   }
 
-  return G_SOURCE_CONTINUE;
+  /* And read the next header */
+  memset (&stdio_header, 0, STDIO_MESSAGE_HEADER_SIZE);
+  g_input_stream_read_all_async (stdout_pipe, stdio_header,
+      STDIO_MESSAGE_HEADER_SIZE, G_PRIORITY_DEFAULT, NULL,
+      (GAsyncReadyCallback) have_stdout_header, NULL);
+}
+
+static void
+have_stdout_header (GInputStream * stdout_pipe, GAsyncResult * res,
+    gpointer user_data)
+{
+  GError *err = NULL;
+  gsize read;
+
+  /* Finish reading the header */
+  if (!g_input_stream_read_all_finish (stdout_pipe, res, &read, &err)) {
+    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
+        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) {
+      GST_ERROR ("Got EOF on stdout");
+    } else {
+      GST_ERROR ("Failed to read header from stdout: %s", err->message);
+    }
+    g_clear_error (&err);
+    g_main_loop_quit (main_loop);
+    return;
+  } else if (read == 0) {
+    GST_ERROR ("Got EOF on stdin");
+    return;
+  } else if (read != STDIO_MESSAGE_HEADER_SIZE) {
+    GST_ERROR ("Unexpected read size: %" G_GSIZE_FORMAT, read);
+    g_main_loop_quit (main_loop);
+    return;
+  } else if (CUR_STDIO_HEADER_SIZE > 8192) {
+    GST_ERROR ("Unexpected size: %u", CUR_STDIO_HEADER_SIZE);
+    g_main_loop_quit (main_loop);
+    return;
+  }
+
+  /* And now read the body */
+  g_input_stream_read_all_async (stdout_pipe, stdout_buffer,
+      CUR_STDIO_HEADER_SIZE, G_PRIORITY_DEFAULT, NULL,
+      (GAsyncReadyCallback) have_stdout_body, NULL);
+}
+
+static void have_stderr_header (GInputStream * stderr_pipe, GAsyncResult * res,
+    gpointer user_data);
+
+static void
+have_stderr_body (GInputStream * stderr_pipe, GAsyncResult * res,
+    gpointer user_data)
+{
+  GError *err = NULL;
+  gsize read;
+#ifndef GST_DISABLE_GST_DEBUG
+  GstByteReader breader;
+  GstDebugLevel level;
+  guint16 filename_length;
+  gchar *filename = NULL;
+  guint16 module_path_length;
+  gchar *module_path = NULL;
+  guint32 line_number;
+  gchar *message = NULL;
+  guint16 message_length;
+  guint8 b;
+#endif
+
+  /* Finish reading the body */
+  if (!g_input_stream_read_all_finish (stderr_pipe, res, &read, &err)) {
+    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
+        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) {
+      GST_ERROR ("Got EOF on stderr");
+    } else {
+      GST_ERROR ("Failed to read header from stderr: %s", err->message);
+    }
+    g_clear_error (&err);
+    g_main_loop_quit (main_loop);
+    return;
+  } else if (read == 0) {
+    GST_ERROR ("Got EOF on stderr");
+    g_main_loop_quit (main_loop);
+    return;
+  } else if (read != CUR_STDERR_HEADER_SIZE) {
+    GST_ERROR ("Unexpected read size: %" G_GSIZE_FORMAT, read);
+    g_main_loop_quit (main_loop);
+    return;
+  }
+
+#ifndef GST_DISABLE_GST_DEBUG
+  gst_byte_reader_init (&breader, stderr_buffer, CUR_STDERR_HEADER_SIZE);
+
+  if (!gst_byte_reader_get_uint8 (&breader, &b) || b > GST_LEVEL_MAX)
+    goto err;
+  level = (GstDebugLevel) b;
+  if (!gst_byte_reader_get_uint16_be (&breader, &filename_length)
+      || filename_length > gst_byte_reader_get_remaining (&breader))
+    goto err;
+  filename =
+      g_strndup ((const gchar *) gst_byte_reader_get_data_unchecked (&breader,
+          filename_length), filename_length);
+
+  if (!gst_byte_reader_get_uint16_be (&breader, &module_path_length)
+      || module_path_length > gst_byte_reader_get_remaining (&breader))
+    goto err;
+  module_path =
+      g_strndup ((const gchar *) gst_byte_reader_get_data_unchecked (&breader,
+          module_path_length), module_path_length);
+
+  if (!gst_byte_reader_get_uint32_be (&breader, &line_number))
+    goto err;
+
+  message_length = gst_byte_reader_get_remaining (&breader);
+  message =
+      g_strndup ((const gchar *) gst_byte_reader_get_data_unchecked (&breader,
+          message_length), message_length);
+
+  gst_debug_log_literal (GST_CAT_DEFAULT, level, filename, module_path,
+      line_number, NULL, message);
+
+  g_clear_pointer (&filename, g_free);
+  g_clear_pointer (&module_path, g_free);
+  g_clear_pointer (&message, g_free);
+#endif
+
+  /* And read the next header */
+  memset (&stderr_header, 0, STDERR_MESSAGE_HEADER_SIZE);
+  g_input_stream_read_all_async (stderr_pipe, stderr_header,
+      STDERR_MESSAGE_HEADER_SIZE, G_PRIORITY_DEFAULT, NULL,
+      (GAsyncReadyCallback) have_stderr_header, NULL);
+  return;
+
+#ifndef GST_DISABLE_GST_DEBUG
+err:
+  {
+    GST_ERROR ("Unexpected stderr data");
+    g_clear_pointer (&filename, g_free);
+    g_clear_pointer (&module_path, g_free);
+    g_clear_pointer (&message, g_free);
+    g_main_loop_quit (main_loop);
+    return;
+  }
+#endif
+}
+
+static void
+have_stderr_header (GInputStream * stderr_pipe, GAsyncResult * res,
+    gpointer user_data)
+{
+  GError *err = NULL;
+  gsize read;
+
+  /* Finish reading the header */
+  if (!g_input_stream_read_all_finish (stderr_pipe, res, &read, &err)) {
+    if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CLOSED) ||
+        g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED)) {
+      GST_ERROR ("Got EOF on stderr");
+    } else {
+      GST_ERROR ("Failed to read header from stderr: %s", err->message);
+    }
+    g_clear_error (&err);
+    g_main_loop_quit (main_loop);
+    return;
+  } else if (read == 0) {
+    GST_ERROR ("Got EOF on stderr");
+    g_main_loop_quit (main_loop);
+    return;
+  } else if (read != STDERR_MESSAGE_HEADER_SIZE) {
+    GST_ERROR ("Unexpected read size: %" G_GSIZE_FORMAT, read);
+    g_main_loop_quit (main_loop);
+    return;
+  } else if (CUR_STDERR_HEADER_SIZE > 8192 || CUR_STDERR_HEADER_SIZE < 9) {
+    GST_ERROR ("Unexpected size: %u", CUR_STDERR_HEADER_SIZE);
+    g_main_loop_quit (main_loop);
+    return;
+  }
+
+  /* And now read the body */
+  g_input_stream_read_all_async (stderr_pipe, stderr_buffer,
+      CUR_STDERR_HEADER_SIZE, G_PRIORITY_DEFAULT, NULL,
+      (GAsyncReadyCallback) have_stderr_body, NULL);
 }
 
 /* Cleanup all announce messages and announce message senders
@@ -1935,7 +2371,8 @@ cleanup_cb (gpointer data)
         GList *tmp = n->next;
 
         if (compare_clock_identity (&sender->master_clock_identity,
-                &domain->master_clock_identity) == 0)
+                &domain->master_clock_identity) == 0
+            && sender->iface_idx == domain->iface_idx)
           GST_WARNING ("currently selected master clock timed out");
         g_free (sender);
         domain->announce_senders =
@@ -1945,12 +2382,13 @@ cleanup_cb (gpointer data)
         n = n->next;
       }
     }
-    select_best_master_clock (domain, now);
 
     /* Clean up any pending syncs */
     for (n = domain->pending_syncs.head; n;) {
       PtpPendingSync *sync = n->data;
       gboolean timed_out = FALSE;
+      gboolean clock_timed_out_sync = FALSE;
+      gboolean clock_timed_out_delay_resp = FALSE;
 
       /* Time out pending syncs after 4 sync intervals or 10 seconds,
        * and pending delay reqs after 4 delay req intervals or 10 seconds
@@ -1961,10 +2399,48 @@ cleanup_cb (gpointer data)
                   4 * domain->min_delay_req_interval < now)
               || (sync->delay_req_send_time_local + 10 * GST_SECOND < now))) {
         timed_out = TRUE;
-      } else if ((domain->sync_interval != 0
-              && sync->sync_recv_time_local + 4 * domain->sync_interval < now)
-          || (sync->sync_recv_time_local + 10 * GST_SECOND < now)) {
+
+        // If no newer delay resp received in the meantime, downgrade the
+        // selected clock
+        if (domain->last_ptp_delay_resp_time_local <
+            sync->delay_req_send_time_local) {
+          clock_timed_out_delay_resp = TRUE;
+        }
+      } else if (sync->follow_up_recv_time_local == GST_CLOCK_TIME_NONE && (
+              (domain->sync_interval != 0
+                  && sync->sync_recv_time_local + 4 * domain->sync_interval <
+                  now)
+              || (sync->sync_recv_time_local + 10 * GST_SECOND < now))) {
         timed_out = TRUE;
+
+        // If no newer sync/follow-up received in the meantime, downgrade the
+        // selected clock
+        if (domain->last_ptp_sync_time_local < sync->sync_recv_time_local) {
+          clock_timed_out_sync = TRUE;
+        }
+      }
+
+      // If the clock is timed out then downgrade it now in case there is a
+      // better clock for the domain that can be selected below.
+      if (domain->have_master_clock && (clock_timed_out_sync
+              || clock_timed_out_delay_resp)) {
+        GST_DEBUG ("Currently selected clock timed out, downgrading");
+
+        for (m = domain->announce_senders; m; m = m->next) {
+          PtpAnnounceSender *sender = m->data;
+
+          if (compare_clock_identity (&domain->master_clock_identity,
+                  &sender->master_clock_identity) == 0
+              && domain->iface_idx == sender->iface_idx) {
+
+            if (clock_timed_out_sync)
+              sender->timed_out_sync++;
+            if (clock_timed_out_delay_resp)
+              sender->timed_out_delay_resp++;
+
+            break;
+          }
+        }
       }
 
       if (timed_out) {
@@ -1976,6 +2452,8 @@ cleanup_cb (gpointer data)
         n = n->next;
       }
     }
+
+    select_best_master_clock (domain, now);
   }
 
   return G_SOURCE_CONTINUE;
@@ -1988,8 +2466,20 @@ ptp_helper_main (gpointer data)
 
   GST_DEBUG ("Starting PTP helper loop");
 
-  /* Check all 5 seconds, if we have to cleanup ANNOUNCE or pending syncs message */
-  cleanup_source = g_timeout_source_new_seconds (5);
+  g_main_context_push_thread_default (main_context);
+
+  memset (&stdio_header, 0, STDIO_MESSAGE_HEADER_SIZE);
+  g_input_stream_read_all_async (stdout_pipe, stdio_header,
+      STDIO_MESSAGE_HEADER_SIZE, G_PRIORITY_DEFAULT, NULL,
+      (GAsyncReadyCallback) have_stdout_header, NULL);
+
+  memset (&stderr_header, 0, STDERR_MESSAGE_HEADER_SIZE);
+  g_input_stream_read_all_async (stderr_pipe, stderr_header,
+      STDERR_MESSAGE_HEADER_SIZE, G_PRIORITY_DEFAULT, NULL,
+      (GAsyncReadyCallback) have_stderr_header, NULL);
+
+  /* Check every 1 seconds, if we have to cleanup ANNOUNCE or pending syncs message */
+  cleanup_source = g_timeout_source_new_seconds (1);
   g_source_set_priority (cleanup_source, G_PRIORITY_DEFAULT);
   g_source_set_callback (cleanup_source, (GSourceFunc) cleanup_cb, NULL, NULL);
   g_source_attach (cleanup_source, main_context);
@@ -1998,6 +2488,8 @@ ptp_helper_main (gpointer data)
   g_main_loop_run (main_loop);
   GST_DEBUG ("Stopped PTP helper loop");
 
+  g_main_context_pop_thread_default (main_context);
+
   g_mutex_lock (&ptp_lock);
   ptp_clock_id.clock_identity = GST_PTP_CLOCK_ID_NONE;
   ptp_clock_id.port_number = 0;
@@ -2040,35 +2532,201 @@ gst_ptp_is_initialized (void)
   return initted;
 }
 
+#if defined(G_OS_WIN32) && !defined(GST_STATIC_COMPILATION)
+/* Note: DllMain is only called when DLLs are loaded or unloaded, so this will
+ * never be called if libgstnet-1.0 is linked statically. Do not add any code
+ * here to, say, initialize variables or set things up since that will only
+ * happen for dynamically-built GStreamer.
+ */
+BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+  if (fdwReason == DLL_PROCESS_ATTACH)
+    gstnet_dll_handle = (HMODULE) hinstDLL;
+  return TRUE;
+}
+
+#endif
+
+static char *
+get_relocated_libgstnet (void)
+{
+  char *dir = NULL;
+
+#ifdef G_OS_WIN32
+  {
+    char *base_dir;
+
+    GST_DEBUG ("attempting to retrieve libgstnet-1.0 location using "
+        "Win32-specific method");
+
+    base_dir =
+        g_win32_get_package_installation_directory_of_module
+        (gstnet_dll_handle);
+    if (!base_dir)
+      return NULL;
+
+    dir = g_build_filename (base_dir, GST_PLUGIN_SUBDIR, NULL);
+    GST_DEBUG ("using DLL dir %s", dir);
+
+    g_free (base_dir);
+  }
+#elif defined(HAVE_DLADDR)
+  {
+    Dl_info info;
+    char *real_fname = NULL;
+    long path_max = 0;
+
+    GST_DEBUG ("attempting to retrieve libgstnet-1.0 location using "
+        "dladdr()");
+
+    if (dladdr (&gst_ptp_init, &info)) {
+      GST_LOG ("dli_fname: %s", info.dli_fname);
+
+      if (!info.dli_fname) {
+        return NULL;
+      }
+#ifdef PATH_MAX
+      path_max = PATH_MAX;
+#else
+      path_max = pathconf (info.dli_fname, _PC_PATH_MAX);
+      if (path_max <= 0)
+        path_max = 4096;
+#endif
+
+      real_fname = g_malloc (path_max);
+      if (realpath (info.dli_fname, real_fname)) {
+        dir = g_path_get_dirname (real_fname);
+        GST_DEBUG ("real directory location: %s", dir);
+      } else {
+        GST_ERROR ("could not canonicalize path %s: %s", info.dli_fname,
+            g_strerror (errno));
+        dir = g_path_get_dirname (info.dli_fname);
+      }
+      g_free (real_fname);
+
+    } else {
+      GST_LOG ("dladdr() failed");
+      return NULL;
+    }
+  }
+#else
+#warning "Unsupported platform for retrieving the current location of a shared library."
+#warning "Relocatable builds will not work."
+  GST_WARNING ("Don't know how to retrieve the location of the shared "
+      "library libgstnet-" GST_API_VERSION);
+#endif
+
+  return dir;
+}
+
+static int
+count_directories (const char *filepath)
+{
+  int i = 0;
+  char *tmp;
+  gsize len;
+
+  g_return_val_if_fail (!g_path_is_absolute (filepath), 0);
+
+  tmp = g_strdup (filepath);
+  len = strlen (tmp);
+
+  /* ignore UNC share paths entirely */
+  if (len >= 3 && G_IS_DIR_SEPARATOR (tmp[0]) && G_IS_DIR_SEPARATOR (tmp[1])
+      && !G_IS_DIR_SEPARATOR (tmp[2])) {
+    GST_WARNING ("found a UNC share path, ignoring");
+    g_clear_pointer (&tmp, g_free);
+    return 0;
+  }
+
+  /* remove trailing slashes if they exist */
+  while (
+      /* don't remove the trailing slash for C:\.
+       * UNC paths are at least \\s\s */
+      len > 3 && G_IS_DIR_SEPARATOR (tmp[len - 1])) {
+    tmp[len - 1] = '\0';
+    len--;
+  }
+
+  while (tmp) {
+    char *dirname, *basename;
+    len = strlen (tmp);
+
+    if (g_strcmp0 (tmp, ".") == 0)
+      break;
+    if (g_strcmp0 (tmp, "/") == 0)
+      break;
+
+    /* g_path_get_dirname() may return something of the form 'C:.', where C is
+     * a drive letter */
+    if (len == 3 && g_ascii_isalpha (tmp[0]) && tmp[1] == ':' && tmp[2] == '.')
+      break;
+
+    basename = g_path_get_basename (tmp);
+    dirname = g_path_get_dirname (tmp);
+
+    if (g_strcmp0 (basename, "..") == 0) {
+      i--;
+    } else if (g_strcmp0 (basename, ".") == 0) {
+      /* nothing to do */
+    } else {
+      i++;
+    }
+
+    g_clear_pointer (&basename, g_free);
+    g_clear_pointer (&tmp, g_free);
+    tmp = dirname;
+  }
+
+  g_clear_pointer (&tmp, g_free);
+
+  if (i < 0) {
+    g_critical ("path counting resulted in a negative directory count!");
+    return 0;
+  }
+
+  return i;
+}
+
+
 /**
- * gst_ptp_init:
- * @clock_id: PTP clock id of this process' clock or %GST_PTP_CLOCK_ID_NONE
- * @interfaces: (transfer none) (array zero-terminated=1) (allow-none): network interfaces to run the clock on
+ * gst_ptp_init_full:
+ * @config: Configuration for initializing the GStreamer PTP subsystem
  *
  * Initialize the GStreamer PTP subsystem and create a PTP ordinary clock in
- * slave-only mode for all domains on the given @interfaces with the
- * given @clock_id.
+ * slave-only mode according to the @config.
  *
- * If @clock_id is %GST_PTP_CLOCK_ID_NONE, a clock id is automatically
- * generated from the MAC address of the first network interface.
+ * @config is a #GstStructure with the following optional fields:
+ * * #guint64 `clock-id`: The clock ID to use for the local clock. If the
+ *     clock-id is not provided or %GST_PTP_CLOCK_ID_NONE is provided, a clock
+ *     id is automatically generated from the MAC address of the first network
+ *     interface.
+ * * #GStrv `interfaces`: The interface names to listen on for PTP packets. If
+ *     none are provided then all compatible interfaces will be used.
+ * * #guint `ttl`: The TTL to use for multicast packets sent out by GStreamer.
+ *     This defaults to 1, i.e. packets will not leave the local network.
  *
  * This function is automatically called by gst_ptp_clock_new() with default
  * parameters if it wasn't called before.
  *
  * Returns: %TRUE if the GStreamer PTP clock subsystem could be initialized.
  *
- * Since: 1.6
+ * Since: 1.24
  */
 gboolean
-gst_ptp_init (guint64 clock_id, gchar ** interfaces)
+gst_ptp_init_full (const GstStructure * config)
 {
   gboolean ret;
   const gchar *env;
   gchar **argv = NULL;
   gint argc, argc_c;
-  gint fd_r, fd_w;
+  guint64 clock_id = GST_CLOCK_TIME_NONE;
+  const GValue *v;
+  gchar **interfaces = NULL;
+  guint ttl = 1;
   GError *err = NULL;
-  GSource *stdin_source;
 
   GST_DEBUG_CATEGORY_INIT (ptp_debug, "ptp", 0, "PTP clock");
 
@@ -2085,7 +2743,7 @@ gst_ptp_init (guint64 clock_id, gchar ** interfaces)
     goto done;
   }
 
-  if (ptp_helper_pid) {
+  if (ptp_helper_process) {
     GST_DEBUG ("PTP currently initializing");
     goto wait;
   }
@@ -2096,27 +2754,84 @@ gst_ptp_init (guint64 clock_id, gchar ** interfaces)
   }
 
   argc = 1;
+  gst_structure_get_uint64 (config, "clock-id", &clock_id);
   if (clock_id != GST_PTP_CLOCK_ID_NONE)
     argc += 2;
+  v = gst_structure_get_value (config, "interfaces");
+  if (v && G_VALUE_HOLDS (v, G_TYPE_STRV))
+    interfaces = g_value_get_boxed (v);
   if (interfaces != NULL)
     argc += 2 * g_strv_length (interfaces);
+  gst_structure_get_uint (config, "ttl", &ttl);
+  argc += 2;
 
-  argv = g_new0 (gchar *, argc + 2);
+  // 3 for: executable, -v and NULL
+  argv = g_new0 (gchar *, argc + 3);
   argc_c = 0;
 
+  /* Find the gst-ptp-helper */
   env = g_getenv ("GST_PTP_HELPER_1_0");
-  if (env == NULL)
+  if (!env)
     env = g_getenv ("GST_PTP_HELPER");
-  if (env != NULL && *env != '\0') {
-    GST_LOG ("Trying GST_PTP_HELPER env var: %s", env);
+
+  if (env && *env != '\0') {
+    /* use the env-var if it is set */
     argv[argc_c++] = g_strdup (env);
   } else {
-    argv[argc_c++] = g_strdup (GST_PTP_HELPER_INSTALLED);
+    char *relocated_libgstnet;
+
+    /* use the installed version */
+    GST_LOG ("Trying installed PTP helper process");
+
+#define MAX_PATH_DEPTH 64
+
+    relocated_libgstnet = get_relocated_libgstnet ();
+    if (relocated_libgstnet) {
+      int plugin_subdir_depth = count_directories (GST_PLUGIN_SUBDIR);
+
+      GST_DEBUG ("found libgstnet-" GST_API_VERSION " library "
+          "at %s", relocated_libgstnet);
+
+      if (plugin_subdir_depth < MAX_PATH_DEPTH) {
+        const char *filenamev[MAX_PATH_DEPTH + 5];
+        int i = 0, j;
+
+        filenamev[i++] = relocated_libgstnet;
+        for (j = 0; j < plugin_subdir_depth; j++)
+          filenamev[i++] = "..";
+        filenamev[i++] = GST_PTP_HELPER_SUBDIR;
+        filenamev[i++] = "gstreamer-" GST_API_VERSION;
+#ifdef G_OS_WIN32
+        filenamev[i++] = "gst-ptp-helper.exe";
+#else
+        filenamev[i++] = "gst-ptp-helper";
+#endif
+        filenamev[i++] = NULL;
+        g_assert (i <= MAX_PATH_DEPTH + 5);
+
+        GST_DEBUG ("constructing path to system PTP helper using "
+            "plugin dir: \'%s\', PTP helper dir: \'%s\'",
+            GST_PLUGIN_SUBDIR, GST_PTP_HELPER_SUBDIR);
+
+        argv[argc_c++] = g_build_filenamev ((char **) filenamev);
+      } else {
+        GST_WARNING ("GST_PLUGIN_SUBDIR: \'%s\' has too many path segments",
+            GST_PLUGIN_SUBDIR);
+        argv[argc_c++] = g_strdup (GST_PTP_HELPER_INSTALLED);
+      }
+    } else {
+      argv[argc_c++] = g_strdup (GST_PTP_HELPER_INSTALLED);
+    }
   }
 
+#undef MAX_PATH_DEPTH
+
+  GST_LOG ("Using PTP helper process: %s", argv[argc_c - 1]);
+
   if (clock_id != GST_PTP_CLOCK_ID_NONE) {
     argv[argc_c++] = g_strdup ("-c");
     argv[argc_c++] = g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", clock_id);
+    GST_LOG ("Using clock ID: %s", argv[argc_c - 1]);
   }
 
   if (interfaces != NULL) {
@@ -2125,24 +2840,25 @@ gst_ptp_init (guint64 clock_id, gchar ** interfaces)
     while (*ptr) {
       argv[argc_c++] = g_strdup ("-i");
       argv[argc_c++] = g_strdup (*ptr);
+      GST_LOG ("Using interface: %s", argv[argc_c - 1]);
       ptr++;
     }
   }
 
-  main_context = g_main_context_new ();
-  main_loop = g_main_loop_new (main_context, FALSE);
+  argv[argc_c++] = g_strdup ("--ttl");
+  argv[argc_c++] = g_strdup_printf ("%u", ttl);
 
-  ptp_helper_thread =
-      g_thread_try_new ("ptp-helper-thread", ptp_helper_main, NULL, &err);
-  if (!ptp_helper_thread) {
-    GST_ERROR ("Failed to start PTP helper thread: %s", err->message);
-    g_clear_error (&err);
-    ret = FALSE;
-    goto done;
+  /* Check if the helper process should be verbose */
+  env = g_getenv ("GST_PTP_HELPER_VERBOSE");
+  if (env && g_ascii_strcasecmp (env, "no") != 0) {
+    argv[argc_c++] = g_strdup ("-v");
   }
 
-  if (!g_spawn_async_with_pipes (NULL, argv, NULL, 0, NULL, NULL,
-          &ptp_helper_pid, &fd_w, &fd_r, NULL, &err)) {
+  ptp_helper_process =
+      g_subprocess_newv ((const gchar * const *) argv,
+      G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE |
+      G_SUBPROCESS_FLAGS_STDERR_PIPE, &err);
+  if (!ptp_helper_process) {
     GST_ERROR ("Failed to start ptp helper process: %s", err->message);
     g_clear_error (&err);
     ret = FALSE;
@@ -2150,23 +2866,21 @@ gst_ptp_init (guint64 clock_id, gchar ** interfaces)
     goto done;
   }
 
-  stdin_channel = g_io_channel_unix_new (fd_r);
-  g_io_channel_set_encoding (stdin_channel, NULL, NULL);
-  g_io_channel_set_buffered (stdin_channel, FALSE);
-  g_io_channel_set_close_on_unref (stdin_channel, TRUE);
-  stdin_source =
-      g_io_create_watch (stdin_channel, G_IO_IN | G_IO_PRI | G_IO_HUP);
-  g_source_set_priority (stdin_source, G_PRIORITY_DEFAULT);
-  g_source_set_callback (stdin_source, (GSourceFunc) have_stdin_data_cb, NULL,
-      NULL);
-  g_source_attach (stdin_source, main_context);
-  g_source_unref (stdin_source);
-
-  /* Create stdout channel */
-  stdout_channel = g_io_channel_unix_new (fd_w);
-  g_io_channel_set_encoding (stdout_channel, NULL, NULL);
-  g_io_channel_set_close_on_unref (stdout_channel, TRUE);
-  g_io_channel_set_buffered (stdout_channel, FALSE);
+  stdin_pipe = g_subprocess_get_stdin_pipe (ptp_helper_process);
+  if (stdin_pipe)
+    g_object_ref (stdin_pipe);
+  stdout_pipe = g_subprocess_get_stdout_pipe (ptp_helper_process);
+  if (stdout_pipe)
+    g_object_ref (stdout_pipe);
+  stderr_pipe = g_subprocess_get_stderr_pipe (ptp_helper_process);
+  if (stderr_pipe)
+    g_object_ref (stderr_pipe);
+  if (!stdin_pipe || !stdout_pipe || !stderr_pipe) {
+    GST_ERROR ("Failed to get ptp helper process pipes");
+    ret = FALSE;
+    supported = FALSE;
+    goto done;
+  }
 
   delay_req_rand = g_rand_new ();
   observation_system_clock =
@@ -2174,6 +2888,18 @@ gst_ptp_init (guint64 clock_id, gchar ** interfaces)
       NULL);
   gst_object_ref_sink (observation_system_clock);
 
+  main_context = g_main_context_new ();
+  main_loop = g_main_loop_new (main_context, FALSE);
+
+  ptp_helper_thread =
+      g_thread_try_new ("ptp-helper-thread", ptp_helper_main, NULL, &err);
+  if (!ptp_helper_thread) {
+    GST_ERROR ("Failed to start PTP helper thread: %s", err->message);
+    g_clear_error (&err);
+    ret = FALSE;
+    goto done;
+  }
+
   initted = TRUE;
 
 wait:
@@ -2195,24 +2921,13 @@ done:
   g_strfreev (argv);
 
   if (!ret) {
-    if (ptp_helper_pid) {
-#ifndef G_OS_WIN32
-      kill (ptp_helper_pid, SIGKILL);
-      waitpid (ptp_helper_pid, NULL, 0);
-#else
-      TerminateProcess (ptp_helper_pid, 1);
-      WaitForSingleObject (ptp_helper_pid, INFINITE);
-#endif
-      g_spawn_close_pid (ptp_helper_pid);
+    if (ptp_helper_process) {
+      g_clear_object (&stdin_pipe);
+      g_clear_object (&stdout_pipe);
+      g_clear_object (&stderr_pipe);
+      g_subprocess_force_exit (ptp_helper_process);
+      g_clear_object (&ptp_helper_process);
     }
-    ptp_helper_pid = 0;
-
-    if (stdin_channel)
-      g_io_channel_unref (stdin_channel);
-    stdin_channel = NULL;
-    if (stdout_channel)
-      g_io_channel_unref (stdout_channel);
-    stdout_channel = NULL;
 
     if (main_loop && ptp_helper_thread) {
       g_main_loop_quit (main_loop);
@@ -2240,6 +2955,40 @@ done:
   return ret;
 }
 
+/**
+ * gst_ptp_init:
+ * @clock_id: PTP clock id of this process' clock or %GST_PTP_CLOCK_ID_NONE
+ * @interfaces: (transfer none) (array zero-terminated=1) (allow-none): network interfaces to run the clock on
+ *
+ * Initialize the GStreamer PTP subsystem and create a PTP ordinary clock in
+ * slave-only mode for all domains on the given @interfaces with the
+ * given @clock_id.
+ *
+ * If @clock_id is %GST_PTP_CLOCK_ID_NONE, a clock id is automatically
+ * generated from the MAC address of the first network interface.
+ *
+ * This function is automatically called by gst_ptp_clock_new() with default
+ * parameters if it wasn't called before.
+ *
+ * Returns: %TRUE if the GStreamer PTP clock subsystem could be initialized.
+ *
+ * Since: 1.6
+ */
+gboolean
+gst_ptp_init (guint64 clock_id, gchar ** interfaces)
+{
+  GstStructure *config;
+  gboolean ret;
+
+  config = gst_structure_new ("config/ptp",
+      "clock-id", G_TYPE_UINT64, clock_id,
+      "interfaces", G_TYPE_STRV, interfaces, NULL);
+  ret = gst_ptp_init_full (config);
+  gst_structure_free (config);
+
+  return ret;
+}
+
 /**
  * gst_ptp_deinit:
  *
@@ -2256,24 +3005,13 @@ gst_ptp_deinit (void)
 
   g_mutex_lock (&ptp_lock);
 
-  if (ptp_helper_pid) {
-#ifndef G_OS_WIN32
-    kill (ptp_helper_pid, SIGKILL);
-    waitpid (ptp_helper_pid, NULL, 0);
-#else
-    TerminateProcess (ptp_helper_pid, 1);
-    WaitForSingleObject (ptp_helper_pid, INFINITE);
-#endif
-    g_spawn_close_pid (ptp_helper_pid);
+  if (ptp_helper_process) {
+    g_clear_object (&stdin_pipe);
+    g_clear_object (&stdout_pipe);
+    g_clear_object (&stderr_pipe);
+    g_subprocess_force_exit (ptp_helper_process);
+    g_clear_object (&ptp_helper_process);
   }
-  ptp_helper_pid = 0;
-
-  if (stdin_channel)
-    g_io_channel_unref (stdin_channel);
-  stdin_channel = NULL;
-  if (stdout_channel)
-    g_io_channel_unref (stdout_channel);
-  stdout_channel = NULL;
 
   if (main_loop && ptp_helper_thread) {
     GThread *tmp = ptp_helper_thread;
@@ -2317,7 +3055,8 @@ gst_ptp_deinit (void)
   }
   g_list_free (domain_data);
   domain_data = NULL;
-  g_list_foreach (domain_clocks, (GFunc) g_free, NULL);
+  // The domain_clocks list is same as domain_data
+  // and the elements are freed above already
   g_list_free (domain_clocks);
   domain_clocks = NULL;
 
diff --git a/libs/gst/net/gstptpclock.h b/libs/gst/net/gstptpclock.h
index 3182431..3f635e5 100644
--- a/libs/gst/net/gstptpclock.h
+++ b/libs/gst/net/gstptpclock.h
@@ -88,6 +88,10 @@ gboolean        gst_ptp_is_initialized             (void);
 GST_NET_API
 gboolean        gst_ptp_init                       (guint64 clock_id,
                                                     gchar ** interfaces);
+
+GST_NET_API
+gboolean        gst_ptp_init_full                  (const GstStructure *config);
+
 GST_NET_API
 void            gst_ptp_deinit                     (void);
 
diff --git a/libs/gst/net/meson.build b/libs/gst/net/meson.build
index bd7771f..f4937d6 100644
--- a/libs/gst/net/meson.build
+++ b/libs/gst/net/meson.build
@@ -32,7 +32,7 @@ gst_net = library('gstnet-@0@'.format(apiversion),
   soversion : soversion,
   darwin_versions : osxversion,
   install : true,
-  dependencies : [gio_dep, gst_base_dep],
+  dependencies : [gio_dep, gst_base_dep, dl_dep, network_deps],
 )
 
 library_def = {'lib': gst_net}
@@ -63,6 +63,7 @@ if build_gir
   library_def += {'gir': [gir]}
   if not static_build
     gst_net_gir = gnome.generate_gir(gst_net, kwargs: gir)
+    library_def += {'gir_targets':  library_def.get('gir_targets', []) + [gst_net_gir]}
     gst_net_gen_sources += [gst_net_gir]
   endif
 endif
diff --git a/meson.build b/meson.build
index f9f591d..dc9dbe2 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,6 @@
 project('gstreamer', 'c',
-  version : '1.22.0',
-  meson_version : '>= 0.62',
+  version : '1.24.12',
+  meson_version : '>= 1.1',
   default_options : [ 'warning_level=1',
                       'buildtype=debugoptimized' ])
 
@@ -32,6 +32,7 @@ helpers_install_dir = join_paths(libexecdir, 'gstreamer-1.0')
 
 cc = meson.get_compiler('c')
 host_system = host_machine.system()
+static_build = get_option('default_library') == 'static'
 
 if host_system == 'darwin'
   ios_test_code = '''#include <TargetConditionals.h>
@@ -75,8 +76,6 @@ if cc.get_id() == 'msvc'
       '/we4053', # one void operand for '?:'
       '/we4062', # enumerator 'identifier' in switch of enum 'enumeration' is not handled
       '/we4098', # 'function' : void function returning a value
-      '/we4101', # 'identifier' : unreferenced local variable
-      '/we4189', # 'identifier' : local variable is initialized but not referenced
     ])
   endif
   add_project_arguments(msvc_args, language: 'c')
@@ -149,6 +148,8 @@ cdata.set_quoted('GST_PLUGIN_SUBDIR', get_option('libdir'),
   description: 'plugin directory path component, used to find plugins on relocatable builds')
 cdata.set_quoted('GST_PLUGIN_SCANNER_SUBDIR', libexecdir,
   description: 'libexecdir path component, used to find plugin-scanner on relocatable builds')
+cdata.set_quoted('GST_PTP_HELPER_SUBDIR', libexecdir,
+  description: 'libexecdir path component, used to find ptp-helper on relocatable builds')
 cdata.set('GST_DISABLE_OPTION_PARSING', not get_option('option-parsing'))
 
 mem_align_opt = get_option('memory-alignment')
@@ -276,6 +277,12 @@ foreach f : check_functions
   endif
 endforeach
 
+if host_system == 'windows'
+  if cc.has_function('_set_thread_local_invalid_parameter_handler', prefix : '#include <stdlib.h>')
+    cdata.set('HAVE__SET_THREAD_LOCAL_INVALID_PARAMETER_HANDLER', 1)
+  endif
+endif
+
 if cc.has_function('localtime_r', prefix : '#include<time.h>')
   cdata.set('HAVE_LOCALTIME_R', 1)
   # Needed by libcheck
@@ -312,7 +319,7 @@ if cc.compiles('''#include <linux/futex.h>
                int main (int argc, char ** argv) {
                  syscall (__NR_futex_time64, NULL, FUTEX_WAKE, FUTEX_WAIT);
                  return 0;
-               }''', name : 'futex(2) system call')
+               }''', name : 'futex_time64(2) system call')
   cdata.set('HAVE_FUTEX_TIME64', 1)
 endif
 
@@ -485,7 +492,23 @@ endif
 
 gst_debug = get_option('gst_debug')
 if not gst_debug
-  add_project_arguments(['-Wno-unused'], language: 'c')
+  if cc.get_argument_syntax() == 'msvc'
+    msvc_args = cc.get_supported_arguments([
+      '/wd4101', # 'identifier' : unreferenced local variable
+      '/wd4189', # 'identifier' : local variable is initialized but not referenced
+    ])
+    add_project_arguments(msvc_args, language: 'c')
+  elif cc.has_argument('-Wno-unused')
+    add_project_arguments(['-Wno-unused'], language: 'c')
+  endif
+else
+  if cc.get_argument_syntax() == 'msvc' and gst_version_is_dev
+    msvc_args = cc.get_supported_arguments([
+      '/we4101', # 'identifier' : unreferenced local variable
+      '/we4189', # 'identifier' : local variable is initialized but not referenced
+    ])
+    add_project_arguments(msvc_args, language: 'c')
+  endif
 endif
 
 warning_flags = [
@@ -531,7 +554,7 @@ configinc = include_directories('.')
 libsinc = include_directories('libs')
 privinc = include_directories('gst')
 
-glib_req = '>= 2.62.0'
+glib_req = '>= 2.64.0'
 
 # Find dependencies
 glib_dep = dependency('glib-2.0', version: glib_req,
@@ -550,6 +573,21 @@ mathlib = cc.find_library('m', required : false)
 # Also provides clock_gettime in glibc < 2.17
 rt_lib = cc.find_library('rt', required : false)
 
+#
+# Solaris and Illumos distros split a lot of networking-related code
+# into '-lsocket -lnsl'.  Anything that calls socketpair(), getifaddr(),
+# etc. probably needs to include network_deps
+#
+socket_lib = cc.find_library('socket', required: false)
+nsl_lib    = cc.find_library('nsl',    required: false)
+network_deps = []
+if socket_lib.found()
+  network_deps += socket_lib
+endif
+if nsl_lib.found()
+  network_deps += nsl_lib
+endif
+
 gir = find_program('g-ir-scanner', required : get_option('introspection'))
 gnome = import('gnome')
 
@@ -567,7 +605,8 @@ gst_c_args = ['-DHAVE_CONFIG_H']
 # FIXME: This is only needed on windows and probably breaks when
 # default_library = 'both'. We should add this flag to static_c_args instead
 # when Meson supports it: https://github.com/mesonbuild/meson/issues/3304
-if get_option('default_library') == 'static'
+
+if static_build
   gst_c_args += ['-DGST_STATIC_COMPILATION']
 endif
 
@@ -632,7 +671,7 @@ if host_system == 'darwin'
   pkgconfig_libs = ['-Wl,-rpath,${libdir}']
 endif
 
-static_build = get_option('default_library') == 'static'
+
 gst_libraries = []
 subdir('gst')
 subdir('libs')
@@ -662,7 +701,7 @@ endif
 configure_file(output : 'config.h', configuration : cdata)
 install_data('gst-element-check-1.0.m4', install_dir : join_paths(get_option('datadir'), 'aclocal'))
 
-meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version())
+meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.22.0', meson.project_version())
 
 plugin_names = []
 gst_plugins = []
diff --git a/meson_options.txt b/meson_options.txt
index 7363bdb..340fb58 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -3,6 +3,7 @@ option('gst_parse', type : 'boolean', value : true,
        description: 'Enable pipeline string parser')
 option('registry', type : 'boolean', value : true)
 option('tracer_hooks', type : 'boolean', value : true, description: 'Enable tracer usage')
+option('ptp-helper', type: 'feature', description: 'Build gst-ptp-helper')
 option('ptp-helper-setuid-user', type : 'string',
        description : 'User to switch to when installing gst-ptp-helper setuid root')
 option('ptp-helper-setuid-group', type : 'string',
@@ -23,6 +24,7 @@ option('libdw', type : 'feature', value : 'auto', description : 'Use libdw to ge
 option('dbghelp', type : 'feature', value : 'auto', description : 'Use dbghelp to generate backtraces')
 option('bash-completion', type : 'feature', value : 'auto', description : 'Install bash completion files')
 option('coretracers', type : 'feature', value : 'auto', description : 'Build coretracers plugin')
+option('gstreamer-static-full', type : 'boolean', value : false, description : 'Enable static support of gstreamer-full.')
 
 # Common feature options
 option('examples', type : 'feature', value : 'auto', yield : true)
diff --git a/plugins/elements/gstclocksync.c b/plugins/elements/gstclocksync.c
index 05258ab..0ede449 100644
--- a/plugins/elements/gstclocksync.c
+++ b/plugins/elements/gstclocksync.c
@@ -57,6 +57,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_clock_sync_debug);
 #define DEFAULT_SYNC                    TRUE
 #define DEFAULT_TS_OFFSET               0
 #define DEFAULT_SYNC_TO_FIRST           FALSE
+#define DEFAULT_QOS                     FALSE
 
 enum
 {
@@ -64,6 +65,7 @@ enum
   PROP_SYNC,
   PROP_TS_OFFSET,
   PROP_SYNC_TO_FIRST,
+  PROP_QOS,
   PROP_LAST
 };
 
@@ -89,6 +91,17 @@ G_DEFINE_TYPE_WITH_CODE (GstClockSync, gst_clock_sync, GST_TYPE_ELEMENT,
 GST_ELEMENT_REGISTER_DEFINE (clocksync, "clocksync", GST_RANK_NONE,
     GST_TYPE_CLOCKSYNC);
 
+#define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
+
+/* generic running average, this has a neutral window size */
+#define UPDATE_RUNNING_AVG(avg,val)   DO_RUNNING_AVG(avg,val,8)
+
+/* the windows for these running averages are experimentally obtained.
+ * positive values get averaged more while negative values use a small
+ * window so we can react faster to badness. */
+#define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16)
+#define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4)
+
 static void gst_clock_sync_finalize (GObject * object);
 
 static void gst_clock_sync_set_property (GObject * object, guint prop_id,
@@ -104,6 +117,8 @@ static GstFlowReturn gst_clock_sync_chain_list (GstPad * pad,
     GstObject * parent, GstBufferList * buflist);
 static gboolean gst_clock_sync_src_query (GstPad * pad, GstObject * parent,
     GstQuery * query);
+static gboolean gst_clock_sync_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
 static GstStateChangeReturn gst_clocksync_change_state (GstElement * element,
     GstStateChange transition);
 static GstClock *gst_clocksync_provide_clock (GstElement * element);
@@ -156,6 +171,19 @@ gst_clock_sync_class_init (GstClockSyncClass * klass)
       "Note that mixed use of ts-offset and this property would be racy "
       "if clocksync element is running already.",
       DEFAULT_SYNC_TO_FIRST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstClockSync:qos:
+   *
+   * Generate Quality-of-Service events upstream.
+   *
+   * Since: 1.22
+   */
+  properties[PROP_QOS] =
+      g_param_spec_boolean ("qos", "Qos",
+      "Generate Quality-of-Service events upstream", DEFAULT_QOS,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (gobject_class, PROP_LAST, properties);
 
   gstelement_class->change_state =
@@ -193,6 +221,7 @@ gst_clock_sync_init (GstClockSync * clocksync)
   gst_pad_set_chain_list_function (clocksync->sinkpad,
       GST_DEBUG_FUNCPTR (gst_clock_sync_chain_list));
   GST_PAD_SET_PROXY_CAPS (clocksync->sinkpad);
+  GST_PAD_SET_PROXY_ALLOCATION (clocksync->sinkpad);
   gst_element_add_pad (GST_ELEMENT (clocksync), clocksync->sinkpad);
 
   clocksync->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
@@ -200,11 +229,16 @@ gst_clock_sync_init (GstClockSync * clocksync)
   gst_pad_set_query_function (clocksync->srcpad, gst_clock_sync_src_query);
 
   GST_PAD_SET_PROXY_CAPS (clocksync->srcpad);
+  GST_PAD_SET_PROXY_ALLOCATION (clocksync->srcpad);
+  gst_pad_set_event_function (clocksync->srcpad,
+      GST_DEBUG_FUNCPTR (gst_clock_sync_src_event));
   gst_element_add_pad (GST_ELEMENT (clocksync), clocksync->srcpad);
 
   clocksync->ts_offset = DEFAULT_TS_OFFSET;
   clocksync->sync = DEFAULT_SYNC;
   clocksync->sync_to_first = DEFAULT_SYNC_TO_FIRST;
+
+  g_atomic_int_set (&clocksync->qos_enabled, DEFAULT_QOS);
   g_cond_init (&clocksync->blocked_cond);
 
   GST_OBJECT_FLAG_SET (clocksync, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
@@ -248,6 +282,9 @@ gst_clock_sync_set_property (GObject * object, guint prop_id,
     case PROP_SYNC_TO_FIRST:
       clocksync->sync_to_first = g_value_get_boolean (value);
       break;
+    case PROP_QOS:
+      g_atomic_int_set (&clocksync->qos_enabled, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -270,18 +307,168 @@ gst_clock_sync_get_property (GObject * object, guint prop_id,
     case PROP_SYNC_TO_FIRST:
       g_value_set_boolean (value, clocksync->sync_to_first);
       break;
+    case PROP_QOS:
+      g_value_set_boolean (value, g_atomic_int_get (&clocksync->qos_enabled));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
 }
 
+/* With STREAM_LOCK
+ * reset all qos measuring */
+static void
+gst_clock_sync_reset_qos (GstClockSync * clocksync)
+{
+  clocksync->prev_rstart = GST_CLOCK_TIME_NONE;
+  clocksync->earliest_in_time = GST_CLOCK_TIME_NONE;
+  clocksync->last_left = GST_CLOCK_TIME_NONE;
+  clocksync->avg_pt = GST_CLOCK_TIME_NONE;
+  clocksync->avg_rate = -1.0;
+  clocksync->avg_in_diff = GST_CLOCK_TIME_NONE;
+
+}
+
+static gboolean
+gst_clock_sync_send_qos (GstClockSync * clocksync, GstQOSType type,
+    gdouble proportion, GstClockTime time, GstClockTimeDiff diff)
+{
+  GstEvent *event;
+  gboolean res;
+
+  /* generate Quality-of-Service event */
+  GST_DEBUG_OBJECT (clocksync,
+      "qos: type %d, proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
+      GST_TIME_FORMAT, type, proportion, diff, GST_TIME_ARGS (time));
+
+  event = gst_event_new_qos (type, proportion, diff, time);
+
+  /* send upstream */
+  res = gst_pad_push_event (clocksync->sinkpad, event);
+
+  return res;
+}
+
+static gboolean
+gst_clock_sync_perform_qos (GstClockSync * clocksync)
+{
+  GstClockTime start;
+  GstClockTimeDiff jitter;
+  GstClockTime pt, entered;
+  GstClockTime duration;
+  gdouble rate;
+
+  start = clocksync->current_rstart;
+
+  /* if Quality-of-Service disabled, do nothing */
+  if (!g_atomic_int_get (&clocksync->qos_enabled) ||
+      !GST_CLOCK_TIME_IS_VALID (start) || !clocksync->sync) {
+
+    return FALSE;
+  }
+
+  jitter = clocksync->current_jitter;
+
+  if (jitter < 0) {
+    /* this is the time the buffer entered the clocksync */
+    if (start < -jitter)
+      entered = 0;
+    else
+      entered = start + jitter;
+  } else {
+    /* this is the time the buffer entered the clocksync */
+    entered = start + jitter;
+  }
+
+  /* Average duration between each buffer timestamps */
+  duration = clocksync->avg_in_diff;
+
+  /* if we have the time when the last buffer left us, calculate
+   * processing time */
+  if (GST_CLOCK_TIME_IS_VALID (clocksync->last_left)) {
+    if (entered > clocksync->last_left) {
+      pt = entered - clocksync->last_left;
+    } else {
+      pt = 0;
+    }
+  } else {
+    pt = clocksync->avg_pt;
+  }
+
+  GST_DEBUG_OBJECT (clocksync, "start: %" GST_TIME_FORMAT
+      ", entered %" GST_TIME_FORMAT ", pt: %" GST_TIME_FORMAT ", duration %"
+      GST_TIME_FORMAT ",jitter %" G_GINT64_FORMAT, GST_TIME_ARGS (start),
+      GST_TIME_ARGS (entered), GST_TIME_ARGS (pt), GST_TIME_ARGS (duration),
+      jitter);
+
+  GST_DEBUG_OBJECT (clocksync,
+      "avg_pt: %" GST_TIME_FORMAT ", avg_rate: %g",
+      GST_TIME_ARGS (clocksync->avg_pt), clocksync->avg_rate);
+
+  /* collect running averages. for first observations, we copy the
+   * values */
+  if (!GST_CLOCK_TIME_IS_VALID (clocksync->avg_pt))
+    clocksync->avg_pt = pt;
+  else
+    clocksync->avg_pt = UPDATE_RUNNING_AVG (clocksync->avg_pt, pt);
+
+  if (duration != -1 && duration != 0) {
+    rate =
+        gst_guint64_to_gdouble (clocksync->avg_pt) /
+        gst_guint64_to_gdouble (duration);
+  } else {
+    rate = 1.0;
+  }
+
+  if (GST_CLOCK_TIME_IS_VALID (clocksync->last_left)) {
+    if (clocksync->avg_rate < 0.0) {
+      clocksync->avg_rate = rate;
+    } else {
+      if (rate > 1.0)
+        clocksync->avg_rate = UPDATE_RUNNING_AVG_N (clocksync->avg_rate, rate);
+      else
+        clocksync->avg_rate = UPDATE_RUNNING_AVG_P (clocksync->avg_rate, rate);
+    }
+  }
+
+  GST_DEBUG_OBJECT (clocksync,
+      "updated: avg_pt: %" GST_TIME_FORMAT
+      ", avg_rate: %g", GST_TIME_ARGS (clocksync->avg_pt), clocksync->avg_rate);
+
+  if (clocksync->avg_rate >= 0.0) {
+    GstQOSType type;
+    GstClockTimeDiff diff;
+
+    /* if we have a valid rate, start sending QoS messages */
+    if (clocksync->current_jitter < 0) {
+      /* make sure we never go below 0 when adding the jitter to the
+       * timestamp. */
+      if (clocksync->current_rstart < -clocksync->current_jitter)
+        clocksync->current_jitter = -clocksync->current_rstart;
+    }
+
+    diff = clocksync->current_jitter;
+    if (diff <= 0)
+      type = GST_QOS_TYPE_OVERFLOW;
+    else
+      type = GST_QOS_TYPE_UNDERFLOW;
+
+    gst_clock_sync_send_qos (clocksync, type, clocksync->avg_rate,
+        clocksync->current_rstart, diff);
+  }
+
+  return TRUE;
+}
+
 static GstFlowReturn
 gst_clocksync_do_sync (GstClockSync * clocksync, GstClockTime running_time)
 {
   GstFlowReturn ret = GST_FLOW_OK;
   GstClock *clock;
 
+  clocksync->current_rstart = GST_CLOCK_TIME_NONE;
+
   if (!clocksync->sync)
     return GST_FLOW_OK;
 
@@ -355,7 +542,29 @@ gst_clocksync_do_sync (GstClockSync * clocksync, GstClockTime running_time)
     }
     if (cret == GST_CLOCK_UNSCHEDULED || clocksync->flushing)
       ret = GST_FLOW_FLUSHING;
+
+    clocksync->current_jitter = jitter;
   }
+
+  clocksync->current_rstart = running_time;
+  /* calculate inter frame spacing */
+  if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (clocksync->prev_rstart) &&
+          clocksync->prev_rstart < running_time)) {
+    GstClockTime in_diff;
+
+    in_diff = running_time - clocksync->prev_rstart;
+
+    if (clocksync->avg_in_diff == -1)
+      clocksync->avg_in_diff = in_diff;
+    else
+      clocksync->avg_in_diff =
+          UPDATE_RUNNING_AVG (clocksync->avg_in_diff, in_diff);
+
+    GST_LOG_OBJECT (clocksync, "avg frame diff %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (clocksync->avg_in_diff));
+  }
+  clocksync->prev_rstart = running_time;
+
   GST_OBJECT_UNLOCK (clocksync);
 
   return ret;
@@ -374,6 +583,8 @@ gst_clock_sync_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
     case GST_EVENT_SEGMENT:
       /* store the event for synching */
       gst_event_copy_segment (event, &clocksync->segment);
+
+      gst_clock_sync_reset_qos (clocksync);
       break;
     case GST_EVENT_GAP:
     {
@@ -406,6 +617,7 @@ gst_clock_sync_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       clocksync->flushing = FALSE;
       gst_segment_init (&clocksync->segment, GST_FORMAT_UNDEFINED);
       GST_OBJECT_UNLOCK (clocksync);
+      gst_clock_sync_reset_qos (clocksync);
       clocksync->is_first = TRUE;
       break;
     default:
@@ -417,6 +629,31 @@ gst_clock_sync_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
   return ret;
 }
 
+static gboolean
+gst_clock_sync_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+  GstClockSync *clocksync = GST_CLOCKSYNC (parent);
+
+  GST_LOG_OBJECT (clocksync, "Received %s event: %" GST_PTR_FORMAT,
+      GST_EVENT_TYPE_NAME (event), event);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_QOS:
+      if (g_atomic_int_get (&clocksync->qos_enabled)) {
+        GST_LOG_OBJECT (clocksync,
+            "Dropping downstream QoS event as we are responsible for handling QoS");
+        gst_event_unref (event);
+        return TRUE;
+      }
+      break;
+    default:
+      break;
+  }
+
+  /* Always handle all events as normal: */
+  return gst_pad_event_default (pad, parent, event);
+}
+
 static void
 gst_clock_sync_update_ts_offset (GstClockSync * clocksync,
     GstClockTime runtimestamp)
@@ -456,6 +693,7 @@ gst_clock_sync_update_ts_offset (GstClockSync * clocksync,
 static GstFlowReturn
 gst_clock_sync_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
 {
+  gboolean performed_qos = FALSE;
   GstClockSync *clocksync = GST_CLOCKSYNC (parent);
   GstFlowReturn ret = GST_FLOW_OK;
 
@@ -495,16 +733,25 @@ gst_clock_sync_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
       gst_buffer_unref (buf);
       return ret;
     }
+
+    performed_qos = gst_clock_sync_perform_qos (clocksync);
   }
 
   /* Forward the buffer */
-  return gst_pad_push (clocksync->srcpad, buf);
+  ret = gst_pad_push (clocksync->srcpad, buf);
+
+  if (performed_qos)
+    clocksync->last_left =
+        gst_element_get_current_running_time (GST_ELEMENT (parent));
+
+  return ret;
 }
 
 static GstFlowReturn
 gst_clock_sync_chain_list (GstPad * pad, GstObject * parent,
     GstBufferList * buffer_list)
 {
+  gboolean performed_qos = FALSE;
   GstClockSync *clocksync = GST_CLOCKSYNC (parent);
   GstFlowReturn ret = GST_FLOW_OK;
   GstBuffer *buf;
@@ -538,11 +785,19 @@ gst_clock_sync_chain_list (GstPad * pad, GstObject * parent,
       gst_buffer_list_unref (buffer_list);
       return ret;
     }
+
+    performed_qos = gst_clock_sync_perform_qos (clocksync);
   }
 
   /* Forward the buffer list */
 done:
-  return gst_pad_push_list (clocksync->srcpad, buffer_list);
+  ret = gst_pad_push_list (clocksync->srcpad, buffer_list);
+
+  if (performed_qos)
+    clocksync->last_left =
+        gst_element_get_current_running_time (GST_ELEMENT (parent));
+
+  return ret;
 }
 
 static gboolean
@@ -647,6 +902,7 @@ gst_clocksync_change_state (GstElement * element, GstStateChange transition)
       GST_OBJECT_UNLOCK (clocksync);
       if (clocksync->sync)
         no_preroll = TRUE;
+      gst_clock_sync_reset_qos (clocksync);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       break;
diff --git a/plugins/elements/gstclocksync.h b/plugins/elements/gstclocksync.h
index 647d73e..5467a62 100644
--- a/plugins/elements/gstclocksync.h
+++ b/plugins/elements/gstclocksync.h
@@ -63,6 +63,23 @@ struct _GstClockSync
   gboolean is_first;
 
   GstClockTime   upstream_latency;
+
+  /* QoS */
+  gboolean qos_enabled;
+  // With STREAM_LOCK {
+  GstClockTime earliest_in_time;
+  GstClockTime current_rstart;
+  GstClockTimeDiff current_jitter;
+  GstClockTime avg_pt, avg_in_diff;
+  gdouble avg_rate;             /* average with infinite window */
+
+  /* when the last buffer left the sink, running time */
+  GstClockTime last_left;
+
+  /* the running time of the previous buffer */
+  GstClockTime prev_rstart;
+
+  // } With STREAM_LOCK
 };
 
 struct _GstClockSyncClass
diff --git a/plugins/elements/gstconcat.c b/plugins/elements/gstconcat.c
index afa6b53..207ad42 100644
--- a/plugins/elements/gstconcat.c
+++ b/plugins/elements/gstconcat.c
@@ -311,8 +311,6 @@ gst_concat_request_new_pad (GstElement * element, GstPadTemplate * templ,
   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_CAPS);
   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_ALLOCATION);
 
-  gst_pad_set_active (sinkpad, TRUE);
-
   g_mutex_lock (&self->lock);
   self->sinkpads = g_list_prepend (self->sinkpads, gst_object_ref (sinkpad));
   if (!self->current_sinkpad) {
diff --git a/plugins/elements/gstdownloadbuffer.c b/plugins/elements/gstdownloadbuffer.c
index 2a6232f..b25aadf 100644
--- a/plugins/elements/gstdownloadbuffer.c
+++ b/plugins/elements/gstdownloadbuffer.c
@@ -1007,6 +1007,8 @@ gst_download_buffer_handle_sink_event (GstPad * pad, GstObject * parent,
 
   dlbuf = GST_DOWNLOAD_BUFFER (parent);
 
+  GST_DEBUG_OBJECT (dlbuf, "%" GST_PTR_FORMAT, event);
+
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_START:
     {
@@ -1323,8 +1325,10 @@ gst_download_buffer_loop (GstPad * pad)
   GST_DOWNLOAD_BUFFER_MUTEX_LOCK_CHECK (dlbuf, dlbuf->srcresult, out_flushing);
 
   ret = gst_download_buffer_read_buffer (dlbuf, -1, -1, &buffer);
-  if (ret != GST_FLOW_OK)
+  if (ret != GST_FLOW_OK) {
+    dlbuf->srcresult = ret;
     goto out_flushing;
+  }
 
   if (dlbuf->stream_start_event != NULL) {
     gst_pad_push_event (dlbuf->srcpad, dlbuf->stream_start_event);
@@ -1384,10 +1388,7 @@ gst_download_buffer_handle_src_event (GstPad * pad, GstObject * parent,
   gboolean res = TRUE;
   GstDownloadBuffer *dlbuf = GST_DOWNLOAD_BUFFER (parent);
 
-#ifndef GST_DISABLE_GST_DEBUG
-  GST_DEBUG_OBJECT (dlbuf, "got event %p (%s)",
-      event, GST_EVENT_TYPE_NAME (event));
-#endif
+  GST_DEBUG_OBJECT (dlbuf, "%" GST_PTR_FORMAT, event);
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_START:
@@ -1731,6 +1732,7 @@ gst_download_buffer_src_activate_push (GstPad * pad, GstObject * parent,
     dlbuf->srcresult = GST_FLOW_OK;
     dlbuf->sinkresult = GST_FLOW_OK;
     dlbuf->unexpected = FALSE;
+    dlbuf->upstream_size = -1;
     result =
         gst_pad_start_task (pad, (GstTaskFunction) gst_download_buffer_loop,
         pad, NULL);
@@ -1770,7 +1772,7 @@ gst_download_buffer_src_activate_pull (GstPad * pad, GstObject * parent,
     dlbuf->srcresult = GST_FLOW_OK;
     dlbuf->sinkresult = GST_FLOW_OK;
     dlbuf->unexpected = FALSE;
-    dlbuf->upstream_size = 0;
+    dlbuf->upstream_size = -1;
     GST_DOWNLOAD_BUFFER_MUTEX_UNLOCK (dlbuf);
   } else {
     GST_DOWNLOAD_BUFFER_MUTEX_LOCK (dlbuf);
diff --git a/plugins/elements/gstelements_private.c b/plugins/elements/gstelements_private.c
index ea50373..aa158e4 100644
--- a/plugins/elements/gstelements_private.c
+++ b/plugins/elements/gstelements_private.c
@@ -540,6 +540,10 @@ gst_writev_buffer_list (GstObject * sink, gint fd, GstPoll * fdset,
         current_buf_mem_idx = 0;
     }
     current_buf_idx = i;
+    if (current_buf_mem_idx != 0) {
+      g_assert (current_buf_idx > 0);
+      current_buf_idx--;
+    }
   }
 
   do {
@@ -629,6 +633,10 @@ gst_writev_buffer_list (GstObject * sink, gint fd, GstPoll * fdset,
           current_buf_mem_idx = 0;
       }
       current_buf_idx = i;
+      if (current_buf_mem_idx != 0) {
+        g_assert (current_buf_idx > 0);
+        current_buf_idx--;
+      }
     }
   } while (left > 0);
 
diff --git a/plugins/elements/gstfilesink.c b/plugins/elements/gstfilesink.c
index d5808fd..0491080 100644
--- a/plugins/elements/gstfilesink.c
+++ b/plugins/elements/gstfilesink.c
@@ -81,6 +81,29 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS_ANY);
 
+#define GST_TYPE_FILE_SINK_FILE_MODE (gst_file_sink_file_mode_get_type())
+static GType
+gst_file_sink_file_mode_get_type (void)
+{
+  static GType file_mode_type = 0;
+
+  if (g_once_init_enter (&file_mode_type)) {
+    static const GEnumValue file_mode[] = {
+      {GST_FILE_SINK_FILE_MODE_TRUNC, "Truncate file (mode wb)", "truncate"},
+      {GST_FILE_SINK_FILE_MODE_APPEND, "Append file (mode ab)", "output"},
+      {GST_FILE_SINK_FILE_MODE_OVERWRITE,
+          "Overwrite file without truncating (mode rb+)", "overwrite"},
+      {0, NULL, NULL}
+    };
+
+    GType new_file_mode_type =
+        g_enum_register_static ("GstFileSinkFileMode", file_mode);
+
+    g_once_init_leave (&file_mode_type, new_file_mode_type);
+  }
+  return file_mode_type;
+}
+
 #define GST_TYPE_FILE_SINK_BUFFER_MODE (gst_file_sink_buffer_mode_get_type ())
 static GType
 gst_file_sink_buffer_mode_get_type (void)
@@ -111,6 +134,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_file_sink_debug);
 #define DEFAULT_APPEND		FALSE
 #define DEFAULT_O_SYNC		FALSE
 #define DEFAULT_MAX_TRANSIENT_ERROR_TIMEOUT	0
+#define DEFAULT_FILE_MODE      GST_FILE_SINK_FILE_MODE_TRUNC
 
 enum
 {
@@ -121,6 +145,7 @@ enum
   PROP_APPEND,
   PROP_O_SYNC,
   PROP_MAX_TRANSIENT_ERROR_TIMEOUT,
+  PROP_FILE_MODE,
   PROP_LAST
 };
 
@@ -145,6 +170,8 @@ gst_fopen (const gchar * filename, const gchar * mode, gboolean o_sync)
     flags |= O_TRUNC;
   else if (strcmp (mode, "ab") == 0)
     flags |= O_APPEND;
+  else if (strcmp (mode, "rb+") == 0)
+    flags |= O_RDWR;
   else
     g_assert_not_reached ();
 
@@ -230,6 +257,18 @@ gst_file_sink_class_init (GstFileSinkClass * klass)
           G_MAXUINT, DEFAULT_BUFFER_SIZE,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  /**
+   * GstFileSink:file-mode
+   *
+   * Ability to specify file mode.
+   *
+   * Since: 1.24
+   */
+  g_object_class_install_property (gobject_class, PROP_FILE_MODE,
+      g_param_spec_enum ("file-mode", "File Mode",
+          "Specify file mode used to open file", GST_TYPE_FILE_SINK_FILE_MODE,
+          DEFAULT_FILE_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   /**
    * GstFileSink:append
    *
@@ -238,7 +277,7 @@ gst_file_sink_class_init (GstFileSinkClass * klass)
   g_object_class_install_property (gobject_class, PROP_APPEND,
       g_param_spec_boolean ("append", "Append",
           "Append to an already existing file", DEFAULT_APPEND,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
 
   g_object_class_install_property (gobject_class, PROP_O_SYNC,
       g_param_spec_boolean ("o-sync", "Synchronous IO",
@@ -276,6 +315,7 @@ gst_file_sink_class_init (GstFileSinkClass * klass)
   }
 
   gst_type_mark_as_plugin_api (GST_TYPE_FILE_SINK_BUFFER_MODE, 0);
+  gst_type_mark_as_plugin_api (GST_TYPE_FILE_SINK_FILE_MODE, 0);
 }
 
 static void
@@ -287,6 +327,7 @@ gst_file_sink_init (GstFileSink * filesink)
   filesink->buffer_mode = DEFAULT_BUFFER_MODE;
   filesink->buffer_size = DEFAULT_BUFFER_SIZE;
   filesink->append = FALSE;
+  filesink->file_mode = DEFAULT_FILE_MODE;
 
   gst_base_sink_set_sync (GST_BASE_SINK (filesink), FALSE);
 }
@@ -358,6 +399,9 @@ gst_file_sink_set_property (GObject * object, guint prop_id,
     case PROP_APPEND:
       sink->append = g_value_get_boolean (value);
       break;
+    case PROP_FILE_MODE:
+      sink->file_mode = g_value_get_enum (value);
+      break;
     case PROP_O_SYNC:
       sink->o_sync = g_value_get_boolean (value);
       break;
@@ -389,6 +433,9 @@ gst_file_sink_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_APPEND:
       g_value_set_boolean (value, sink->append);
       break;
+    case PROP_FILE_MODE:
+      g_value_set_enum (value, sink->file_mode);
+      break;
     case PROP_O_SYNC:
       g_value_set_boolean (value, sink->o_sync);
       break;
@@ -408,8 +455,10 @@ gst_file_sink_open_file (GstFileSink * sink)
   if (sink->filename == NULL || sink->filename[0] == '\0')
     goto no_filename;
 
-  if (sink->append)
+  if (sink->append || sink->file_mode == GST_FILE_SINK_FILE_MODE_APPEND)
     sink->file = gst_fopen (sink->filename, "ab", sink->o_sync);
+  else if (sink->file_mode == GST_FILE_SINK_FILE_MODE_OVERWRITE)
+    sink->file = gst_fopen (sink->filename, "rb+", sink->o_sync);
   else
     sink->file = gst_fopen (sink->filename, "wb", sink->o_sync);
   if (sink->file == NULL)
diff --git a/plugins/elements/gstfilesink.h b/plugins/elements/gstfilesink.h
index bc479c5..aef04c8 100644
--- a/plugins/elements/gstfilesink.h
+++ b/plugins/elements/gstfilesink.h
@@ -30,7 +30,6 @@
 #include <gst/base/gstbasesink.h>
 
 G_BEGIN_DECLS
-
 #define GST_TYPE_FILE_SINK \
   (gst_file_sink_get_type())
 #define GST_FILE_SINK(obj) \
@@ -62,6 +61,22 @@ typedef enum {
   GST_FILE_SINK_BUFFER_MODE_UNBUFFERED = _IONBF
 } GstFileSinkBufferMode;
 
+/**
+ * GstFileSinkFileMode:
+ * @FILESINK_FILE_MODE_TRUNC: Default file mode (wb)
+ * @FILESINK_FILE_MODE_APPEND: Append file mode (ab)
+ * @FILESINK_FILE_MODE_OVERWRITE: Overwrite file mode (rb+)
+ *
+ * File write mode.
+ *
+ * Since: 1.24
+ */
+typedef enum {
+  GST_FILE_SINK_FILE_MODE_TRUNC     = 1,
+  GST_FILE_SINK_FILE_MODE_APPEND    = 2,
+  GST_FILE_SINK_FILE_MODE_OVERWRITE = 3,
+} GstFileSinkFileMode;
+
 /**
  * GstFileSink:
  *
@@ -84,6 +99,8 @@ struct _GstFileSink {
   /* For default buffer mode */
   GstBufferList *buffer_list;
 
+  gint  file_mode;
+
   /* For full buffer mode */
   guint8 *buffer;
   gsize   allocated_buffer_size;
diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c
index 5dfe014..01d2ff6 100644
--- a/plugins/elements/gstfilesrc.c
+++ b/plugins/elements/gstfilesrc.c
@@ -57,6 +57,9 @@
 /* Prevent stat.h from defining the stat* functions as
  * _stat*, since we're explicitly overriding that */
 #undef _INC_STAT_INL
+#ifdef HAVE__SET_THREAD_LOCAL_INVALID_PARAMETER_HANDLER
+#include <stdlib.h>
+#endif
 #endif
 
 #include <fcntl.h>
@@ -403,6 +406,35 @@ gst_file_src_is_seekable (GstBaseSrc * basesrc)
   return src->seekable;
 }
 
+#ifdef G_OS_WIN32
+#ifdef HAVE__SET_THREAD_LOCAL_INVALID_PARAMETER_HANDLER
+static void __cdecl
+gst_file_src_win32_iph (wchar_t const *exp, wchar_t const *func,
+    wchar_t const *file, unsigned int line, uintptr_t reserved)
+{
+  /* Do nothing */
+}
+
+static HANDLE
+gst_file_src_win32_get_osfhandle (int fd)
+{
+  HANDLE handle;
+  _invalid_parameter_handler old_iph =
+      _set_thread_local_invalid_parameter_handler (gst_file_src_win32_iph);
+  handle = (HANDLE) _get_osfhandle (fd);
+  _set_thread_local_invalid_parameter_handler (old_iph);
+
+  return handle;
+}
+#else /* HAVE__SET_THREAD_LOCAL_INVALID_PARAMETER_HANDLER */
+static HANDLE
+gst_file_src_win32_get_osfhandle (int fd)
+{
+  return (HANDLE) _get_osfhandle (fd);
+}
+#endif /* HAVE__SET_THREAD_LOCAL_INVALID_PARAMETER_HANDLER */
+#endif /* G_OS_WIN32 */
+
 static gboolean
 gst_file_src_get_size (GstBaseSrc * basesrc, guint64 * size)
 {
@@ -417,7 +449,7 @@ gst_file_src_get_size (GstBaseSrc * basesrc, guint64 * size)
   }
 #ifdef G_OS_WIN32
   {
-    HANDLE h = (HANDLE) _get_osfhandle (src->fd);
+    HANDLE h = gst_file_src_win32_get_osfhandle (src->fd);
     LARGE_INTEGER file_size;
 
     if (h == INVALID_HANDLE_VALUE)
@@ -472,7 +504,7 @@ gst_file_src_start (GstBaseSrc * basesrc)
 
 #ifdef G_OS_WIN32
   {
-    HANDLE h = (HANDLE) _get_osfhandle (src->fd);
+    HANDLE h = gst_file_src_win32_get_osfhandle (src->fd);
     FILE_STANDARD_INFO file_info;
 
     if (h == INVALID_HANDLE_VALUE)
diff --git a/plugins/elements/gstfunnel.c b/plugins/elements/gstfunnel.c
index cdb22c9..b09dbf1 100644
--- a/plugins/elements/gstfunnel.c
+++ b/plugins/elements/gstfunnel.c
@@ -238,8 +238,6 @@ gst_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ,
   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_CAPS);
   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_ALLOCATION);
 
-  gst_pad_set_active (sinkpad, TRUE);
-
   gst_element_add_pad (element, sinkpad);
 
   GST_DEBUG_OBJECT (element, "requested pad %s:%s",
diff --git a/plugins/elements/gstidentity.c b/plugins/elements/gstidentity.c
index ab577b7..e3063b9 100644
--- a/plugins/elements/gstidentity.c
+++ b/plugins/elements/gstidentity.c
@@ -569,14 +569,16 @@ gst_identity_src_event (GstBaseTransform * trans, GstEvent * event)
           &start, &stop_type, &stop);
 
       GST_OBJECT_LOCK (identity);
-      gst_segment_init (&identity->seek_segment, fmt);
-      if (!gst_segment_do_seek (&identity->seek_segment, rate, fmt,
-              flags, start_type, start, stop_type, stop, NULL)) {
-        GST_WARNING_OBJECT (identity, "Could not run seek %" GST_PTR_FORMAT,
-            event);
-        GST_OBJECT_UNLOCK (identity);
-
-        return FALSE;
+      if (identity->single_segment) {
+        gst_segment_init (&identity->seek_segment, fmt);
+        if (!gst_segment_do_seek (&identity->seek_segment, rate, fmt,
+                flags, start_type, start, stop_type, stop, NULL)) {
+          GST_WARNING_OBJECT (identity, "Could not handle %" GST_PTR_FORMAT,
+              event);
+          GST_OBJECT_UNLOCK (identity);
+
+          return FALSE;
+        }
       }
       GST_OBJECT_UNLOCK (identity);
 
diff --git a/plugins/elements/gstinputselector.c b/plugins/elements/gstinputselector.c
index ac8470e..ac6735d 100644
--- a/plugins/elements/gstinputselector.c
+++ b/plugins/elements/gstinputselector.c
@@ -361,7 +361,7 @@ static GstSelectorPadCachedBuffer *
 gst_selector_pad_new_cached_buffer (GstSelectorPad * selpad, GstBuffer * buffer)
 {
   GstSelectorPadCachedBuffer *cached_buffer =
-      g_slice_new (GstSelectorPadCachedBuffer);
+      g_new (GstSelectorPadCachedBuffer, 1);
   cached_buffer->buffer = buffer;
   cached_buffer->segment = selpad->segment;
   return cached_buffer;
@@ -372,7 +372,7 @@ gst_selector_pad_free_cached_buffer (GstSelectorPadCachedBuffer * cached_buffer)
 {
   if (cached_buffer->buffer)
     gst_buffer_unref (cached_buffer->buffer);
-  g_slice_free (GstSelectorPadCachedBuffer, cached_buffer);
+  g_free (cached_buffer);
 }
 
 /* must be called with the SELECTOR_LOCK */
@@ -839,6 +839,13 @@ gst_input_selector_wait_running_time (GstInputSelector * sel,
       GstClockTimeDiff jitter;
       GstClockID clock_id;
 
+      if (!sel->playing) {
+        GST_DEBUG_OBJECT (selpad, "Waiting for playing");
+        GST_INPUT_SELECTOR_WAIT (sel);
+        GST_DEBUG_OBJECT (selpad, "Done waiting");
+        continue;
+      }
+
       base_time = gst_element_get_base_time (GST_ELEMENT_CAST (sel));
       if (!GST_CLOCK_TIME_IS_VALID (base_time)) {
         GST_DEBUG_OBJECT (selpad, "sync-mode=clock but no base time. Blocking");
@@ -1432,6 +1439,7 @@ gst_input_selector_init (GstInputSelector * sel)
   g_mutex_init (&sel->lock);
   g_cond_init (&sel->cond);
   sel->eos = FALSE;
+  sel->playing = FALSE;
 
   sel->upstream_latency = 0;
   sel->last_output_ts = GST_CLOCK_TIME_NONE;
@@ -1534,7 +1542,7 @@ gst_input_selector_set_property (GObject * object, guint prop_id,
 
       GST_INPUT_SELECTOR_LOCK (sel);
 
-      sel->active_sinkpad_from_user = ! !pad;
+      sel->active_sinkpad_from_user = !!pad;
 #if DEBUG_CACHED_BUFFERS
       gst_input_selector_debug_cached_buffers (sel);
 #endif
@@ -1934,7 +1942,6 @@ gst_input_selector_request_new_pad (GstElement * element,
 
   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_CAPS);
   GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_FLAG_PROXY_ALLOCATION);
-  gst_pad_set_active (sinkpad, TRUE);
   GST_INPUT_SELECTOR_UNLOCK (sel);
   gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
 
@@ -2029,9 +2036,20 @@ gst_input_selector_change_state (GstElement * element,
       GST_INPUT_SELECTOR_BROADCAST (self);
       GST_INPUT_SELECTOR_UNLOCK (self);
       break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:{
+      GST_INPUT_SELECTOR_LOCK (self);
+      self->playing = TRUE;
+      GST_INPUT_SELECTOR_BROADCAST (self);
+      GST_INPUT_SELECTOR_UNLOCK (self);
+      break;
+    }
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:{
       GList *walk;
 
+      GST_INPUT_SELECTOR_LOCK (self);
+      self->playing = FALSE;
+      GST_INPUT_SELECTOR_BROADCAST (self);
+      GST_OBJECT_LOCK (self);
       for (walk = GST_ELEMENT_CAST (self)->sinkpads; walk;
           walk = g_list_next (walk)) {
         GstSelectorPad *selpad = GST_SELECTOR_PAD_CAST (walk->data);
@@ -2040,6 +2058,8 @@ gst_input_selector_change_state (GstElement * element,
           gst_clock_id_unschedule (selpad->clock_id);
         }
       }
+      GST_OBJECT_UNLOCK (self);
+      GST_INPUT_SELECTOR_UNLOCK (self);
       break;
     }
     default:
diff --git a/plugins/elements/gstinputselector.h b/plugins/elements/gstinputselector.h
index 039f628..35e008b 100644
--- a/plugins/elements/gstinputselector.h
+++ b/plugins/elements/gstinputselector.h
@@ -81,6 +81,7 @@ struct _GstInputSelector {
   gboolean eos;
   gboolean eos_sent;
   gboolean flushing;
+  gboolean playing;
 
   GstClockTime upstream_latency;
   GstClockTime last_output_ts;
diff --git a/plugins/elements/gstmultiqueue.c b/plugins/elements/gstmultiqueue.c
index cf4edc8..1f2bf82 100644
--- a/plugins/elements/gstmultiqueue.c
+++ b/plugins/elements/gstmultiqueue.c
@@ -141,12 +141,10 @@ struct _GstSingleQueue
   /* segments */
   GstSegment sink_segment;
   GstSegment src_segment;
-  gboolean has_src_segment;     /* preferred over initializing the src_segment to
-                                 * UNDEFINED as this doesn't requires adding ifs
-                                 * in every segment usage */
 
   /* position of src/sink */
   GstClockTimeDiff sinktime, srctime;
+  GstClockTimeDiff sink_start_time;
   /* cached input value, used for interleave */
   GstClockTimeDiff cached_sinktime;
   /* TRUE if either position needs to be recalculated */
@@ -1147,42 +1145,31 @@ gst_multi_queue_get_property (GObject * object, guint prop_id,
 static GstIterator *
 gst_multi_queue_iterate_internal_links (GstPad * pad, GstObject * parent)
 {
+  GstSingleQueue *sq = GST_MULTIQUEUE_PAD (pad)->sq;
   GstIterator *it = NULL;
-  GstPad *opad, *sinkpad, *srcpad;
-  GstSingleQueue *squeue;
-  GstMultiQueue *mq = GST_MULTI_QUEUE (parent);
-  GValue val = { 0, };
+  GstPad *opad;
 
-  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
-  squeue = GST_MULTIQUEUE_PAD (pad)->sq;
-  if (!squeue)
-    goto out;
-
-  srcpad = g_weak_ref_get (&squeue->srcpad);
-  sinkpad = g_weak_ref_get (&squeue->sinkpad);
-  if (sinkpad == pad && srcpad) {
-    opad = srcpad;
-    gst_clear_object (&sinkpad);
+  switch (GST_PAD_DIRECTION (pad)) {
+    case GST_PAD_SRC:
+      opad = g_weak_ref_get (&sq->sinkpad);
+      break;
 
-  } else if (srcpad == pad && sinkpad) {
-    opad = sinkpad;
-    gst_clear_object (&srcpad);
+    case GST_PAD_SINK:
+      opad = g_weak_ref_get (&sq->srcpad);
+      break;
 
-  } else {
-    gst_clear_object (&srcpad);
-    gst_clear_object (&sinkpad);
-    goto out;
+    default:
+      g_return_val_if_reached (NULL);
   }
 
-  g_value_init (&val, GST_TYPE_PAD);
-  g_value_set_object (&val, opad);
-  it = gst_iterator_new_single (GST_TYPE_PAD, &val);
-  g_value_unset (&val);
-
-  gst_object_unref (opad);
+  if (opad) {
+    GValue val = G_VALUE_INIT;
 
-out:
-  GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
+    g_value_init (&val, GST_TYPE_PAD);
+    g_value_take_object (&val, opad);
+    it = gst_iterator_new_single (GST_TYPE_PAD, &val);
+    g_value_unset (&val);
+  }
 
   return it;
 }
@@ -1370,8 +1357,6 @@ gst_single_queue_pause (GstMultiQueue * mq, GstSingleQueue * sq)
     gst_object_unref (srcpad);
   }
 
-  sq->sink_tainted = sq->src_tainted = TRUE;
-
   return result;
 }
 
@@ -1386,7 +1371,6 @@ gst_single_queue_stop (GstMultiQueue * mq, GstSingleQueue * sq)
     result = gst_pad_stop_task (srcpad);
     gst_object_unref (srcpad);
   }
-  sq->sink_tainted = sq->src_tainted = TRUE;
 
   return result;
 }
@@ -1416,7 +1400,6 @@ gst_single_queue_flush (GstMultiQueue * mq, GstSingleQueue * sq, gboolean flush,
     GST_MULTI_QUEUE_MUTEX_LOCK (mq);
     gst_segment_init (&sq->sink_segment, GST_FORMAT_TIME);
     gst_segment_init (&sq->src_segment, GST_FORMAT_TIME);
-    sq->has_src_segment = FALSE;
     /* All pads start off OK for a smooth kick-off */
     sq->srcresult = GST_FLOW_OK;
     sq->pushed = FALSE;
@@ -1427,6 +1410,9 @@ gst_single_queue_flush (GstMultiQueue * mq, GstSingleQueue * sq, gboolean flush,
     sq->nextid = 0;
     sq->oldid = 0;
     sq->last_oldid = G_MAXUINT32;
+    sq->sinktime = GST_CLOCK_STIME_NONE;
+    sq->srctime = GST_CLOCK_STIME_NONE;
+    sq->sink_start_time = GST_CLOCK_STIME_NONE;
     sq->next_time = GST_CLOCK_STIME_NONE;
     sq->last_time = GST_CLOCK_STIME_NONE;
     sq->cached_sinktime = GST_CLOCK_STIME_NONE;
@@ -1440,6 +1426,8 @@ gst_single_queue_flush (GstMultiQueue * mq, GstSingleQueue * sq, gboolean flush,
     mq->high_time = GST_CLOCK_STIME_NONE;
 
     sq->flushing = FALSE;
+
+    sq->sink_tainted = sq->src_tainted = FALSE;
     GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
   }
 }
@@ -1709,7 +1697,7 @@ calculate_interleave (GstMultiQueue * mq, GstSingleQueue * sq)
 static void
 update_time_level (GstMultiQueue * mq, GstSingleQueue * sq)
 {
-  GstClockTimeDiff sink_time, src_time;
+  GstClockTimeDiff sink_time, src_time, sink_start_time;
 
   if (sq->sink_tainted) {
     sink_time = sq->sinktime = my_segment_to_running_time (&sq->sink_segment,
@@ -1727,56 +1715,48 @@ update_time_level (GstMultiQueue * mq, GstSingleQueue * sq)
        * we set the last_time */
       sq->last_time = sink_time;
     }
-    if (G_UNLIKELY (sink_time != GST_CLOCK_STIME_NONE)) {
+
+    sq->sink_tainted = FALSE;
+    if (sink_time != GST_CLOCK_STIME_NONE) {
       /* if we have a time, we become untainted and use the time */
-      sq->sink_tainted = FALSE;
       if (mq->use_interleave) {
         sq->cached_sinktime = sink_time;
         calculate_interleave (mq, sq);
       }
     }
-  } else
+  } else {
     sink_time = sq->sinktime;
+  }
 
-  if (sq->src_tainted) {
-    GstSegment *segment;
-    gint64 position;
-
-    if (sq->has_src_segment) {
-      segment = &sq->src_segment;
-      position = sq->src_segment.position;
-    } else {
-      /*
-       * If the src pad had no segment yet, use the sink segment
-       * to avoid signalling overrun if the received sink segment has a
-       * a position > max-size-time while the src pad time would be the default=0
-       *
-       * This can happen when switching pads on chained/adaptive streams and the
-       * new chain has a segment with a much larger position
-       */
-      segment = &sq->sink_segment;
-      position = sq->sink_segment.position;
-    }
+  sink_start_time = sq->sink_start_time;
 
-    src_time = sq->srctime = my_segment_to_running_time (segment, position);
-    /* if we have a time, we become untainted and use the time */
-    if (G_UNLIKELY (src_time != GST_CLOCK_STIME_NONE)) {
-      sq->src_tainted = FALSE;
-    }
-  } else
+  if (sq->src_tainted) {
+    src_time = sq->srctime = my_segment_to_running_time (&sq->src_segment,
+        sq->src_segment.position);
+    sq->src_tainted = FALSE;
+  } else {
     src_time = sq->srctime;
+  }
 
   GST_DEBUG_ID (sq->debug_id,
-      "sink %" GST_STIME_FORMAT ", src %" GST_STIME_FORMAT,
-      GST_STIME_ARGS (sink_time), GST_STIME_ARGS (src_time));
-
-  /* This allows for streams with out of order timestamping - sometimes the
-   * emerging timestamp is later than the arriving one(s) */
-  if (G_LIKELY (GST_CLOCK_STIME_IS_VALID (sink_time) &&
-          GST_CLOCK_STIME_IS_VALID (src_time) && sink_time > src_time))
-    sq->cur_time = sink_time - src_time;
-  else
+      "sink %" GST_STIME_FORMAT ", src %" GST_STIME_FORMAT
+      ", sink-start-time %" GST_STIME_FORMAT, GST_STIME_ARGS (sink_time),
+      GST_STIME_ARGS (src_time), GST_STIME_ARGS (sink_start_time));
+
+  if (GST_CLOCK_STIME_IS_VALID (sink_time)) {
+    if (!GST_CLOCK_STIME_IS_VALID (src_time) &&
+        GST_CLOCK_STIME_IS_VALID (sink_start_time) &&
+        sink_time >= sink_start_time) {
+      /* If we got input buffers but output thread didn't push any buffer yet */
+      sq->cur_time = sink_time - sink_start_time;
+    } else if (GST_CLOCK_STIME_IS_VALID (src_time) && sink_time >= src_time) {
+      sq->cur_time = sink_time - src_time;
+    } else {
+      sq->cur_time = 0;
+    }
+  } else {
     sq->cur_time = 0;
+  }
 
   /* updating the time level can change the buffering state */
   update_buffering (mq, sq);
@@ -1784,22 +1764,22 @@ update_time_level (GstMultiQueue * mq, GstSingleQueue * sq)
   return;
 }
 
-/* take a SEGMENT event and apply the values to segment, updating the time
- * level of queue. */
+/* take a SEGMENT event and apply the values to segment */
 static void
 apply_segment (GstMultiQueue * mq, GstSingleQueue * sq, GstEvent * event,
     GstSegment * segment)
 {
   GstClockTimeDiff ppos = 0;
+  gboolean is_sink = segment == &sq->sink_segment;
 
   /* If we switched groups, grab the previous position */
   if (segment->rate > 0.0) {
-    if (segment == &sq->sink_segment && sq->sink_stream_gid_changed) {
+    if (is_sink && sq->sink_stream_gid_changed) {
       ppos =
           gst_segment_to_running_time (segment, GST_FORMAT_TIME,
           segment->position);
       sq->sink_stream_gid_changed = FALSE;
-    } else if (segment == &sq->src_segment && sq->src_stream_gid_changed) {
+    } else if (!is_sink && sq->src_stream_gid_changed) {
       ppos =
           gst_segment_to_running_time (segment, GST_FORMAT_TIME,
           segment->position);
@@ -1834,21 +1814,17 @@ apply_segment (GstMultiQueue * mq, GstSingleQueue * sq, GstEvent * event,
   else
     segment->position = segment->stop;
 
-  if (segment == &sq->sink_segment)
-    sq->sink_tainted = TRUE;
+  /* Will be updated on buffer flows */
+  if (is_sink)
+    sq->sink_tainted = FALSE;
   else {
-    sq->has_src_segment = TRUE;
-    sq->src_tainted = TRUE;
+    sq->src_tainted = FALSE;
   }
 
   GST_DEBUG_ID (sq->debug_id,
       "configured SEGMENT %" GST_SEGMENT_FORMAT, segment);
 
-  /* segment can update the time level of the queue */
-  update_time_level (mq, sq);
-
   GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
-  gst_multi_queue_post_buffering (mq);
 }
 
 /* take a buffer and update segment, updating the time level of the queue. */
@@ -1856,23 +1832,36 @@ static void
 apply_buffer (GstMultiQueue * mq, GstSingleQueue * sq, GstClockTime timestamp,
     GstClockTime duration, GstSegment * segment)
 {
+  gboolean is_sink = segment == &sq->sink_segment;
+
   GST_MULTI_QUEUE_MUTEX_LOCK (mq);
 
-  /* if no timestamp is set, assume it's continuous with the previous
-   * time */
-  if (timestamp == GST_CLOCK_TIME_NONE)
-    timestamp = segment->position;
+  /* if no timestamp is set, assume it didn't change compared to the previous
+   * buffer and simply return here. Non-time limits might have still changed
+   * and a buffering message might have to be posted */
+  if (timestamp == GST_CLOCK_TIME_NONE) {
+    update_buffering (mq, sq);
+    GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
+    gst_multi_queue_post_buffering (mq);
+    return;
+  }
+
+  if (is_sink && !GST_CLOCK_STIME_IS_VALID (sq->sink_start_time)) {
+    sq->sink_start_time = my_segment_to_running_time (segment, timestamp);
+    GST_DEBUG_ID (sq->debug_id, "Start time updated to %" GST_STIME_FORMAT,
+        GST_STIME_ARGS (sq->sink_start_time));
+  }
 
   /* add duration */
   if (duration != GST_CLOCK_TIME_NONE)
     timestamp += duration;
 
   GST_DEBUG_ID (sq->debug_id, "%s position updated to %" GST_TIME_FORMAT,
-      segment == &sq->sink_segment ? "sink" : "src", GST_TIME_ARGS (timestamp));
+      is_sink ? "sink" : "src", GST_TIME_ARGS (timestamp));
 
   segment->position = timestamp;
 
-  if (segment == &sq->sink_segment)
+  if (is_sink)
     sq->sink_tainted = TRUE;
   else
     sq->src_tainted = TRUE;
@@ -1889,32 +1878,37 @@ apply_gap (GstMultiQueue * mq, GstSingleQueue * sq, GstEvent * event,
 {
   GstClockTime timestamp;
   GstClockTime duration;
-
-  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
+  gboolean is_sink = segment == &sq->sink_segment;
 
   gst_event_parse_gap (event, &timestamp, &duration);
 
-  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+  g_return_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp));
 
-    if (GST_CLOCK_TIME_IS_VALID (duration)) {
-      timestamp += duration;
-    }
+  GST_MULTI_QUEUE_MUTEX_LOCK (mq);
 
-    GST_DEBUG_ID (sq->debug_id,
-        "%s position updated to %" GST_TIME_FORMAT,
-        segment == &sq->sink_segment ? "sink" : "src",
-        GST_TIME_ARGS (timestamp));
+  if (is_sink && !GST_CLOCK_STIME_IS_VALID (sq->sink_start_time)) {
+    sq->sink_start_time = my_segment_to_running_time (segment, timestamp);
+    GST_DEBUG_ID (sq->debug_id, "Start time updated to %" GST_STIME_FORMAT,
+        GST_STIME_ARGS (sq->sink_start_time));
+  }
 
-    segment->position = timestamp;
+  if (GST_CLOCK_TIME_IS_VALID (duration)) {
+    timestamp += duration;
+  }
 
-    if (segment == &sq->sink_segment)
-      sq->sink_tainted = TRUE;
-    else
-      sq->src_tainted = TRUE;
+  GST_DEBUG_ID (sq->debug_id,
+      "%s position updated to %" GST_TIME_FORMAT,
+      is_sink ? "sink" : "src", GST_TIME_ARGS (timestamp));
 
-    /* calc diff with other end */
-    update_time_level (mq, sq);
-  }
+  segment->position = timestamp;
+
+  if (is_sink)
+    sq->sink_tainted = TRUE;
+  else
+    sq->src_tainted = TRUE;
+
+  /* calc diff with other end */
+  update_time_level (mq, sq);
 
   GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
   gst_multi_queue_post_buffering (mq);
@@ -2051,8 +2045,6 @@ gst_single_queue_push_one (GstMultiQueue * mq, GstSingleQueue * sq,
       }
       case GST_EVENT_SEGMENT:
         apply_segment (mq, sq, event, &sq->src_segment);
-        /* Applying the segment may have made the queue non-full again, unblock it if needed */
-        gst_data_queue_limits_changed (sq->queue);
         if (G_UNLIKELY (*allow_drop)) {
           result = GST_FLOW_OK;
           *allow_drop = FALSE;
@@ -2086,7 +2078,6 @@ gst_single_queue_push_one (GstMultiQueue * mq, GstSingleQueue * sq,
 
     if (G_UNLIKELY (*allow_drop)) {
       GST_DEBUG_ID (sq->debug_id, "Dropping EOS query %p", query);
-      gst_query_unref (query);
       res = FALSE;
     } else {
       res = gst_pad_peer_query (srcpad, query);
@@ -2124,7 +2115,7 @@ gst_multi_queue_item_destroy (GstMultiQueueItem * item)
 {
   if (!item->is_query && item->object)
     gst_mini_object_unref (item->object);
-  g_slice_free (GstMultiQueueItem, item);
+  g_free (item);
 }
 
 /* takes ownership of passed mini object! */
@@ -2133,7 +2124,7 @@ gst_multi_queue_buffer_item_new (GstMiniObject * object, guint32 curid)
 {
   GstMultiQueueItem *item;
 
-  item = g_slice_new (GstMultiQueueItem);
+  item = g_new (GstMultiQueueItem, 1);
   item->object = object;
   item->destroy = (GDestroyNotify) gst_multi_queue_item_destroy;
   item->posid = curid;
@@ -2152,7 +2143,7 @@ gst_multi_queue_mo_item_new (GstMiniObject * object, guint32 curid)
 {
   GstMultiQueueItem *item;
 
-  item = g_slice_new (GstMultiQueueItem);
+  item = g_new (GstMultiQueueItem, 1);
   item->object = object;
   item->destroy = (GDestroyNotify) gst_multi_queue_item_destroy;
   item->posid = curid;
@@ -2407,11 +2398,9 @@ next:
     /* pretend we have not seen EOS yet for upstream's sake */
     result = sq->srcresult;
   } else if (dropping && gst_data_queue_is_empty (sq->queue)) {
-    /* queue empty, so stop dropping
-     * we can commit the result we have now,
+    /* queue empty. we can commit the result we have now,
      * which is either OK after a segment, or EOS */
     GST_DEBUG_ID (sq->debug_id, "committed EOS drop");
-    dropping = FALSE;
     result = GST_FLOW_EOS;
   }
   sq->srcresult = result;
@@ -2648,6 +2637,7 @@ gst_multi_queue_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
   GstEventType type;
   GstEvent *sref = NULL;
   GstPad *srcpad;
+  gboolean is_timed_event = FALSE;
 
 
   sq = GST_MULTIQUEUE_PAD (pad)->sq;
@@ -2732,6 +2722,7 @@ gst_multi_queue_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
           GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
         }
       }
+      is_timed_event = TRUE;
       break;
 
     default:
@@ -2755,8 +2746,13 @@ gst_multi_queue_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       "Enqueuing event %p of type %s with id %d",
       event, GST_EVENT_TYPE_NAME (event), curid);
 
-  if (!gst_data_queue_push (sq->queue, (GstDataQueueItem *) item))
-    goto flushing;
+  if (is_timed_event) {
+    if (!gst_data_queue_push (sq->queue, (GstDataQueueItem *) item))
+      goto flushing;
+  } else {
+    if (!gst_data_queue_push_force (sq->queue, (GstDataQueueItem *) item))
+      goto flushing;
+  }
 
   /* mark EOS when we received one, we must do that after putting the
    * buffer in the queue because EOS marks the buffer as filled. */
@@ -2964,6 +2960,34 @@ gst_multi_queue_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
   }
 
   switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_LATENCY:
+    {
+      GstClockTime latency = GST_CLOCK_TIME_NONE;
+      gst_event_parse_latency (event, &latency);
+      if (GST_CLOCK_TIME_IS_VALID (latency)) {
+        GST_MULTI_QUEUE_MUTEX_LOCK (mq);
+        if (latency > mq->min_interleave_time) {
+          /* Due to the dynamic nature of multiqueue, whe `use-interleave` is
+           * used we can't report a maximum tolerated latency (when queried)
+           * since it is calculated dynamically.
+           *
+           * When in such live pipelines, we need to make sure multiqueue can
+           * handle the lowest global latency (provided by this event). Failure
+           * to do that would result in not providing enough buffering for a
+           * realtime pipeline.
+           */
+          GST_DEBUG_OBJECT (mq,
+              "Raising minimum interleave time to %" GST_TIME_FORMAT,
+              GST_TIME_ARGS (latency));
+          mq->min_interleave_time = latency;
+          if (mq->use_interleave)
+            calculate_interleave (mq, NULL);
+        }
+        GST_MULTI_QUEUE_MUTEX_UNLOCK (mq);
+      }
+      ret = gst_pad_push_event (sinkpad, event);
+    }
+      break;
     case GST_EVENT_RECONFIGURE:
       GST_MULTI_QUEUE_MUTEX_LOCK (mq);
       if (sq->srcresult == GST_FLOW_NOT_LINKED) {
@@ -3541,8 +3565,9 @@ gst_single_queue_new (GstMultiQueue * mqueue, guint id)
 
   sq->sinktime = GST_CLOCK_STIME_NONE;
   sq->srctime = GST_CLOCK_STIME_NONE;
-  sq->sink_tainted = TRUE;
-  sq->src_tainted = TRUE;
+  sq->sink_start_time = GST_CLOCK_STIME_NONE;
+  sq->sink_tainted = FALSE;
+  sq->src_tainted = FALSE;
 
   sq->sink_stream_gid = sq->src_stream_gid = GST_GROUP_ID_INVALID;
   sq->sink_stream_gid_changed = FALSE;
diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c
index 6955d63..b65da32 100644
--- a/plugins/elements/gstqueue.c
+++ b/plugins/elements/gstqueue.c
@@ -472,9 +472,10 @@ gst_queue_init (GstQueue * queue)
 
   queue->sinktime = GST_CLOCK_STIME_NONE;
   queue->srctime = GST_CLOCK_STIME_NONE;
+  queue->sink_start_time = GST_CLOCK_STIME_NONE;
 
-  queue->sink_tainted = TRUE;
-  queue->src_tainted = TRUE;
+  queue->sink_tainted = FALSE;
+  queue->src_tainted = FALSE;
 
   queue->newseg_applied_to_src = FALSE;
 
@@ -528,7 +529,7 @@ my_segment_to_running_time (GstSegment * segment, GstClockTime val)
 static void
 update_time_level (GstQueue * queue)
 {
-  gint64 sink_time, src_time;
+  gint64 sink_time, src_time, sink_start_time;
 
   if (queue->sink_tainted) {
     GST_LOG_OBJECT (queue, "update sink time");
@@ -538,6 +539,7 @@ update_time_level (GstQueue * queue)
     queue->sink_tainted = FALSE;
   }
   sink_time = queue->sinktime;
+  sink_start_time = queue->sink_start_time;
 
   if (queue->src_tainted) {
     GST_LOG_OBJECT (queue, "update src time");
@@ -548,21 +550,31 @@ update_time_level (GstQueue * queue)
   }
   src_time = queue->srctime;
 
-  GST_LOG_OBJECT (queue, "sink %" GST_STIME_FORMAT ", src %" GST_STIME_FORMAT,
-      GST_STIME_ARGS (sink_time), GST_STIME_ARGS (src_time));
-
-  if (GST_CLOCK_STIME_IS_VALID (src_time)
-      && GST_CLOCK_STIME_IS_VALID (sink_time) && sink_time >= src_time)
-    queue->cur_level.time = sink_time - src_time;
-  else
+  GST_LOG_OBJECT (queue, "sink %" GST_STIME_FORMAT ", src %" GST_STIME_FORMAT
+      ", sink-start-time %" GST_STIME_FORMAT,
+      GST_STIME_ARGS (sink_time), GST_STIME_ARGS (src_time),
+      GST_STIME_ARGS (sink_start_time));
+
+  if (GST_CLOCK_STIME_IS_VALID (sink_time)) {
+    if (!GST_CLOCK_STIME_IS_VALID (src_time) &&
+        GST_CLOCK_STIME_IS_VALID (sink_start_time) &&
+        sink_time >= sink_start_time) {
+      /* If we got input buffers but output thread didn't push any buffer yet */
+      queue->cur_level.time = sink_time - sink_start_time;
+    } else if (GST_CLOCK_STIME_IS_VALID (src_time) && sink_time >= src_time) {
+      queue->cur_level.time = sink_time - src_time;
+    } else {
+      queue->cur_level.time = 0;
+    }
+  } else {
     queue->cur_level.time = 0;
+  }
 }
 
-/* take a SEGMENT event and apply the values to segment, updating the time
- * level of queue. */
+/* take a SEGMENT event and apply the values to segment */
 static void
 apply_segment (GstQueue * queue, GstEvent * event, GstSegment * segment,
-    gboolean sink)
+    gboolean is_sink)
 {
   gst_event_copy_segment (event, segment);
 
@@ -576,15 +588,15 @@ apply_segment (GstQueue * queue, GstEvent * event, GstSegment * segment,
     segment->stop = -1;
     segment->time = 0;
   }
-  if (sink)
-    queue->sink_tainted = TRUE;
-  else
-    queue->src_tainted = TRUE;
 
-  GST_DEBUG_OBJECT (queue, "configured SEGMENT %" GST_SEGMENT_FORMAT, segment);
+  /* Will be updated on buffer flows */
+  if (is_sink) {
+    queue->sink_tainted = FALSE;
+  } else {
+    queue->src_tainted = FALSE;
+  }
 
-  /* segment can update the time level of the queue */
-  update_time_level (queue);
+  GST_DEBUG_OBJECT (queue, "configured SEGMENT %" GST_SEGMENT_FORMAT, segment);
 }
 
 static void
@@ -596,63 +608,79 @@ apply_gap (GstQueue * queue, GstEvent * event,
 
   gst_event_parse_gap (event, &timestamp, &duration);
 
-  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+  g_return_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp));
 
-    if (GST_CLOCK_TIME_IS_VALID (duration)) {
-      timestamp += duration;
-    }
+  if (is_sink && !GST_CLOCK_STIME_IS_VALID (queue->sink_start_time)) {
+    queue->sink_start_time = my_segment_to_running_time (segment, timestamp);
+    GST_DEBUG_OBJECT (queue, "Start time updated to %" GST_STIME_FORMAT,
+        GST_STIME_ARGS (queue->sink_start_time));
+  }
 
-    segment->position = timestamp;
+  if (GST_CLOCK_TIME_IS_VALID (duration)) {
+    timestamp += duration;
+  }
 
-    if (is_sink)
-      queue->sink_tainted = TRUE;
-    else
-      queue->src_tainted = TRUE;
+  segment->position = timestamp;
 
-    /* calc diff with other end */
-    update_time_level (queue);
-  }
+  if (is_sink)
+    queue->sink_tainted = TRUE;
+  else
+    queue->src_tainted = TRUE;
+
+  /* calc diff with other end */
+  update_time_level (queue);
 }
 
 
 /* take a buffer and update segment, updating the time level of the queue. */
 static void
 apply_buffer (GstQueue * queue, GstBuffer * buffer, GstSegment * segment,
-    gboolean sink)
+    gboolean is_sink)
 {
   GstClockTime duration, timestamp;
 
   timestamp = GST_BUFFER_DTS_OR_PTS (buffer);
   duration = GST_BUFFER_DURATION (buffer);
 
-  /* if no timestamp is set, assume it's continuous with the previous
-   * time */
+  /* if no timestamp is set, assume it didn't change compared to the previous
+   * buffer and simply return here */
   if (timestamp == GST_CLOCK_TIME_NONE)
-    timestamp = segment->position;
+    return;
+
+  if (is_sink && !GST_CLOCK_STIME_IS_VALID (queue->sink_start_time) &&
+      GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    queue->sink_start_time = my_segment_to_running_time (segment, timestamp);
+    GST_DEBUG_OBJECT (queue, "Start time updated to %" GST_STIME_FORMAT,
+        GST_STIME_ARGS (queue->sink_start_time));
+  }
 
   /* add duration */
   if (duration != GST_CLOCK_TIME_NONE)
     timestamp += duration;
 
   GST_LOG_OBJECT (queue, "%s position updated to %" GST_TIME_FORMAT,
-      segment == &queue->sink_segment ? "sink" : "src",
-      GST_TIME_ARGS (timestamp));
+      is_sink ? "sink" : "src", GST_TIME_ARGS (timestamp));
 
   segment->position = timestamp;
-  if (sink)
+  if (is_sink)
     queue->sink_tainted = TRUE;
   else
     queue->src_tainted = TRUE;
 
-
   /* calc diff with other end */
   update_time_level (queue);
 }
 
+typedef struct
+{
+  GstClockTime first_timestamp;
+  GstClockTime timestamp;
+} BufListData;
+
 static gboolean
 buffer_list_apply_time (GstBuffer ** buf, guint idx, gpointer user_data)
 {
-  GstClockTime *timestamp = user_data;
+  BufListData *data = user_data;
   GstClockTime btime;
 
   GST_TRACE ("buffer %u has pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT
@@ -661,13 +689,18 @@ buffer_list_apply_time (GstBuffer ** buf, guint idx, gpointer user_data)
       GST_TIME_ARGS (GST_BUFFER_DURATION (*buf)));
 
   btime = GST_BUFFER_DTS_OR_PTS (*buf);
-  if (GST_CLOCK_TIME_IS_VALID (btime))
-    *timestamp = btime;
+  if (GST_CLOCK_TIME_IS_VALID (btime)) {
+    if (!GST_CLOCK_TIME_IS_VALID (data->first_timestamp))
+      data->first_timestamp = btime;
+
+    data->timestamp = btime;
+  }
 
-  if (GST_BUFFER_DURATION_IS_VALID (*buf))
-    *timestamp += GST_BUFFER_DURATION (*buf);
+  if (GST_BUFFER_DURATION_IS_VALID (*buf)
+      && GST_CLOCK_TIME_IS_VALID (data->timestamp))
+    data->timestamp += GST_BUFFER_DURATION (*buf);
 
-  GST_TRACE ("ts now %" GST_TIME_FORMAT, GST_TIME_ARGS (*timestamp));
+  GST_TRACE ("ts now %" GST_TIME_FORMAT, GST_TIME_ARGS (data->timestamp));
 
   return TRUE;
 }
@@ -675,21 +708,35 @@ buffer_list_apply_time (GstBuffer ** buf, guint idx, gpointer user_data)
 /* take a buffer list and update segment, updating the time level of the queue */
 static void
 apply_buffer_list (GstQueue * queue, GstBufferList * buffer_list,
-    GstSegment * segment, gboolean sink)
+    GstSegment * segment, gboolean is_sink)
 {
-  GstClockTime timestamp;
+  BufListData data;
+
+  data.first_timestamp = GST_CLOCK_TIME_NONE;
 
-  /* if no timestamp is set, assume it's continuous with the previous time */
-  timestamp = segment->position;
+  /* if no timestamp is set, assume it didn't change compared to the previous
+   * buffer and simply return here without updating */
+  data.timestamp = GST_CLOCK_TIME_NONE;
 
-  gst_buffer_list_foreach (buffer_list, buffer_list_apply_time, &timestamp);
+  gst_buffer_list_foreach (buffer_list, buffer_list_apply_time, &data);
+
+  if (!GST_CLOCK_TIME_IS_VALID (data.timestamp))
+    return;
+
+  if (is_sink && !GST_CLOCK_STIME_IS_VALID (queue->sink_start_time) &&
+      GST_CLOCK_TIME_IS_VALID (data.first_timestamp)) {
+    queue->sink_start_time = my_segment_to_running_time (segment,
+        data.first_timestamp);
+    GST_DEBUG_OBJECT (queue, "Start time updated to %" GST_STIME_FORMAT,
+        GST_STIME_ARGS (queue->sink_start_time));
+  }
 
   GST_DEBUG_OBJECT (queue, "position updated to %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (timestamp));
+      GST_TIME_ARGS (data.timestamp));
 
-  segment->position = timestamp;
+  segment->position = data.timestamp;
 
-  if (sink)
+  if (is_sink)
     queue->sink_tainted = TRUE;
   else
     queue->src_tainted = TRUE;
@@ -727,7 +774,8 @@ gst_queue_locked_flush (GstQueue * queue, gboolean full)
   queue->head_needs_discont = queue->tail_needs_discont = FALSE;
 
   queue->sinktime = queue->srctime = GST_CLOCK_STIME_NONE;
-  queue->sink_tainted = queue->src_tainted = TRUE;
+  queue->sink_start_time = GST_CLOCK_STIME_NONE;
+  queue->sink_tainted = queue->src_tainted = FALSE;
 
   /* we deleted a lot of something */
   GST_QUEUE_SIGNAL_DEL (queue);
@@ -1556,7 +1604,11 @@ out_flushing:
     gst_pad_pause_task (queue->srcpad);
     GST_CAT_LOG_OBJECT (queue_dataflow, queue,
         "pause task, reason:  %s", gst_flow_get_name (ret));
-    if (ret == GST_FLOW_FLUSHING) {
+
+    /* flush internal queue except for not-linked and eos
+     * not-linked: reconfigure event will start srcpad task
+     * eos: stream-start can clear eos and will start srcpad task again */
+    if (ret != GST_FLOW_NOT_LINKED && ret != GST_FLOW_EOS) {
       gst_queue_locked_flush (queue, FALSE);
     } else {
       GST_QUEUE_SIGNAL_DEL (queue);
diff --git a/plugins/elements/gstqueue.h b/plugins/elements/gstqueue.h
index 2a9cb36..cc632ad 100644
--- a/plugins/elements/gstqueue.h
+++ b/plugins/elements/gstqueue.h
@@ -99,6 +99,7 @@ struct _GstQueue {
 
   /* position of src/sink */
   GstClockTimeDiff sinktime, srctime;
+  GstClockTimeDiff sink_start_time;
   /* TRUE if either position needs to be recalculated */
   gboolean sink_tainted, src_tainted;
 
diff --git a/plugins/elements/gstqueue2.c b/plugins/elements/gstqueue2.c
index d50435c..82cb148 100644
--- a/plugins/elements/gstqueue2.c
+++ b/plugins/elements/gstqueue2.c
@@ -264,7 +264,6 @@ static GParamSpec *obj_props[PROP_LAST] = { NULL, };
 #define SET_PERCENT(q, perc) G_STMT_START {                              \
   if (perc != q->buffering_percent) {                                    \
     q->buffering_percent = perc;                                         \
-    q->percent_changed = TRUE;                                           \
     GST_DEBUG_OBJECT (q, "buffering %d percent", perc);                  \
     get_buffering_stats (q, perc, &q->mode, &q->avg_in, &q->avg_out,     \
         &q->buffering_left);                                             \
@@ -320,8 +319,6 @@ static gboolean gst_queue2_is_filled (GstQueue2 * queue);
 
 static void update_cur_level (GstQueue2 * queue, GstQueue2Range * range);
 static void update_in_rates (GstQueue2 * queue, gboolean force);
-static GstMessage *gst_queue2_get_buffering_message (GstQueue2 * queue,
-    gint * percent);
 static void update_buffering (GstQueue2 * queue);
 static void gst_queue2_post_buffering (GstQueue2 * queue);
 
@@ -538,8 +535,9 @@ gst_queue2_init (GstQueue2 * queue)
 
   queue->sinktime = GST_CLOCK_TIME_NONE;
   queue->srctime = GST_CLOCK_TIME_NONE;
-  queue->sink_tainted = TRUE;
-  queue->src_tainted = TRUE;
+  queue->sink_start_time = GST_CLOCK_TIME_NONE;
+  queue->sink_tainted = FALSE;
+  queue->src_tainted = FALSE;
 
   queue->srcresult = GST_FLOW_FLUSHING;
   queue->sinkresult = GST_FLOW_FLUSHING;
@@ -625,9 +623,16 @@ debug_ranges (GstQueue2 * queue)
 static void
 clean_ranges (GstQueue2 * queue)
 {
+  GstQueue2Range *r, *next;
+
   GST_DEBUG_OBJECT (queue, "clean queue ranges");
 
-  g_slice_free_chain (GstQueue2Range, queue->ranges, next);
+  r = queue->ranges;
+  while (r != NULL) {
+    next = r->next;
+    g_free (r);
+    r = next;
+  }
   queue->ranges = NULL;
   queue->current = NULL;
 }
@@ -692,7 +697,7 @@ add_range (GstQueue2 * queue, guint64 offset, gboolean update_existing)
     GST_DEBUG_OBJECT (queue,
         "new range %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, offset, offset);
 
-    range = g_slice_new0 (GstQueue2Range);
+    range = g_new0 (GstQueue2Range, 1);
     range->offset = offset;
     /* we want to write to the next location in the ring buffer */
     range->rb_offset = queue->current ? queue->current->rb_writing_pos : 0;
@@ -762,19 +767,29 @@ update_time_level (GstQueue2 * queue)
     queue->src_tainted = FALSE;
   }
 
-  GST_DEBUG_OBJECT (queue, "sink %" GST_TIME_FORMAT ", src %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (queue->sinktime), GST_TIME_ARGS (queue->srctime));
-
-  if (queue->sinktime != GST_CLOCK_TIME_NONE
-      && queue->srctime != GST_CLOCK_TIME_NONE
-      && queue->sinktime >= queue->srctime)
-    queue->cur_level.time = queue->sinktime - queue->srctime;
-  else
+  GST_DEBUG_OBJECT (queue, "sink %" GST_TIME_FORMAT ", src %" GST_TIME_FORMAT
+      ", sink-start-time %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (queue->sinktime), GST_TIME_ARGS (queue->srctime),
+      GST_TIME_ARGS (queue->sink_start_time));
+
+  if (GST_CLOCK_TIME_IS_VALID (queue->sinktime)) {
+    if (!GST_CLOCK_TIME_IS_VALID (queue->srctime) &&
+        GST_CLOCK_TIME_IS_VALID (queue->sink_start_time) &&
+        queue->sinktime >= queue->sink_start_time) {
+      /* If we got input buffers but output thread didn't push any buffer yet */
+      queue->cur_level.time = queue->sinktime - queue->sink_start_time;
+    } else if (GST_CLOCK_TIME_IS_VALID (queue->srctime) &&
+        queue->sinktime >= queue->srctime) {
+      queue->cur_level.time = queue->sinktime - queue->srctime;
+    } else {
+      queue->cur_level.time = 0;
+    }
+  } else {
     queue->cur_level.time = 0;
+  }
 }
 
-/* take a SEGMENT event and apply the values to segment, updating the time
- * level of queue. */
+/* take a SEGMENT event and apply the values to segment */
 static void
 apply_segment (GstQueue2 * queue, GstEvent * event, GstSegment * segment,
     gboolean is_sink)
@@ -801,13 +816,11 @@ apply_segment (GstQueue2 * queue, GstEvent * event, GstSegment * segment,
 
   GST_DEBUG_OBJECT (queue, "configured SEGMENT %" GST_SEGMENT_FORMAT, segment);
 
+  /* Will be updated on buffer flows */
   if (is_sink)
-    queue->sink_tainted = TRUE;
+    queue->sink_tainted = FALSE;
   else
-    queue->src_tainted = TRUE;
-
-  /* segment can update the time level of the queue */
-  update_time_level (queue);
+    queue->src_tainted = FALSE;
 }
 
 static void
@@ -819,22 +832,28 @@ apply_gap (GstQueue2 * queue, GstEvent * event,
 
   gst_event_parse_gap (event, &timestamp, &duration);
 
-  if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+  g_return_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp));
 
-    if (GST_CLOCK_TIME_IS_VALID (duration)) {
-      timestamp += duration;
-    }
+  if (is_sink && !GST_CLOCK_TIME_IS_VALID (queue->sink_start_time)) {
+    queue->sink_start_time = gst_segment_to_running_time (segment,
+        GST_FORMAT_TIME, timestamp);
+    GST_DEBUG_OBJECT (queue, "Start time updated to %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (queue->sink_start_time));
+  }
 
-    segment->position = timestamp;
+  if (GST_CLOCK_TIME_IS_VALID (duration)) {
+    timestamp += duration;
+  }
 
-    if (is_sink)
-      queue->sink_tainted = TRUE;
-    else
-      queue->src_tainted = TRUE;
+  segment->position = timestamp;
 
-    /* calc diff with other end */
-    update_time_level (queue);
-  }
+  if (is_sink)
+    queue->sink_tainted = TRUE;
+  else
+    queue->src_tainted = TRUE;
+
+  /* calc diff with other end */
+  update_time_level (queue);
 }
 
 static void
@@ -856,14 +875,15 @@ query_downstream_bitrate (GstQueue2 * queue)
 
   GST_QUEUE2_MUTEX_LOCK (queue);
   changed = queue->downstream_bitrate != downstream_bitrate;
-  queue->downstream_bitrate = downstream_bitrate;
-  GST_QUEUE2_MUTEX_UNLOCK (queue);
-
   if (changed) {
+    queue->downstream_bitrate = downstream_bitrate;
     if (queue->use_buffering)
       update_buffering (queue);
-    gst_queue2_post_buffering (queue);
+  }
+  GST_QUEUE2_MUTEX_UNLOCK (queue);
 
+  if (changed) {
+    gst_queue2_post_buffering (queue);
     g_object_notify_by_pspec (G_OBJECT (queue), obj_props[PROP_BITRATE]);
   }
 }
@@ -876,6 +896,12 @@ apply_buffer (GstQueue2 * queue, GstBuffer * buffer, GstSegment * segment,
   GstClockTime duration, timestamp;
 
   timestamp = GST_BUFFER_DTS_OR_PTS (buffer);
+
+  /* if no timestamp is set, assume it didn't change compared to the previous
+   * buffer and simply return here */
+  if (timestamp == GST_CLOCK_TIME_NONE)
+    return;
+
   duration = GST_BUFFER_DURATION (buffer);
 
   /* If we have no duration, pick one from the bitrate if we can */
@@ -899,10 +925,13 @@ apply_buffer (GstQueue2 * queue, GstBuffer * buffer, GstSegment * segment,
     }
   }
 
-  /* if no timestamp is set, assume it's continuous with the previous
-   * time */
-  if (timestamp == GST_CLOCK_TIME_NONE)
-    timestamp = segment->position;
+  if (is_sink && !GST_CLOCK_TIME_IS_VALID (queue->sink_start_time) &&
+      GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    queue->sink_start_time = gst_segment_to_running_time (segment,
+        GST_FORMAT_TIME, timestamp);
+    GST_DEBUG_OBJECT (queue, "Start time updated to %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (queue->sink_start_time));
+  }
 
   /* add duration */
   if (duration != GST_CLOCK_TIME_NONE)
@@ -924,6 +953,7 @@ apply_buffer (GstQueue2 * queue, GstBuffer * buffer, GstSegment * segment,
 
 struct BufListData
 {
+  GstClockTime first_timestamp;
   GstClockTime timestamp;
   guint bitrate;
 };
@@ -942,19 +972,23 @@ buffer_list_apply_time (GstBuffer ** buf, guint idx, gpointer data)
       GST_TIME_ARGS (GST_BUFFER_DURATION (*buf)));
 
   btime = GST_BUFFER_DTS_OR_PTS (*buf);
-  if (GST_CLOCK_TIME_IS_VALID (btime))
+  if (GST_CLOCK_TIME_IS_VALID (btime)) {
+    if (!GST_CLOCK_TIME_IS_VALID (bld->first_timestamp))
+      bld->first_timestamp = btime;
+
     *timestamp = btime;
+  }
 
-  if (GST_BUFFER_DURATION_IS_VALID (*buf))
+  if (GST_BUFFER_DURATION_IS_VALID (*buf)
+      && GST_CLOCK_TIME_IS_VALID (*timestamp)) {
     *timestamp += GST_BUFFER_DURATION (*buf);
-  else if (bld->bitrate != 0) {
+  } else if (bld->bitrate != 0 && GST_CLOCK_TIME_IS_VALID (*timestamp)) {
     guint64 size = gst_buffer_get_size (*buf);
 
     /* If we have no duration, pick one from the bitrate if we can */
     *timestamp += gst_util_uint64_scale (bld->bitrate, 8 * GST_SECOND, size);
   }
 
-
   GST_TRACE ("ts now %" GST_TIME_FORMAT, GST_TIME_ARGS (*timestamp));
   return TRUE;
 }
@@ -966,8 +1000,11 @@ apply_buffer_list (GstQueue2 * queue, GstBufferList * buffer_list,
 {
   struct BufListData bld;
 
-  /* if no timestamp is set, assume it's continuous with the previous time */
-  bld.timestamp = segment->position;
+  bld.first_timestamp = GST_CLOCK_TIME_NONE;
+
+  /* if no timestamp is set, assume it didn't change compared to the previous
+   * buffer and simply return here without updating */
+  bld.timestamp = GST_CLOCK_TIME_NONE;
 
   bld.bitrate = 0;
   if (queue->use_tags_bitrate) {
@@ -982,6 +1019,17 @@ apply_buffer_list (GstQueue2 * queue, GstBufferList * buffer_list,
 
   gst_buffer_list_foreach (buffer_list, buffer_list_apply_time, &bld);
 
+  if (!GST_CLOCK_TIME_IS_VALID (bld.timestamp))
+    return;
+
+  if (is_sink && !GST_CLOCK_TIME_IS_VALID (queue->sink_start_time) &&
+      GST_CLOCK_TIME_IS_VALID (bld.first_timestamp)) {
+    queue->sink_start_time = gst_segment_to_running_time (segment,
+        GST_FORMAT_TIME, bld.first_timestamp);
+    GST_DEBUG_OBJECT (queue, "Start time updated to %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (queue->sink_start_time));
+  }
+
   GST_DEBUG_OBJECT (queue, "last_stop updated to %" GST_TIME_FORMAT,
       GST_TIME_ARGS (bld.timestamp));
 
@@ -1130,38 +1178,6 @@ get_buffering_stats (GstQueue2 * queue, gint percent, GstBufferingMode * mode,
   }
 }
 
-/* Called with the lock taken */
-static GstMessage *
-gst_queue2_get_buffering_message (GstQueue2 * queue, gint * percent)
-{
-  GstMessage *msg = NULL;
-  if (queue->percent_changed) {
-    /* Don't change the buffering level if the sinkpad is waiting for
-     * space to become available.  This prevents the situation where,
-     * upstream is pushing buffers larger than our limits so only 1 buffer
-     * is ever in the queue at a time.
-     * Changing the level causes a buffering message to be posted saying that
-     * we are buffering which the application may pause to wait for another
-     * 100% buffering message which would be posted very soon after the
-     * waiting sink thread adds it's buffer to the queue */
-    /* FIXME: This situation above can still occur later if
-     * the sink pad is waiting to push a serialized event into the queue and
-     * the queue becomes empty for a short period of time. */
-    if (!queue->waiting_del
-        && queue->last_posted_buffering_percent != queue->buffering_percent) {
-      *percent = queue->buffering_percent;
-
-      GST_DEBUG_OBJECT (queue, "Going to post buffering: %d%%", *percent);
-      msg = gst_message_new_buffering (GST_OBJECT_CAST (queue), *percent);
-
-      gst_message_set_buffering_stats (msg, queue->mode, queue->avg_in,
-          queue->avg_out, queue->buffering_left);
-    }
-  }
-
-  return msg;
-}
-
 static void
 gst_queue2_post_buffering (GstQueue2 * queue)
 {
@@ -1169,21 +1185,34 @@ gst_queue2_post_buffering (GstQueue2 * queue)
   gint percent = -1;
 
   g_mutex_lock (&queue->buffering_post_lock);
+
   GST_QUEUE2_MUTEX_LOCK (queue);
-  msg = gst_queue2_get_buffering_message (queue, &percent);
+  /* Don't change the buffering level if the sinkpad is waiting for
+   * space to become available.  This prevents the situation where,
+   * upstream is pushing buffers larger than our limits so only 1 buffer
+   * is ever in the queue at a time.
+   * Changing the level causes a buffering message to be posted saying that
+   * we are buffering which the application may pause to wait for another
+   * 100% buffering message which would be posted very soon after the
+   * waiting sink thread adds it's buffer to the queue */
+  /* FIXME: This situation above can still occur later if
+   * the sink pad is waiting to push a serialized event into the queue and
+   * the queue becomes empty for a short period of time. */
+  if ((!queue->waiting_del || queue->buffering_percent == 100)
+      && queue->last_posted_buffering_percent != queue->buffering_percent) {
+    percent = queue->buffering_percent;
+
+    GST_DEBUG_OBJECT (queue, "Going to post buffering: %d%%", percent);
+    msg = gst_message_new_buffering (GST_OBJECT_CAST (queue), percent);
+
+    gst_message_set_buffering_stats (msg, queue->mode, queue->avg_in,
+        queue->avg_out, queue->buffering_left);
+  }
   GST_QUEUE2_MUTEX_UNLOCK (queue);
 
   if (msg != NULL) {
     if (gst_element_post_message (GST_ELEMENT_CAST (queue), msg)) {
-      GST_QUEUE2_MUTEX_LOCK (queue);
-      /* Set these states only if posting the message succeeded. Otherwise,
-       * this post attempt failed, and the next one won't be done, because
-       * gst_queue2_get_buffering_message() checks these states and decides
-       * based on their values that it won't produce a message. */
       queue->last_posted_buffering_percent = percent;
-      if (percent == queue->buffering_percent)
-        queue->percent_changed = FALSE;
-      GST_QUEUE2_MUTEX_UNLOCK (queue);
       GST_DEBUG_OBJECT (queue, "successfully posted %d%% buffering message",
           percent);
     } else
@@ -1902,7 +1931,8 @@ gst_queue2_locked_flush (GstQueue2 * queue, gboolean full, gboolean clear_temp)
   gst_segment_init (&queue->sink_segment, GST_FORMAT_TIME);
   gst_segment_init (&queue->src_segment, GST_FORMAT_TIME);
   queue->sinktime = queue->srctime = GST_CLOCK_TIME_NONE;
-  queue->sink_tainted = queue->src_tainted = TRUE;
+  queue->sink_start_time = GST_CLOCK_TIME_NONE;
+  queue->sink_tainted = queue->src_tainted = FALSE;
   if (queue->starting_segment != NULL)
     gst_event_unref (queue->starting_segment);
   queue->starting_segment = NULL;
@@ -2096,7 +2126,7 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer)
         if (range_to_destroy) {
           if (range_to_destroy == queue->ranges)
             queue->ranges = range;
-          g_slice_free (GstQueue2Range, range_to_destroy);
+          g_free (range_to_destroy);
           range_to_destroy = NULL;
         }
       }
@@ -2146,7 +2176,7 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer)
             new_writing_pos = next->writing_pos;
             do_seek = TRUE;
           }
-          g_slice_free (GstQueue2Range, next);
+          g_free (next);
         }
         goto update_and_signal;
       }
@@ -2202,37 +2232,12 @@ gst_queue2_create_write (GstQueue2 * queue, GstBuffer * buffer)
     update_cur_level (queue, queue->current);
 
     /* update the buffering status */
-    if (queue->use_buffering) {
-      GstMessage *msg;
-      gint percent = -1;
+    if (queue->use_buffering)
       update_buffering (queue);
-      msg = gst_queue2_get_buffering_message (queue, &percent);
-      if (msg) {
-        gboolean post_ok;
-
-        GST_QUEUE2_MUTEX_UNLOCK (queue);
-
-        g_mutex_lock (&queue->buffering_post_lock);
-        post_ok = gst_element_post_message (GST_ELEMENT_CAST (queue), msg);
-
-        GST_QUEUE2_MUTEX_LOCK (queue);
 
-        if (post_ok) {
-          /* Set these states only if posting the message succeeded. Otherwise,
-           * this post attempt failed, and the next one won't be done, because
-           * gst_queue2_get_buffering_message() checks these states and decides
-           * based on their values that it won't produce a message. */
-          queue->last_posted_buffering_percent = percent;
-          if (percent == queue->buffering_percent)
-            queue->percent_changed = FALSE;
-          GST_DEBUG_OBJECT (queue, "successfully posted %d%% buffering message",
-              percent);
-        } else {
-          GST_DEBUG_OBJECT (queue, "could not post buffering message");
-        }
-        g_mutex_unlock (&queue->buffering_post_lock);
-      }
-    }
+    GST_QUEUE2_MUTEX_UNLOCK (queue);
+    gst_queue2_post_buffering (queue);
+    GST_QUEUE2_MUTEX_LOCK (queue);
 
     GST_INFO_OBJECT (queue, "cur_level.bytes %u (max %" G_GUINT64_FORMAT ")",
         queue->cur_level.bytes, QUEUE_MAX_BYTES (queue));
@@ -3228,22 +3233,26 @@ out_flushing:
     GstFlowReturn ret = queue->srcresult;
 
     gst_pad_pause_task (queue->srcpad);
-    if (ret == GST_FLOW_FLUSHING) {
+
+    /* flush internal queue except for not-linked and eos
+     * not-linked: reconfigure event will start srcpad task
+     * eos: stream-start can clear eos and will start srcpad task again */
+    if (ret != GST_FLOW_NOT_LINKED && ret != GST_FLOW_EOS) {
       gst_queue2_locked_flush (queue, FALSE, FALSE);
     } else {
       GST_QUEUE2_SIGNAL_DEL (queue);
       queue->last_query = FALSE;
       g_cond_signal (&queue->query_handled);
     }
-    GST_QUEUE2_MUTEX_UNLOCK (queue);
-    GST_CAT_LOG_OBJECT (queue_dataflow, queue,
-        "pause task, reason:  %s", gst_flow_get_name (queue->srcresult));
     /* Recalculate buffering levels before stopping since the source flow
      * might cause a different buffering level (like NOT_LINKED making
      * the queue appear as full) */
     if (queue->use_buffering)
       update_buffering (queue);
+    GST_QUEUE2_MUTEX_UNLOCK (queue);
     gst_queue2_post_buffering (queue);
+    GST_CAT_LOG_OBJECT (queue_dataflow, queue,
+        "pause task, reason:  %s", gst_flow_get_name (queue->srcresult));
     /* let app know about us giving up if upstream is not expected to do so */
     /* EOS is already taken care of elsewhere */
     if (eos && (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS)) {
@@ -3734,7 +3743,7 @@ gst_queue2_src_activate_pull (GstPad * pad, GstObject * parent, gboolean active)
         result = gst_queue2_open_temp_location_file (queue);
       } else if (!queue->ring_buffer) {
         queue->ring_buffer = g_malloc (queue->ring_buffer_max_size);
-        result = ! !queue->ring_buffer;
+        result = !!queue->ring_buffer;
       } else {
         result = TRUE;
       }
diff --git a/plugins/elements/gstqueue2.h b/plugins/elements/gstqueue2.h
index 5e8fa9a..8ad8a19 100644
--- a/plugins/elements/gstqueue2.h
+++ b/plugins/elements/gstqueue2.h
@@ -86,6 +86,7 @@ struct _GstQueue2
 
   /* Position of src/sink */
   GstClockTime sinktime, srctime;
+  GstClockTime sink_start_time;
   /* TRUE if either position needs to be recalculated */
   gboolean sink_tainted, src_tainted;
   /* Bitrates taken from tags */
@@ -170,7 +171,6 @@ struct _GstQueue2
   gint64 buffering_left;
   gint avg_in;
   gint avg_out;
-  gboolean percent_changed;
   GMutex buffering_post_lock; /* assures only one posted at a time */
 };
 
diff --git a/plugins/elements/gstsparsefile.c b/plugins/elements/gstsparsefile.c
index 201f84a..6e74753 100644
--- a/plugins/elements/gstsparsefile.c
+++ b/plugins/elements/gstsparsefile.c
@@ -98,7 +98,7 @@ get_write_range (GstSparseFile * file, gsize offset)
     next = next->next;
   }
   if (result == NULL) {
-    result = g_slice_new0 (GstSparseRange);
+    result = g_new0 (GstSparseRange, 1);
     result->start = offset;
     result->stop = offset;
 
@@ -150,7 +150,7 @@ gst_sparse_file_new (void)
 {
   GstSparseFile *result;
 
-  result = g_slice_new0 (GstSparseFile);
+  result = g_new0 (GstSparseFile, 1);
   result->current_pos = 0;
   result->ranges = NULL;
   result->n_ranges = 0;
@@ -181,6 +181,17 @@ gst_sparse_file_set_fd (GstSparseFile * file, gint fd)
   return file->file != NULL;
 }
 
+static void
+gst_sparse_range_free_chain (GstSparseRange * r)
+{
+  while (r != NULL) {
+    GstSparseRange *next = r->next;
+
+    g_free (r);
+    r = next;
+  }
+}
+
 /**
  * gst_sparse_file_clear:
  * @file: a #GstSparseFile
@@ -192,7 +203,7 @@ gst_sparse_file_clear (GstSparseFile * file)
 {
   g_return_if_fail (file != NULL);
 
-  g_slice_free_chain (GstSparseRange, file->ranges, next);
+  gst_sparse_range_free_chain (file->ranges);
   file->current_pos = 0;
   file->ranges = NULL;
   file->n_ranges = 0;
@@ -216,8 +227,8 @@ gst_sparse_file_free (GstSparseFile * file)
     fflush (file->file);
     fclose (file->file);
   }
-  g_slice_free_chain (GstSparseRange, file->ranges, next);
-  g_slice_free (GstSparseFile, file);
+  gst_sparse_range_free_chain (file->ranges);
+  g_free (file);
 }
 
 /**
@@ -284,7 +295,7 @@ gst_sparse_file_write (GstSparseFile * file, gsize offset, gconstpointer data,
       file->write_range = NULL;
     if (file->read_range == next)
       file->read_range = NULL;
-    g_slice_free (GstSparseRange, next);
+    g_free (next);
     file->n_ranges--;
   }
   if (available)
@@ -319,7 +330,7 @@ error:
  * @remaining will be set to the amount of bytes remaining in the read
  * range.
  *
- * Returns: The number of bytes read of 0 on error.
+ * Returns: The number of bytes read or 0 on error.
  *
  * Since: 1.4
  */
@@ -372,7 +383,14 @@ error:
           gst_sparse_file_io_error_from_errno (errno), "Error reading file: %s",
           g_strerror (errno));
     } else if (feof (file->file)) {
+      if (res == 0) {
+        g_set_error_literal (error, GST_SPARSE_FILE_IO_ERROR,
+            GST_SPARSE_FILE_IO_ERROR_FAILED, "Error reading file: EOF");
+      }
       return res;
+    } else {
+      g_set_error_literal (error, GST_SPARSE_FILE_IO_ERROR,
+          GST_SPARSE_FILE_IO_ERROR_FAILED, "Error reading file");
     }
     return 0;
   }
diff --git a/plugins/elements/gsttypefindelement.c b/plugins/elements/gsttypefindelement.c
index 7ba30c3..6cd4e4b 100644
--- a/plugins/elements/gsttypefindelement.c
+++ b/plugins/elements/gsttypefindelement.c
@@ -490,7 +490,7 @@ gst_type_find_element_seek (GstTypeFindElement * typefind, GstEvent * event)
   gst_segment_do_seek (&seeksegment, rate, format, flags,
       start_type, start, stop_type, stop, NULL);
 
-  flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
+  flush = !!(flags & GST_SEEK_FLAG_FLUSH);
 
   GST_DEBUG_OBJECT (typefind, "New segment %" GST_SEGMENT_FORMAT, &seeksegment);
 
diff --git a/plugins/tracers/gstleaks.c b/plugins/tracers/gstleaks.c
index 35df3bc..45e5ca9 100644
--- a/plugins/tracers/gstleaks.c
+++ b/plugins/tracers/gstleaks.c
@@ -27,10 +27,16 @@
  * objects and prints a list of leaks to the debug log under `GST_TRACER:7` when
  * gst_deinit() is called, and also prints a g_warning().
  *
- * Starting with GStreamer 1.18, you can also use action signals on the tracer
+ * Starting with GStreamer 1.18, you can also use GObject action signals on the tracer
  * object to fetch leak information. Use gst_tracing_get_active_tracers() to
  * get a list of all active tracers and find the right one by name.
  *
+ * If the `GST_LEAKS_TRACER_SIG` env variable is defined, you can use the
+ * following POSIX signals to interact with the leaks tracer:
+ * - SIGUSR1: log alive objects
+ * - SIGUSR2: create a checkpoint and print a list of objects created and
+ *   destroyed since the previous checkpoint.
+ *
  * You can activate this tracer in the usual way by adding the string 'leaks'
  * to the environment variable `GST_TRACERS`. Such as: `GST_TRACERS=leaks`
  *
@@ -1039,6 +1045,7 @@ gst_leaks_tracer_activity_start_tracking (GstLeaksTracer * self)
   GST_OBJECT_LOCK (self);
   if (self->added) {
     GST_ERROR_OBJECT (self, "tracking is already in progress");
+    GST_OBJECT_UNLOCK (self);
     return;
   }
 
diff --git a/plugins/tracers/gstlog.c b/plugins/tracers/gstlog.c
index 9649998..bd89ea8 100644
--- a/plugins/tracers/gstlog.c
+++ b/plugins/tracers/gstlog.c
@@ -22,7 +22,88 @@
  * SECTION:tracer-log
  * @short_description: log hook event
  *
- * A tracing module that logs all data from all hooks.
+ * A tracing module that logs all data from all GstTracer hooks. Takes no
+ * arguments other than an optional name.
+ *
+ * ### Enabling the log tracer
+ *
+ * Enable through an environment variable: `GST_TRACERS=log` (notice
+ * the plural).
+ *
+ * You can double check the plugin has been enabled using
+ * `GST_DEBUG='*:INFO'`. You should see:
+ *
+ * ```
+ * $ GST_TRACERS="log" GST_DEBUG='*:INFO' \
+ *      gst-launch-1.0 fakesrc num-buffers=1 ! fakesink \
+ *      2>&1 | grep "enabling tracers"
+[...] _priv_gst_tracing_init: enabling tracers: 'log'
+ * ```
+ *
+ * ### Using the log tracer
+ *
+ * This tracer logs accross a number of categories at the `TRACE` level.
+ *
+ * **For this reason, you need to set `GST_DEBUG` to capture the output from
+ * this plugin.**
+ *
+ * These are the logging categories under which the different hooks operate:
+ *
+ *  * `GST_DEBUG=GST_BUFFER:TRACE`
+ *    * `pad-push-pre`, `pad-push-post`
+ *    * `pad-pull-range-pre`, `pad-pull-range-post`
+ *  * `GST_DEBUG=GST_BUFFER_LIST:TRACE`
+ *    * `pad-push-list-pre`, `pad-push-list-post`
+ *  * `GST_DEBUG=GST_EVENT:TRACE`
+ *    * `pad-push-event-pre`, `pad-push-event-post`
+ *  * `GST_DEBUG=GST_QUERY:TRACE`
+ *    * `pad-query-pre`, `pad-query-post`
+ *    * `element-query-pre`, `element-query-post`
+ *  * `GST_DEBUG=GST_MESSAGE:TRACE`
+ *    * `element-post-message-pre`, `element-post-message-post`
+ *  * `GST_DEBUG=GST_ELEMENT_FACTORY:TRACE`
+ *    * `element-new`
+ *  * `GST_DEBUG=GST_ELEMENT_PADS:TRACE`
+ *    * `element-add-pad`
+ *    * `element-remove-pad`
+ *  * `GST_DEBUG=GST_STATES:TRACE`
+ *    * `element-change-state-pre`, `element-change-state-post`
+ *  * `GST_DEBUG=GST_BIN:TRACE`
+ *    * `bin-add-pre`, `bin-add-post`
+ *    * `bin-remove-pre`, `bin-remove-post`
+ *  * `GST_DEBUG=GST_PADS:TRACE`
+ *    * `pad-link-pre`, `pad-link-post`
+ *    * `pad-unlink-pre`, `pad-unlink-post`
+ *
+ * Since the categories mentioned above are not exclusive to this tracer
+ * plugin, but are also used by core GStreamer code, you should expect a lot of
+ * unrelated logging to appear.
+ *
+ * On the other hand, the functions in this plugin have a consistent naming
+ * scheme, which should make it easy to filter the logs: `do_{hook_name}`
+ *
+ * ### Example
+ *
+ * As an example, if we wanted to log the flow of events and pads being linked
+ * we could run the following command:
+ *
+ * ```
+ * $ GST_TRACERS="log" \
+ *       GST_DEBUG=GST_EVENT:TRACE,GST_PADS:TRACE \
+ *       gst-play-1.0 file.webm \
+ *       2>&1 | egrep -w 'do_(pad_link)_(pre|post):'
+ * [...]
+ * [...] GST_PADS :0:do_pad_link_pre:<typefind:src> 0:00:00.096516923, src=<typefind:src>, sink=<matroskademux0:sink>
+ * [...] GST_PADS :0:do_pad_link_post:<typefind:src> 0:00:00.096678191, src=<typefind:src>, sink=<matroskademux0:sink>, res=0
+ * [...] GST_PADS :0:do_pad_link_pre:<matroskademux0:audio_0> 0:00:00.103133773, src=<matroskademux0:audio_0>, sink=<decodepad1:proxypad2>
+ * [...] GST_PADS :0:do_pad_link_post:<matroskademux0:audio_0> 0:00:00.103567148, src=<matroskademux0:audio_0>, sink=<decodepad1:proxypad2>, res=0
+ * [...]
+ * [...] GST_EVENT :0:do_push_event_pre:<vp8dec0:sink> 0:00:00.930848627, pad=<vp8dec0:sink>, event=qos event: 0x7fec9c00c0a0, time 99:99:99.999999999, seq-num 393, GstEventQOS, type=(GstQOSType)overflow, proportion=(double)0.036137789409526271, diff=(gint64)-29350000, timestamp=(guint64)533000000;
+ * [...] GST_EVENT :0:do_push_event_pre:<multiqueue0:sink_1> 0:00:00.930901498, pad=<multiqueue0:sink_1>, event=qos event: 0x7fec9c00c0a0, time 99:99:99.999999999, seq-num 393, GstEventQOS, type=(GstQOSType)overflow, proportion=(double)0.036137789409526271, diff=(gint64)-29350000, timestamp=(guint64)533000000;
+ * [...] GST_EVENT :0:do_push_event_post:<multiqueue0:sink_1> 0:00:00.931041882, pad=<multiqueue0:sink_1>, res=1
+ * [...] GST_EVENT :0:do_push_event_post:<vp8dec0:sink> 0:00:00.931082112, pad=<vp8dec0:sink>, res=1
+ * [...]
+ * ```
  */
 
 #ifdef HAVE_CONFIG_H
diff --git a/plugins/tracers/gstrusage.c b/plugins/tracers/gstrusage.c
index 9976ddf..c49e902 100644
--- a/plugins/tracers/gstrusage.c
+++ b/plugins/tracers/gstrusage.c
@@ -74,13 +74,13 @@ static GPrivate thread_stats_key = G_PRIVATE_INIT (free_thread_stats);
 static void
 free_trace_value (gpointer data)
 {
-  g_slice_free (GstTraceValue, data);
+  g_free (data);
 }
 
 static GstTraceValues *
 make_trace_values (GstClockTime window)
 {
-  GstTraceValues *self = g_slice_new0 (GstTraceValues);
+  GstTraceValues *self = g_new0 (GstTraceValues, 1);
   self->window = window;
   g_queue_init (&self->values);
   return self;
@@ -91,7 +91,7 @@ free_trace_values (GstTraceValues * self)
 {
   g_queue_foreach (&self->values, (GFunc) free_trace_value, NULL);
   g_queue_clear (&self->values);
-  g_slice_free (GstTraceValues, self);
+  g_free (self);
 }
 
 static gboolean
@@ -136,7 +136,7 @@ update_trace_value (GstTraceValues * self, GstClockTime nts,
   lv = q->head ? q->head->data : NULL;
   if (!lv || (GST_CLOCK_DIFF (lv->ts, nts) > (window / WINDOW_SUBDIV))) {
     /* push the new measurement */
-    lv = g_slice_new0 (GstTraceValue);
+    lv = g_new0 (GstTraceValue, 1);
     lv->ts = nts;
     lv->val = nval;
     g_queue_push_head (q, lv);
diff --git a/plugins/tracers/gststats.c b/plugins/tracers/gststats.c
index 72edd2a..d2a84c2 100644
--- a/plugins/tracers/gststats.c
+++ b/plugins/tracers/gststats.c
@@ -84,7 +84,7 @@ static GstElementStats no_elem_stats = { 0, };
 static GstElementStats *
 fill_element_stats (GstStatsTracer * self, GstElement * element)
 {
-  GstElementStats *stats = g_slice_new0 (GstElementStats);
+  GstElementStats *stats = g_new0 (GstElementStats, 1);
 
   stats->index = self->num_elements++;
   stats->parent_ix = G_MAXUINT;
@@ -103,7 +103,7 @@ log_new_element_stats (GstElementStats * stats, GstElement * element,
 static void
 free_element_stats (gpointer data)
 {
-  g_slice_free (GstElementStats, data);
+  g_free (data);
 }
 
 static GstElementStats *
@@ -186,7 +186,7 @@ static GstPadStats no_pad_stats = { 0, };
 static GstPadStats *
 fill_pad_stats (GstStatsTracer * self, GstPad * pad)
 {
-  GstPadStats *stats = g_slice_new0 (GstPadStats);
+  GstPadStats *stats = g_new0 (GstPadStats, 1);
 
   stats->index = self->num_pads++;
   stats->parent_ix = G_MAXUINT;
@@ -206,7 +206,7 @@ log_new_pad_stats (GstPadStats * stats, GstPad * pad)
 static void
 free_pad_stats (gpointer data)
 {
-  g_slice_free (GstPadStats, data);
+  g_free (data);
 }
 
 static GstPadStats *
diff --git a/po/LINGUAS b/po/LINGUAS
index acb10da..0404783 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -1 +1 @@
-af ast az be bg ca cs da de el en_GB eo es eu fi fr fur gl hr hu id it ja ka ko lt nb nl pl pt_BR ro ru rw sk sl sq sr sv tr uk vi zh_CN zh_TW
+af ast az be bg ca cs da de el en_GB eo es eu fi fr fur gl hr hu id it ja ka ko lt lv nb nl pl pt_BR ro ru rw sk sl sq sr sv tr uk vi zh_CN zh_TW
diff --git a/po/af.po b/po/af.po
index 0463914..8894a66 100644
--- a/po/af.po
+++ b/po/af.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 0.9.7\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2005-12-05 11:45+0200\n"
 "Last-Translator: Petri Jooste <rkwjpj@puk.ac.za>\n"
 "Language-Team: Afrikaans <i18n@af.org.za>\n"
@@ -57,9 +57,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Skakel ontfouting af"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Aktiveer volledige diagnostiese boodskappe vir inproplaaiing"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Dubbelpunt-geskeide paaie wat inproppe bevat"
 
@@ -831,6 +828,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1064,6 +1067,10 @@ msgstr "album wat hierdie data bevat"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr ""
 
@@ -1079,6 +1086,9 @@ msgstr ""
 msgid "conditionally available"
 msgstr ""
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1324,6 +1334,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "Moenie 'n fouthanteerder installeer nie"
 
@@ -1382,6 +1398,9 @@ msgstr "Pyplyn word gestel na NULL ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Pyplyn word gestel na NULL ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Aktiveer volledige diagnostiese boodskappe vir inproplaaiing"
+
 #~ msgid "Internal GStreamer error: state change failed."
 #~ msgstr "Interne GStreamer-fout: state change failed."
 
diff --git a/po/ast.po b/po/ast.po
index 56f56e0..d7ce697 100644
--- a/po/ast.po
+++ b/po/ast.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 0.10.28.2\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2010-06-07 22:01+0100\n"
 "Last-Translator: astur <maacub@gmail.com>\n"
 "Language-Team: Asturian <ubuntu-l10n-ast@lists.ubuntu.com>\n"
@@ -62,9 +62,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Desactivar depuración"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Activar el diagnósticu detalláu de la carga de los complementos"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Rutas separtaes por dos puntos «:», que contengan complementos"
 
@@ -837,6 +834,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1070,6 +1073,10 @@ msgstr "El fluxu nun caltién datos"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Interfaces implementaes:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "llexible"
 
@@ -1086,6 +1093,9 @@ msgstr "controlable"
 msgid "conditionally available"
 msgstr "controlable"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1337,6 +1347,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "Nun instalar un remanador de fallos"
 
@@ -1393,6 +1409,9 @@ msgstr "Afitando pipeline a NULL...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Lliberando la tubería…\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Activar el diagnósticu detalláu de la carga de los complementos"
+
 #~ msgid "link without source element"
 #~ msgstr "enllaz ensin elementos de fonte"
 
diff --git a/po/az.po b/po/az.po
index 1135c69..37fadcf 100644
--- a/po/az.po
+++ b/po/az.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer-0.8.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2004-03-19 18:40+0200\n"
 "Last-Translator: Metin Amiroff <metin@karegen.com>\n"
 "Language-Team: Azerbaijani <translation-team-az@lists.sourceforge.net>\n"
@@ -53,9 +53,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Xəta ayırmasını bağla"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr ""
-
 msgid "Colon-separated paths containing plugins"
 msgstr ""
 
@@ -792,6 +789,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1020,6 +1023,10 @@ msgstr ""
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr ""
 
@@ -1035,6 +1042,9 @@ msgstr ""
 msgid "conditionally available"
 msgstr ""
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1276,6 +1286,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr ""
 
diff --git a/po/be.po b/po/be.po
index cdc7b1f..5d78fdb 100644
--- a/po/be.po
+++ b/po/be.po
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 0.9.7\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2006-01-18 22:26+0200\n"
 "Last-Translator: Ales Nyakhaychyk <nab@mail.by>\n"
 "Language-Team: Belarusian <i18n@mova.org>\n"
@@ -57,9 +57,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Выключае адладку"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Уключае шматслоўную дыягностыку загрузкі ўтулак"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Падзелены двукроп'ямі сьпіс шляхоў, дзе месьцяцца ўтулкі"
 
@@ -799,6 +796,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ""
@@ -1030,6 +1033,10 @@ msgstr "альбом, якія зьмяшчае гэтыя даньі"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr ""
 
@@ -1045,6 +1052,9 @@ msgstr ""
 msgid "conditionally available"
 msgstr ""
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1286,6 +1296,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr ""
 
@@ -1340,3 +1356,6 @@ msgstr ""
 
 msgid "Freeing pipeline ...\n"
 msgstr ""
+
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Уключае шматслоўную дыягностыку загрузкі ўтулак"
diff --git a/po/bg.po b/po/bg.po
index fefab3e..15b2c5e 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -1,18 +1,18 @@
 # Bulgarian translation of gstreamer.
 # Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software Fondation, Inc.
 # Copyright (C) 2011, 2016, 2017, 2019 Free Software Fondation, Inc.
-# Copyright (C) 2021, 2023 Alexander Shopov.
+# Copyright (C) 2021, 2023, 2024 Alexander Shopov.
 # This file is distributed under the same license as the gstreamer package.
 # Alexander Shopov <ash@kambanaria.org>, 2005, 2006, 2007, 2008, 2009, 2010.
 # Alexander Shopov <ash@kambanaria.org>, 2011, 2016, 2017, 2019, 2021, 2023.
-#
+# Alexander Shopov <ash@kambanaria.org>, 2024.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.21.90\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
-"PO-Revision-Date: 2023-01-15 20:23+0200\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-03-09 11:13+0100\n"
 "Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
 "Language-Team: Bulgarian <dict@ludost.net>\n"
 "Language: bg\n"
@@ -59,15 +59,12 @@ msgid ""
 "auto, unix"
 msgstr ""
 "Смяна на режима на оцветяване на съобщенията за изчистване на грешки. "
-"Възможните стойности са: „off“ (изключване), „on“ (включване), "
-"„disable“ (спиране), „auto“ (автоматично), „unix“ (стандартно за unix)"
+"Възможните стойности са: „off“ (изключване), „on“ (включване), „disable“ "
+"(спиране), „auto“ (автоматично), „unix“ (стандартно за unix)"
 
 msgid "Disable debugging"
 msgstr "Без съобщения за изчистване на грешки"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Включване на подробни съобщения при зареждане на приставка"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Пътища с приставки, разделени с двоеточие"
 
@@ -831,6 +828,12 @@ msgstr "собствени данни"
 msgid "Private data"
 msgstr "Собствени данни"
 
+msgid "container-specific-track-id"
+msgstr "container-specific-track-id"
+
+msgid "Container-specific Track ID"
+msgstr "Идентификатор на песен, специфичен за контейнера"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1063,6 +1066,10 @@ msgstr "Потокът не съдържа никакви данни"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sРеализирани интерфейси%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sРеализирани интерфейси%s:\n"
+
 msgid "readable"
 msgstr "с права за четене"
 
@@ -1078,6 +1085,9 @@ msgstr "може да се контролира"
 msgid "conditionally available"
 msgstr "налично под условие"
 
+msgid "can be set only at object construction time"
+msgstr "може да се зададе само при създаването на обекта"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 "може да се променя само в състоянията NULL (зануляване), READY (готовност), "
@@ -1338,6 +1348,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "ИМЕ-НА-СВОЙСТВО"
 
+msgid "Set the name of the program"
+msgstr "Задаване на име на програмата"
+
+msgid "PROGRAM-NAME"
+msgstr "ИМЕ-НА-ПРОГРАМА"
+
 msgid "Do not install a fault handler"
 msgstr "Да не се инсталира модул за обработка на грешки"
 
diff --git a/po/ca.po b/po/ca.po
index 25d91bc..c9d25d3 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 0.10.30.3\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2010-11-04 19:41+0100\n"
 "Last-Translator: Jordi Mallach <jordi@sindominio.net>\n"
 "Language-Team: Catalan <ca@dodds.net>\n"
@@ -59,9 +59,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Inhabilita la depuració"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Habilita els diagnòstics detallats de càrrega de connectors"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Camins separats per dos punts que contenen connectors"
 
@@ -842,6 +839,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1076,6 +1079,10 @@ msgstr "El flux no conté dades."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Interfícies implementades:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "llegible"
 
@@ -1092,6 +1099,9 @@ msgstr "controlable"
 msgid "conditionally available"
 msgstr "controlable"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "es pot canviar als estats NUL, PREPARAT, EN PAUSA o REPRODUINT"
 
@@ -1350,6 +1360,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "No instal·les un gestor de fallades"
 
@@ -1406,6 +1422,9 @@ msgstr "S'està establint el conducte a NUL…\n"
 msgid "Freeing pipeline ...\n"
 msgstr "S'està alliberant el conducte…\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Habilita els diagnòstics detallats de càrrega de connectors"
+
 #~ msgid "link without source element"
 #~ msgstr "l'enllaç no té un element font"
 
diff --git a/po/cs.po b/po/cs.po
index 0ab2ed7..e1250b1 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -9,7 +9,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.12.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2017-09-13 15:04+0200\n"
 "Last-Translator: Marek Černocký <marek@manet.cz>\n"
 "Language-Team: Czech <translation-team-cs@lists.sourceforge.net>\n"
@@ -62,9 +62,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Zakázat ladění"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Povolit podrobnou diagnostiku načítání zásuvných modulů"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Dvojtečkou oddělované cesty obsahující zásuvné moduly"
 
@@ -831,6 +828,12 @@ msgstr "soukromá data"
 msgid "Private data"
 msgstr "Soukromá data"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr "; "
@@ -1065,6 +1068,10 @@ msgstr "Proud neobsahuje žádná data."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Implementovaná rozhraní:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "lze číst"
 
@@ -1081,6 +1088,9 @@ msgstr "lze ovládat"
 msgid "conditionally available"
 msgstr "lze ovládat"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "lze změnit ve stavu PRÁZDNÉ, PŘIPRAVENO, POZASTAVENO nebo PŘEHRÁVÁ"
 
@@ -1349,6 +1359,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "NÁZEV-VLASTNOSTI"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "NÁZEV-VLASTNOSTI"
+
 msgid "Do not install a fault handler"
 msgstr "Neinstalovat obsluhu výjimek"
 
@@ -1405,6 +1422,9 @@ msgstr "Nastavuje se roura na PRÁZDNÁ…\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Uvolňuje se roura…\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Povolit podrobnou diagnostiku načítání zásuvných modulů"
+
 # On strike?
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "CHYBA: Roura se nechce pozastavit.\n"
diff --git a/po/da.po b/po/da.po
index 39552e2..4eb33c4 100644
--- a/po/da.po
+++ b/po/da.po
@@ -10,7 +10,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.15.1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2019-02-14 13:26+0200\n"
 "Last-Translator: Joe Hansen <joedalton2@yahoo.dk>\n"
 "Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
@@ -64,9 +64,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Deaktiver fejlsøgning"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Aktiver udførlig diagnostik ved indlæsning af moduler"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Kolon-separerede stier der indeholder moduler"
 
@@ -836,6 +833,12 @@ msgstr "private-data"
 msgid "Private data"
 msgstr "Private data"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1074,6 +1077,10 @@ msgstr "Mediestrøm indeholder ingen data."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sImplementerede grænseflader%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sImplementerede grænseflader%s:\n"
+
 msgid "readable"
 msgstr "læselig"
 
@@ -1090,6 +1097,9 @@ msgstr "kontrollerbar"
 msgid "conditionally available"
 msgstr "kontrollerbar"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "kan ændres i tilstandene NULL, READY, PAUSED eller PLAYING"
 
@@ -1352,6 +1362,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "EGENSKABSNAVN"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "EGENSKABSNAVN"
+
 msgid "Do not install a fault handler"
 msgstr "Installer ikke en fejlhåndterer"
 
@@ -1408,6 +1425,9 @@ msgstr "Rørledning sættes til NUL ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Rørledning frigøres ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Aktiver udførlig diagnostik ved indlæsning af moduler"
+
 #, c-format
 #~ msgid "Error creating pipe: %s\n"
 #~ msgstr "Fejl ved oprettelse af datakanal: %s\n"
diff --git a/po/de.po b/po/de.po
index 0445572..284c225 100644
--- a/po/de.po
+++ b/po/de.po
@@ -7,10 +7,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.21.90\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
-"PO-Revision-Date: 2023-01-16 22:34+0100\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-03-16 23:40+0100\n"
 "Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
 "Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
 "Language: de\n"
@@ -19,7 +19,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Bugs: Report translation errors to the Language-Team address.\n"
-"X-Generator: Poedit 3.1.1\n"
+"X-Generator: Poedit 3.4.2\n"
 "X-Poedit-SourceCharset: UTF-8\n"
 
 msgid "Print the GStreamer version"
@@ -64,9 +64,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Fehlerdiagnose deaktivieren"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Ausführliche Meldungen beim Laden von Plugins aktivieren"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Durch Doppelpunkte getrennte Pfade zu den Plugins"
 
@@ -858,6 +855,12 @@ msgstr "Private-Daten"
 msgid "Private data"
 msgstr "Private Daten"
 
+msgid "container-specific-track-id"
+msgstr "container-specific-track-id"
+
+msgid "Container-specific Track ID"
+msgstr "Container-spezifische Verfolgungs-KENNUNG"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1100,6 +1103,10 @@ msgstr "Der Datenstrom enthält keine Daten."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sImplementierte Schnittstellen%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sImplementierte Schnittstellen%s:\n"
+
 msgid "readable"
 msgstr "lesbar"
 
@@ -1115,6 +1122,9 @@ msgstr "regelbar"
 msgid "conditionally available"
 msgstr "unter Vorbehalt verfügbar"
 
+msgid "can be set only at object construction time"
+msgstr "kann nur zum Zeitpunkt der Objekterstellung festgelegt werden"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "änderbar in den Status NULL, BEREIT, PAUSIERT oder ABSPIELEN"
 
@@ -1376,6 +1386,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "EIGENSCHAFT-NAME"
 
+msgid "Set the name of the program"
+msgstr "Den Namen des Programms festlegen"
+
+msgid "PROGRAM-NAME"
+msgstr "PROGRAMM-NAME"
+
 msgid "Do not install a fault handler"
 msgstr "Keine Routine zum Abfangen von Fehlern installieren"
 
@@ -1436,6 +1452,9 @@ msgstr "Leitung wird auf NULL gesetzt ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Leitung wird geleert ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Ausführliche Meldungen beim Laden von Plugins aktivieren"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "FEHLER: Leitung möchte nicht pausiert werden.\n"
 
diff --git a/po/el.po b/po/el.po
index f478a98..b9213ef 100644
--- a/po/el.po
+++ b/po/el.po
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer-0.10.30.3\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2010-11-29 11:14+0200\n"
 "Last-Translator: Michael Kotsarinis <mk73628@gmail.com>\n"
 "Language-Team: Greek <team@lists.gnome.gr>\n"
@@ -60,9 +60,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Απενεργοποίηση αποσφαλμάτωσης"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Ενεργοποίηση αναλυτικών διαγνωστικών φόρτωσης πρόσθετου"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Διαχωρισμένες με άνω-κάτω τελεία διαδρομές που περιέχουν πρόσθετα"
 
@@ -854,6 +851,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1088,6 +1091,10 @@ msgstr "Η ροή δεν περιέχει δεδομένα."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Υλοποιημένες διεπαφές:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "αναγνώσιμο"
 
@@ -1104,6 +1111,9 @@ msgstr "ελεγχόμενο"
 msgid "conditionally available"
 msgstr "ελεγχόμενο"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "μπορεί να αλλάξει σε κατάσταση NULL, READY, PAUSED ή PLAYING"
 
@@ -1355,6 +1365,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "Να μην εγκατασταθεί χειριστής σφαλμάτων"
 
@@ -1411,6 +1427,9 @@ msgstr "Ορισμός διασωλήνωσης σε NULL …\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Αποδέσμευση της διασωλήνωσης …\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Ενεργοποίηση αναλυτικών διαγνωστικών φόρτωσης πρόσθετου"
+
 #~ msgid "link without source element"
 #~ msgstr "σύνδεση χωρίς στοιχείο προέλευσης"
 
diff --git a/po/en_GB.po b/po/en_GB.po
index 3bd543b..cd4aef8 100644
--- a/po/en_GB.po
+++ b/po/en_GB.po
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 0.8.1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2004-04-26 10:36-0400\n"
 "Last-Translator: Gareth Owen <gowen72@yahoo.com>\n"
 "Language-Team: English (British) <en_gb@li.org>\n"
@@ -55,9 +55,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Disable debugging"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Enable verbose plugin loading diagnostics"
-
 msgid "Colon-separated paths containing plugins"
 msgstr ""
 
@@ -835,6 +832,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1067,6 +1070,10 @@ msgstr "album containing this data"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr ""
 
@@ -1082,6 +1089,9 @@ msgstr ""
 msgid "conditionally available"
 msgstr ""
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1326,6 +1336,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+#, fuzzy
+msgid "Set the name of the program"
+msgstr "Stream is of the wrong format."
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "Do not install a fault handler"
 
@@ -1385,6 +1402,9 @@ msgstr "RUNNING pipeline ...\n"
 #~ msgid "Disable accelerated CPU instructions"
 #~ msgstr "Disable accelerated CPU instructions"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Enable verbose plugin loading diagnostics"
+
 #~ msgid "SCHEDULER"
 #~ msgstr "SCHEDULER"
 
diff --git a/po/eo.po b/po/eo.po
index 30508df..9bc35d7 100644
--- a/po/eo.po
+++ b/po/eo.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.19.2\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2023-01-08 11:53-0300\n"
 "Last-Translator: Felipe Castro <fefcas@gmail.com>\n"
 "Language-Team: Esperanto <translation-team-eo@lists.sourceforge.net>\n"
@@ -61,9 +61,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Malaktivigi sencimigon"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Aktivigi detaleman diagnozon de ŝargado je kromaĵo"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Dupunkto-apartitaj vojoj enhavantaj kromaĵojn"
 
@@ -822,6 +819,12 @@ msgstr "privata-datumaro"
 msgid "Private data"
 msgstr "Privata datumaro"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1054,6 +1057,10 @@ msgstr "La fluo enhavas neniun datumaron."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sRealigitaj Interfacoj%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sRealigitaj Interfacoj%s:\n"
+
 msgid "readable"
 msgstr "legebla"
 
@@ -1069,6 +1076,9 @@ msgstr "regebla"
 msgid "conditionally available"
 msgstr "disponebla kondiĉe"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "ŝanĝebla nur en statoj NULA, PRETA, PAŬZITA aŭ LUDANTA"
 
@@ -1324,6 +1334,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "ATRIBUTO-NOMO"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "ATRIBUTO-NOMO"
+
 msgid "Do not install a fault handler"
 msgstr "Ne instali traktilon de misfunkcio"
 
@@ -1384,6 +1401,9 @@ msgstr "Ni difinas ĉenstablon kiel NULA ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Ni liberigas ĉenstablon ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Aktivigi detaleman diagnozon de ŝargado je kromaĵo"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "ERARO: ĉenstablo ne volas paŭzi.\n"
 
diff --git a/po/es.po b/po/es.po
index bf06b76..0d83002 100644
--- a/po/es.po
+++ b/po/es.po
@@ -1,15 +1,15 @@
-# translation of gstreamer-1.21.90 to Español
+# translation of gstreamer-1.24.0 to Español
 # spanish translation for gstreamer
 # This file is put in the public domain.
 # Jorge González <jorgegonz@svn.gnome.org>, 2009, 2010, 2011.
-# Cristian Othón Martínez Vera <cfuga@cfuga.mx>, 2022, 2023
+# Cristian Othón Martínez Vera <cfuga@cfuga.mx>, 2022, 2023, 2024.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.21.90\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
-"PO-Revision-Date: 2023-01-16 11:12-0600\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-03-07 11:29-0600\n"
 "Last-Translator: Cristian Othón Martínez Vera <cfuga@cfuga.mx>\n"
 "Language-Team: Spanish <es@tp.org.es>\n"
 "Language: es\n"
@@ -61,9 +61,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Desactivar depuración"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Activar la salida detallada del diagnóstico de carga de complementos"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Rutas separadas por punto y coma conteniendo los complementos"
 
@@ -843,6 +840,12 @@ msgstr "datos-privados"
 msgid "Private data"
 msgstr "Datos privados"
 
+msgid "container-specific-track-id"
+msgstr "id-pista-específica-contenedor"
+
+msgid "Container-specific Track ID"
+msgstr "ID de Pista Específica-del-contenedor"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1079,6 +1082,10 @@ msgstr "El flujo no contiene datos."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sInterfaces implementados%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sInterfaces implementados%s:\n"
+
 msgid "readable"
 msgstr "legible"
 
@@ -1094,6 +1101,9 @@ msgstr "controlable"
 msgid "conditionally available"
 msgstr "condicionalmente disponible"
 
+msgid "can be set only at object construction time"
+msgstr "solamente se puede definir en el momento de construcción del objeto"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "intercambiable entre los estados NULL, READY, PAUSED o PLAYING"
 
@@ -1352,6 +1362,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "NOMBRE-PROPIEDAD"
 
+msgid "Set the name of the program"
+msgstr "Define el nombre del programa"
+
+msgid "PROGRAM-NAME"
+msgstr "NOMBRE-PROGRAMA"
+
 msgid "Do not install a fault handler"
 msgstr "No instalar un manejador predeterminado"
 
@@ -1414,6 +1430,10 @@ msgstr "Estableciendo el conducto a NULL …\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Liberando el conducto…\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr ""
+#~ "Activar la salida detallada del diagnóstico de carga de complementos"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "ERROR: El conducto no quiere pausarse.\n"
 
diff --git a/po/eu.po b/po/eu.po
index cce1e8b..e005efe 100644
--- a/po/eu.po
+++ b/po/eu.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer-0.10.26.2\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2010-03-25 13:10+0100\n"
 "Last-Translator: Mikel Olasagasti Uranga <hey_neken@mundurat.net>\n"
 "Language-Team: Basque <translation-team-eu@lists.sourceforge.net>\n"
@@ -61,9 +61,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Desgaitu arazketa"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Gaitu pluginen kargatze-diagnostiko xehatua"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Pluginak dituzten bide-izenak, bi punturekin bereizita"
 
@@ -842,6 +839,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1079,6 +1082,10 @@ msgstr "Korronteak ez du daturik."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Inplementatutako interfazeak:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "irakur daitekeena"
 
@@ -1095,6 +1102,9 @@ msgstr "kontrola daitekeena"
 msgid "conditionally available"
 msgstr "kontrola daitekeena"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1347,6 +1357,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "Ez instalatu akats-maneiatzailerik"
 
@@ -1403,6 +1419,9 @@ msgstr "Kanalizazioa NULUA gisa ezartzen... \n"
 msgid "Freeing pipeline ...\n"
 msgstr "Kanalizazioa askatzen...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Gaitu pluginen kargatze-diagnostiko xehatua"
+
 #~ msgid "link without source element"
 #~ msgstr "iturburu-elementurik gabeko esteka"
 
diff --git a/po/fi.po b/po/fi.po
index d79e549..835479c 100644
--- a/po/fi.po
+++ b/po/fi.po
@@ -12,7 +12,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 0.10.30.3\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2010-11-17 23:10+0200\n"
 "Last-Translator: Tommi Vainikainen <Tommi.Vainikainen@iki.fi>\n"
 "Language-Team: Finnish <translation-team-fi@lists.sourceforge.net>\n"
@@ -63,9 +63,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Ei vianetsintää"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Käytä monisanaista liitännäisten latausdiagnostiikka"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Kaksoispistein erotellut polut liitännäisiin"
 
@@ -840,6 +837,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1074,6 +1077,10 @@ msgstr "Virta on tyhjä."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Toteutetut rajapinnat:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "luettavissa"
 
@@ -1090,6 +1097,9 @@ msgstr "ohjattavissa"
 msgid "conditionally available"
 msgstr "ohjattavissa"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "vaihdettavissa TYHJÄ-, VALMIS-, TAUOLLA- tai SOI-tiloissa"
 
@@ -1342,6 +1352,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "Älä asenna virheenkäsittelintä"
 
@@ -1398,6 +1414,9 @@ msgstr "Asetetaan liukuhihna tilaan TYHJÄ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Vapautetaan liukuhihna...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Käytä monisanaista liitännäisten latausdiagnostiikka"
+
 #~ msgid "link without source element"
 #~ msgstr "linkki ilman lähde-elementtiä"
 
diff --git a/po/fr.po b/po/fr.po
index e1b0753..32fadf9 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -5,14 +5,15 @@
 # Thomas Vander Stichele <thomas@apestaart.org>, 2004.
 # Claude Paroz <claude@2xlibre.net>, 2008-2012.
 # Stéphane Aulery <lkppo@free.fr>, 2015-2022.
+# Christian Wiatr <w9204-fs@yahoo.com>, 2023.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.19.2\n"
+"Project-Id-Version: gstreamer 1.21.90\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
-"PO-Revision-Date: 2022-07-05 00:47+0200\n"
-"Last-Translator: Stéphane Aulery <lkppo@free.fr>\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2023-06-04 11:11+0200\n"
+"Last-Translator: Christian Wiatr <w9204-fs@yahoo.com>\n"
 "Language-Team: French <traduc@traduc.org>\n"
 "Language: fr\n"
 "MIME-Version: 1.0\n"
@@ -20,6 +21,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=2; plural=n>1;\n"
+"X-Generator: Poedit 2.4.2\n"
 
 msgid "Print the GStreamer version"
 msgstr "Affiche la version de GStreamer"
@@ -63,9 +65,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Désactive le débogage"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Active le diagnostic détaillé du chargement des greffons"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Chemins contenant des greffons, séparés par des deux-points"
 
@@ -839,6 +838,12 @@ msgstr "données-privées"
 msgid "Private data"
 msgstr "Données privées"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -853,7 +858,7 @@ msgstr "Aucun gestionnaire d’URI trouvé pour le protocole %s"
 
 #, c-format
 msgid "URI scheme '%s' not supported"
-msgstr "schéma URI « %s » non pris en charge"
+msgstr "URI de schéma « %s » non prise en charge"
 
 #, c-format
 msgid "ERROR: from element %s: %s\n"
@@ -879,7 +884,7 @@ msgid "link has no sink [source=%s@%p]"
 msgstr "lien sans sink [source=%s@%p]"
 
 msgid "No such property."
-msgstr ""
+msgstr "Propriété non trouvée."
 
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
@@ -901,9 +906,11 @@ msgstr "pas d’élément « %s »"
 msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
 msgstr "impossible de définir la propriété « %s » de l’élément « %s » à « %s »"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
-msgstr "impossible de définir la propriété « %s » de l’élément « %s » à « %s »"
+msgstr ""
+"impossible de définir la propriété « %s » du fils de l'élément « %s » à "
+"« %s »"
 
 msgid "Delayed linking failed."
 msgstr "Échec du chargement dynamique différé."
@@ -1073,6 +1080,10 @@ msgstr "Le flux ne contient aucune donnée."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sinterfaces implémentées%s :\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sinterfaces implémentées%s :\n"
+
 msgid "readable"
 msgstr "accès en lecture"
 
@@ -1088,6 +1099,9 @@ msgstr "contrôlable"
 msgid "conditionally available"
 msgstr "dospinibilité conditionnelle"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "modifiable en l’état NULL, READY, PAUSED ou PLAYING"
 
@@ -1179,7 +1193,8 @@ msgstr ""
 "GST_INSPECT_NO_COLORS."
 
 msgid "Color output, even when not sending to a tty."
-msgstr "Couleur de la sortie, même quand vers un autre périphérique qu'un tty"
+msgstr ""
+"Couleur de la sortie, même quand le périphérique est différent d'un tty."
 
 #, c-format
 msgid "Could not load plugin file: %s\n"
@@ -1346,6 +1361,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "NOM-PROPRIÉTÉ"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "NOM-PROPRIÉTÉ"
+
 msgid "Do not install a fault handler"
 msgstr "N’installe pas de gestionnaire de dysfonctionnement"
 
@@ -1408,6 +1430,9 @@ msgstr "Définition du pipeline à NULL…\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Libération du pipeline…\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Active le diagnostic détaillé du chargement des greffons"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "ERREUR : le pipeline refuse de se mettre en pause.\n"
 
diff --git a/po/fur.po b/po/fur.po
index 0efd014..97205b7 100644
--- a/po/fur.po
+++ b/po/fur.po
@@ -1,22 +1,23 @@
 # Friulian translation for gstreamer package of GStreamer project.
 # This file is put in the public domain.
-# Fabio Tomat <f.t.public@gmail.com>, 2017.
+# Fabio Tomat <f.t.public@gmail.com>, 2023.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.10.0\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
-"PO-Revision-Date: 2017-03-19 15:41+0100\n"
-"Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-10-03 15:38+0000\n"
+"Last-Translator: Fabio T. <f.t.public@gmail.com>\n"
 "Language-Team: Friulian <f.t.public@gmail.com>\n"
 "Language: fur\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 1.8.12\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Editor: HaiPO 2.0 beta\n"
+"X-Generator: Poedit 3.2.2\n"
 
 msgid "Print the GStreamer version"
 msgstr "Stampe la version di GStreamer"
@@ -25,11 +26,12 @@ msgid "Make all warnings fatal"
 msgstr "Fâs deventâ ducj i avertiments fatâi"
 
 msgid "Print available debug categories and exit"
-msgstr ""
+msgstr "Stampe lis categoriis di debug disponibilis e jes"
 
 msgid ""
 "Default debug level from 1 (only error) to 9 (anything) or 0 for no output"
 msgstr ""
+"Nivel di debug predefinît di 1 (dome erôr) a 9 (dut) opûr 0 par no vê output"
 
 msgid "LEVEL"
 msgstr "NIVEL"
@@ -38,26 +40,27 @@ msgid ""
 "Comma-separated list of category_name:level pairs to set specific levels for "
 "the individual categories. Example: GST_AUTOPLUG:5,GST_ELEMENT_*:3"
 msgstr ""
+"Liste separade di virgulis di cubiis non_categorie:nivel par stabilî i nivei "
+"specifics pes categoriis individuâls. Esempli: GST_AUTOPLUG:5,GST_ELEMENT_*:3"
 
 msgid "LIST"
 msgstr "LISTE"
 
 msgid "Disable colored debugging output"
-msgstr ""
+msgstr "Disabilite la jessude di debug colorade"
 
 msgid ""
 "Changes coloring mode of the debug log. Possible modes: off, on, disable, "
 "auto, unix"
 msgstr ""
+"Al cambie la modalitât di colorazion dal regjistri di debug. Lis modalitât "
+"pussibilis: off, on, disable, auto, unix"
 
 msgid "Disable debugging"
-msgstr ""
-
-msgid "Enable verbose plugin loading diagnostics"
-msgstr ""
+msgstr "Disabilite il debug"
 
 msgid "Colon-separated paths containing plugins"
-msgstr ""
+msgstr "Percors separâts di “:” che a contegnin i plugins"
 
 msgid "PATHS"
 msgstr "PERCORS"
@@ -66,18 +69,24 @@ msgid ""
 "Comma-separated list of plugins to preload in addition to the list stored in "
 "environment variable GST_PLUGIN_PATH"
 msgstr ""
+"Liste separade di “:” di plugins di pre-cjariâ in zonte ae liste archividade "
+"te variabile di ambient GST_PLUGIN_PATH"
 
 msgid "PLUGINS"
 msgstr "PLUGIN"
 
 msgid "Disable trapping of segmentation faults during plugin loading"
 msgstr ""
+"Disabilite la cature di vuascj di segmentazion dilunc il cjariament dai "
+"plugins"
 
 msgid "Disable updating the registry"
-msgstr ""
+msgstr "Disabilite l'inzornament dal regjistri"
 
 msgid "Disable spawning a helper process while scanning the registry"
 msgstr ""
+"Disabilite la creazion di un procès aiutant intant che si analize il "
+"regjistri"
 
 msgid "GStreamer Options"
 msgstr "Opzions GStreamer"
@@ -90,69 +99,75 @@ msgid "Unknown option"
 msgstr "Opzion no cognossude"
 
 msgid "GStreamer encountered a general core library error."
-msgstr ""
+msgstr "GStreamer al à riscontrât un erôr gjenerâl de librarie cûr."
 
 msgid ""
 "GStreamer developers were too lazy to assign an error code to this error."
 msgstr ""
+"I svilupadôrs di GStreamer a jerin masse pelandrons par assegnâ un codiç di "
+"erôr a chest erôr."
 
 msgid "Internal GStreamer error: code not implemented."
-msgstr ""
+msgstr "Erôr interni di GStreamer: codiç no implementât."
 
 msgid ""
 "GStreamer error: state change failed and some element failed to post a "
 "proper error message with the reason for the failure."
 msgstr ""
+"Erôr di GStreamer: il cambiament di stât al à falît e cualchi element nol è "
+"rivât a publicâ un messaç di erôr adat cul motîf relatîf al faliment."
 
 msgid "Internal GStreamer error: pad problem."
-msgstr ""
+msgstr "Erôr interni di GStreamer: probleme di imbotidure."
 
 msgid "Internal GStreamer error: thread problem."
-msgstr ""
+msgstr "Erôr interni di GStreamer: probleme di thread."
 
 msgid "GStreamer error: negotiation problem."
-msgstr ""
+msgstr "Erôr di GStreamer: probleme di negoziazion."
 
 msgid "Internal GStreamer error: event problem."
-msgstr ""
+msgstr "Erôr interni di GStreamer: probleme di event."
 
 msgid "Internal GStreamer error: seek problem."
-msgstr ""
+msgstr "Erôr interni di GStreamer: probleme di ricercje."
 
 msgid "Internal GStreamer error: caps problem."
-msgstr ""
+msgstr "Erôr interni di GStreamer: probleme di sottitui."
 
 msgid "Internal GStreamer error: tag problem."
-msgstr ""
+msgstr "Erôr interni di GStreamer: probleme di etichete."
 
 msgid "Your GStreamer installation is missing a plug-in."
-msgstr ""
+msgstr "Ae tô instalazion di GStreamer e mancje un plug-in."
 
 msgid "GStreamer error: clock problem."
-msgstr ""
+msgstr "Erôr di GStreamer: probleme di orloi."
 
 msgid ""
 "This application is trying to use GStreamer functionality that has been "
 "disabled."
 msgstr ""
+"Cheste aplicazion e sta cirint di doprâ une funzion di GStreamer che e je "
+"stade disabilitade."
 
 msgid "GStreamer encountered a general supporting library error."
-msgstr ""
+msgstr "GStreamer al à riscontrât un erôr gjenerâl de librarie di supuart."
 
 msgid "Could not initialize supporting library."
-msgstr ""
+msgstr "Impussibil inizializâ la librarie di supuart."
 
 msgid "Could not close supporting library."
-msgstr ""
+msgstr "Impussibil sierâ la libarie di supuart."
 
 msgid "Could not configure supporting library."
-msgstr ""
+msgstr "Impussibil configurâ la librarie di supuart."
 
 msgid "Encoding error."
 msgstr "Erôr di codifiche."
 
 msgid "GStreamer encountered a general resource error."
-msgstr ""
+msgstr "GStreamer al à riscontrât un erôr gjenerâl des risorsis."
 
 msgid "Resource not found."
 msgstr "Risorse no cjatade."
@@ -194,19 +209,22 @@ msgid "Not authorized to access resource."
 msgstr "No autorizât a acedi ae risorse."
 
 msgid "GStreamer encountered a general stream error."
-msgstr ""
+msgstr "GStreamer al à riscontrât un erôr gjenerâl di flus."
 
 msgid "Element doesn't implement handling of this stream. Please file a bug."
 msgstr ""
+"L'element nol implemente la gjestion di chest flus. Par plasê, fâs une "
+"segnalazion di erôr."
 
 msgid "Could not determine type of stream."
 msgstr "Impussibil determinâ il gjenar di flus."
 
 msgid "The stream is of a different type than handled by this element."
-msgstr ""
+msgstr "Il flus al è di un gjenar diferent di chel gjestît di chest element."
 
 msgid "There is no codec present that can handle the stream's type."
 msgstr ""
+"Nol è presint nissun codificadôr che al pues gjestî chest gjenar di flus."
 
 msgid "Could not decode stream."
 msgstr "Impussibil decodificâ il flus."
@@ -215,10 +233,10 @@ msgid "Could not encode stream."
 msgstr "Impussibil codificâ il flus."
 
 msgid "Could not demultiplex stream."
-msgstr ""
+msgstr "Impussibil demultiplexâ il flus."
 
 msgid "Could not multiplex stream."
-msgstr ""
+msgstr "Impussibil multiplexâ il flus."
 
 msgid "The stream is in the wrong format."
 msgstr "Il flus al è tal formât sbaliât."
@@ -242,7 +260,7 @@ msgid "No standard error message for domain %s and code %d."
 msgstr "Nissun messaç di erôr standard pal domini %s e codiç %d."
 
 msgid "Selected clock cannot be used in pipeline."
-msgstr ""
+msgstr "Nol è pussibil doprâ te pipeline l'orloi selezionât."
 
 #, c-format
 msgid "Error writing registry cache to %s: %s"
@@ -319,13 +337,14 @@ msgid "comment"
 msgstr "coment"
 
 msgid "free text commenting the data"
-msgstr ""
+msgstr "test libar che al comente i dâts"
 
 msgid "extended comment"
-msgstr ""
+msgstr "coment slargjât"
 
 msgid "free text commenting the data in key=value or key[en]=comment form"
 msgstr ""
+"test libar che al comente i dâts te forme clâf=valôr o clâf[ing]=coment"
 
 msgid "track number"
 msgstr "numar dal toc"
@@ -366,8 +385,8 @@ msgstr "sît web"
 
 msgid "Homepage for this media (i.e. artist or movie homepage)"
 msgstr ""
-"sît web par chest contignût multimediâl (p.e. il sît web dal artist o dal "
-"film)"
+"Sît web par chest contignût multimediâl (vâl a dî la pagjine web dal artist "
+"o dal film)"
 
 msgid "description"
 msgstr "descrizion"
@@ -441,10 +460,10 @@ msgid "person(s) who composed the recording"
 msgstr "persone(-is) che e à componût la regjistrazion"
 
 msgid "conductor"
-msgstr ""
+msgstr "diretôr"
 
 msgid "conductor/performer refinement"
-msgstr ""
+msgstr "perfezionament diretôr/artist"
 
 msgid "duration"
 msgstr "durade"
@@ -507,16 +526,16 @@ msgid "maximum bitrate in bits/s"
 msgstr "bitrate massim in bit/s"
 
 msgid "encoder"
-msgstr ""
+msgstr "codificadôr"
 
 msgid "encoder used to encode this stream"
-msgstr ""
+msgstr "codificadôr doprât par codificâ chest flus"
 
 msgid "encoder version"
-msgstr ""
+msgstr "version codificadôr"
 
 msgid "version of the encoder used to encode this stream"
-msgstr ""
+msgstr "version dal codfiicadôr doprât par codificâ chest flus"
 
 msgid "serial"
 msgstr "seriâl"
@@ -525,34 +544,34 @@ msgid "serial number of track"
 msgstr "numar seriâl dal toc"
 
 msgid "replaygain track gain"
-msgstr ""
+msgstr "vuadagn de linie replaygain"
 
 msgid "track gain in db"
 msgstr "vuadagn toc in db"
 
 msgid "replaygain track peak"
-msgstr ""
+msgstr "Pic de linie replaygain"
 
 msgid "peak of the track"
 msgstr "pic dal toc"
 
 msgid "replaygain album gain"
-msgstr ""
+msgstr "vuadagn dal album replaygain"
 
 msgid "album gain in db"
 msgstr "vuadagn album in db"
 
 msgid "replaygain album peak"
-msgstr ""
+msgstr "pic dal album replaygain"
 
 msgid "peak of the album"
 msgstr "pic dal album"
 
 msgid "replaygain reference level"
-msgstr ""
+msgstr "nivel di riferiment replaygain"
 
 msgid "reference level of track and album gain values"
-msgstr ""
+msgstr "nivel di riferiment dai valôrs di vuadagn de linie e dal album"
 
 msgid "language code"
 msgstr "codiç lenghe"
@@ -604,6 +623,8 @@ msgid ""
 "human readable descriptive location of where the media has been recorded or "
 "produced"
 msgstr ""
+"ubicazion descritive par umans di dulà che l'element multimediâl al è stât "
+"regjistrât o prodot"
 
 msgid "geo location latitude"
 msgstr "latitudin posizion gjeog."
@@ -656,43 +677,53 @@ msgstr ""
 "o prodot"
 
 msgid "geo location sublocation"
-msgstr ""
+msgstr "sot-posizion de posizion gjeografiche"
 
 msgid ""
 "a location within a city where the media has been produced or created (e.g. "
 "the neighborhood)"
 msgstr ""
+"une posizion dentri di une citât dulà che l'element multimediâl al è stât "
+"prodot o creât (p.e. borc)"
 
 msgid "geo location horizontal error"
-msgstr ""
+msgstr "erôr de posizion orizontâl gjeografiche"
 
 msgid "expected error of the horizontal positioning measures (in meters)"
-msgstr ""
+msgstr "erôr spietât des misuris di posizionament orizontâl (in metris)"
 
 msgid "geo location movement speed"
-msgstr ""
+msgstr "velocitât di moviment de posizion gjeografiche"
 
 msgid ""
 "movement speed of the capturing device while performing the capture in m/s"
 msgstr ""
+"velocitât di moviment dal dispositîf di acuisizion intant che al eseguìs il "
+"rilevament in m/s"
 
 msgid "geo location movement direction"
-msgstr ""
+msgstr "direzion di moviment de posizion gjeografiche"
 
 msgid ""
 "indicates the movement direction of the device performing the capture of a "
 "media. It is represented as degrees in floating point representation, 0 "
 "means the geographic north, and increases clockwise"
 msgstr ""
+"al indiche la direzion di moviment dal dispositîf tal eseguî la acuisizion "
+"di un contignût multimediâl. Al è rapresentât tant che grâts in virgule "
+"mobile, 0 al è il Nord gjeografic e al incrès in sens orari"
 
 msgid "geo location capture direction"
-msgstr ""
+msgstr "direzion de acuisizion de posizion gjeografiche"
 
 msgid ""
 "indicates the direction the device is pointing to when capturing  a media. "
 "It is represented as degrees in floating point  representation, 0 means the "
 "geographic north, and increases clockwise"
 msgstr ""
+"al indiche la direzion là che il dispositîf al sta pontant intant che al "
+"tire sù  un contignût multimediâl. Al è rapresentât tant che grâts in "
+"virgule mobile,  0 al è il Nord gjeografic e al incrès in sens orari"
 
 #. TRANSLATORS: 'show name' = 'TV/radio/podcast show name' here
 msgid "show name"
@@ -700,6 +731,8 @@ msgstr "mostre non"
 
 msgid "Name of the tv/podcast/series show the media is from"
 msgstr ""
+"Non di dulà che a rivin i contignûts multimediâi di tv/podcast/seriis "
+"televisivis"
 
 #. TRANSLATORS: 'show sortname' = 'TV/radio/podcast show name as used for sorting purposes' here
 msgid "show sortname"
@@ -708,6 +741,8 @@ msgstr "mostre non ordenament"
 msgid ""
 "Name of the tv/podcast/series show the media is from, for sorting purposes"
 msgstr ""
+"Non di dulà che a rivin i contignûts multimediâi di tv/podcast/seriis "
+"televisivis, par finalitâts di ordenament"
 
 msgid "episode number"
 msgstr "numar episodi"
@@ -726,10 +761,10 @@ msgstr ""
 "multimediâl"
 
 msgid "lyrics"
-msgstr ""
+msgstr "tescj"
 
 msgid "The lyrics of the media, commonly used for songs"
-msgstr ""
+msgstr "I tescj dai contignûts multimediâi, di solit doprâts pes cjançons"
 
 msgid "composer sortname"
 msgstr "non ordenament compositôr"
@@ -778,7 +813,7 @@ msgid "application data"
 msgstr "dâts aplicazion"
 
 msgid "Arbitrary application data to be serialized into the media"
-msgstr ""
+msgstr "Dâts di aplicazion arbitraris di serializâ tal contignût multimediâl"
 
 msgid "image orientation"
 msgstr "orientament imagjin"
@@ -788,177 +823,192 @@ msgstr ""
 "Ce mût che la imagjin e varès di jessi voltade o ribaltade prime di mostrâle"
 
 msgid "publisher"
-msgstr ""
+msgstr "editôr"
 
 msgid "Name of the label or publisher"
-msgstr ""
+msgstr "Non de etichete o dal editôr"
 
 msgid "interpreted-by"
-msgstr ""
+msgstr "interpretât di"
 
 msgid "Information about the people behind a remix and similar interpretations"
 msgstr ""
+"Informazions su lis personis daûr di un remix e di interpretazions similis"
 
 msgid "midi-base-note"
-msgstr ""
+msgstr "midi-base-note"
 
 msgid "Midi note number of the audio track."
-msgstr ""
+msgstr "Numar di notis midi di une linie audio."
 
 msgid "private-data"
-msgstr ""
+msgstr "dâts privâts"
 
 msgid "Private data"
+msgstr "Dâts privâts"
+
+msgid "container-specific-track-id"
 msgstr ""
 
+msgid "Container-specific Track ID"
+msgstr "ID de linie specific dal contignidôr"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
 
 #, c-format
 msgid "Invalid URI: %s"
-msgstr ""
+msgstr "URI no valit: %s"
 
 #, c-format
 msgid "No URI handler for the %s protocol found"
-msgstr ""
+msgstr "Nissun gjestôr URI cjatât pal protocol %s"
 
 #, c-format
 msgid "URI scheme '%s' not supported"
-msgstr ""
+msgstr "Scheme dal URI '%s' no supuartât"
 
 #, c-format
 msgid "ERROR: from element %s: %s\n"
-msgstr ""
+msgstr "ERÔR: dal element %s: %s\n"
 
 #, c-format
 msgid ""
 "Additional debug info:\n"
 "%s\n"
 msgstr ""
+"Informazions adizionâls di debug:\n"
+"%s\n"
 
 #. ******************************************************************************************
 #. *** helpers for pipeline-setup
 #. ******************************************************************************************
 #, c-format
 msgid "link has no source [sink=%s@%p]"
-msgstr ""
+msgstr "il colegament nol à sorzint [destinazion=%s@%p]"
 
 #, c-format
 msgid "link has no sink [source=%s@%p]"
-msgstr ""
+msgstr "il colegament nol à destinazion [sorzint=%s@%p]"
 
 msgid "No such property."
-msgstr ""
+msgstr "Cheste proprietât no esist."
 
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
-msgstr ""
+msgstr "nissune proprietât \"%s\" tal element \"%s\""
 
-#, fuzzy, c-format
+#, c-format
 msgid "Element \"%s\" is not a GstPreset"
-msgstr "Il file \"%s\" al è un socket."
+msgstr "L'element \"%s\" nol è un GstPreset"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not set preset \"%s\" in element \"%s\""
-msgstr "Impussibil creâ il file temporani \"%s\"."
+msgstr "impussibil stabilî la pre-configurazion \"%s\" tal element \"%s\""
 
 #, c-format
 msgid "no element \"%s\""
-msgstr ""
+msgstr "nissun element \"%s\""
 
 #, c-format
 msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
-msgstr ""
+msgstr "impussibil meti la proprietât \"%s\" tal element \"%s\" a \"%s\""
 
 #, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
 msgstr ""
+"impussibil meti la proprietât \"%s\" tal fi dal element \"%s\" a \"%s\""
 
 msgid "Delayed linking failed."
-msgstr ""
+msgstr "Nol è stât pussibil fâ il colegament intardât."
 
 #, c-format
 msgid "could not link %s to %s, %s can't handle caps %s"
-msgstr ""
+msgstr "impussibil colegâ %s a %s, %s nol rive a gjestî lis capacitâts %s"
 
 #, c-format
 msgid "could not link %s to %s, neither element can handle caps %s"
 msgstr ""
+"impussibil colegâ %s a %s, nissun dai doi elements al rive a gjestî lis "
+"capacitâts %s"
 
 #, c-format
 msgid "could not link %s to %s with caps %s"
-msgstr ""
+msgstr "impussibil colegâ %s a %s cu lis capacitâts %s"
 
 #, c-format
 msgid "could not link %s to %s"
-msgstr ""
+msgstr "impussibil colegâ %s a %s"
 
 #, c-format
 msgid "unexpected reference \"%s\" - ignoring"
-msgstr ""
+msgstr "riferiment \"%s\" inspietât - si ignore"
 
 #, c-format
 msgid "unexpected pad-reference \"%s\" - ignoring"
-msgstr ""
+msgstr "riferiment-pad \"%s\" inspietât - si ignore"
 
 #, c-format
 msgid "could not parse caps \"%s\""
-msgstr ""
+msgstr "impussibil analizâ lis capacitât \"%s\""
 
 #, c-format
 msgid "no sink element for URI \"%s\""
-msgstr ""
+msgstr "nissun element di destinazion pal URI \"%s\""
 
 #, c-format
 msgid "no source element for URI \"%s\""
-msgstr ""
+msgstr "nissun element sorzint pal URI \"%s\""
 
 msgid "syntax error"
 msgstr "erôr di sintassi"
 
 #, c-format
 msgid "specified empty bin \"%s\", not allowed"
-msgstr ""
+msgstr "specificât bin \"%s\" vueit, no consintût"
 
 #, c-format
 msgid "no bin \"%s\", unpacking elements"
-msgstr ""
+msgstr "nissun bin \"%s\", daûr a dispacâ i elements"
 
 msgid "empty pipeline not allowed"
-msgstr ""
+msgstr "la pipeline vueide no je ametude"
 
 msgid "Pipeline construction is invalid, please add queues."
-msgstr ""
+msgstr "La costrusion de pipeline no je valide, zonte codis di riproduzion."
 
 msgid "A lot of buffers are being dropped."
-msgstr ""
+msgstr "A vegnin scartâts une vore di buffers."
 
 msgid "Internal data flow problem."
-msgstr ""
+msgstr "Probleme di flus dâts interni."
 
 msgid "Internal data flow error."
-msgstr ""
+msgstr "Erôr di flus dâts interni."
 
 msgid "Internal clock error."
-msgstr ""
+msgstr "Erôr di orloi interni."
 
 msgid "Failed to map buffer."
-msgstr ""
+msgstr "Impussibil mapâ il buffer."
 
 msgid "Filter caps"
-msgstr ""
+msgstr "Filtre capacitâts"
 
 msgid ""
 "Restrict the possible allowed capabilities (NULL means ANY). Setting this "
 "property takes a reference to the supplied GstCaps object."
 msgstr ""
+"Limite lis pussibilis capacitâts consintudis (NULL al significhe DUTIS). La "
+"configurazion di cheste proprietât e cjape un riferiment al ogjet GstCaps "
+"indicât."
 
 msgid "Caps Change Mode"
-msgstr ""
+msgstr "Modalitât cambi capacitâts"
 
 msgid "Filter caps change behaviour"
-msgstr ""
+msgstr "Compuartament dal cambi dal filtri des capacitâts"
 
 msgid "No Temp directory specified."
 msgstr "Nissune cartele temporanie specificade."
@@ -972,7 +1022,7 @@ msgid "Could not open file \"%s\" for reading."
 msgstr "Impussibil vierzi il file \"%s\" pe leture."
 
 msgid "Error while writing to download file."
-msgstr ""
+msgstr "Erôr inte scriture dal file discjariât."
 
 msgid "No file name specified for writing."
 msgstr "Nissun non di file specificât pe scriture."
@@ -998,7 +1048,7 @@ msgstr "Nissun non di file specificât pe leture."
 
 #, c-format
 msgid "Could not get info on \"%s\"."
-msgstr ""
+msgstr "Impussibil otignî informazions su \"%s\"."
 
 #, c-format
 msgid "\"%s\" is a directory."
@@ -1009,25 +1059,25 @@ msgid "File \"%s\" is a socket."
 msgstr "Il file \"%s\" al è un socket."
 
 msgid "Failed after iterations as requested."
-msgstr ""
+msgstr "Erôr dopo des iterazions come domandadis."
 
 msgid "eos-after and error-after can't both be defined."
-msgstr ""
+msgstr "nol è pussibil definî ducj i doi eos-after e error-after."
 
 msgid "caps"
-msgstr ""
+msgstr "capacitâts"
 
 msgid "detected capabilities in stream"
-msgstr ""
+msgstr "rilevadis capacitâts tal flus"
 
 msgid "minimum"
-msgstr ""
+msgstr "minim"
 
 msgid "force caps"
-msgstr ""
+msgstr "sfuarce capacitâts"
 
 msgid "force caps without doing a typefind"
-msgstr ""
+msgstr "sfuarce lis capacitâts cence fâ un typefind"
 
 msgid "Stream doesn't contain enough data."
 msgstr "Il flus nol conten vonde dâts."
@@ -1035,40 +1085,47 @@ msgstr "Il flus nol conten vonde dâts."
 msgid "Stream contains no data."
 msgstr "Il flus nol conten dâts."
 
-#, fuzzy, c-format
+#, c-format
 msgid "%sImplemented Interfaces%s:\n"
-msgstr "Interfacis implementadis:\n"
+msgstr "%sInterfacis implementadis%s:\n"
+
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sInterfacis implementadis%s:\n"
 
 msgid "readable"
-msgstr ""
+msgstr "leibil"
 
 msgid "writable"
-msgstr ""
+msgstr "scrivibil"
 
 msgid "deprecated"
-msgstr ""
+msgstr "deplorât"
 
 msgid "controllable"
-msgstr ""
+msgstr "controlabil"
 
 msgid "conditionally available"
-msgstr ""
+msgstr "disponibil in mût condizionâl"
+
+msgid "can be set only at object construction time"
+msgstr "al è pussibil stabilîlu dome tal moment de costruzion dal ogjet"
 
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
-msgstr ""
+msgstr "al è pussibil cambiâlu tai stâts NULL, READY, PAUSED o PLAYING"
 
 msgid "changeable only in NULL, READY or PAUSED state"
-msgstr ""
+msgstr "al è pussibil cambiâlu nome tai stâts  NULL, READY o PAUSED"
 
 msgid "changeable only in NULL or READY state"
-msgstr ""
+msgstr "al è pussibil cambiâlu nome tai stâts NULL o READY"
 
 msgid "Blacklisted files:"
 msgstr "File te liste nere:"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%sTotal count%s: %s"
-msgstr "Conte totâl: "
+msgstr "%sConte totâl%s: %s"
 
 #, c-format
 msgid "%d blacklisted file"
@@ -1106,33 +1163,44 @@ msgid ""
 "                                       Useful in connection with external "
 "automatic plugin installation mechanisms"
 msgstr ""
+"Stampe une liste che la machine e pues analizâ di funzionalitâts di un "
+"plugin specificât o di ducj i plugins furnîts.\n"
+"                                       Util se doprât adun cun mecanisims "
+"esternis e automatics di instalazion dai plugins"
 
 msgid "List the plugin contents"
-msgstr ""
+msgstr "Liste i contignûts dal plugin"
 
 msgid ""
 "A slashes ('/') separated list of types of elements (also known as klass) to "
 "list. (unordered)"
 msgstr ""
+"Une liste separade di sbaris ('/') di gjenars di elements (cognossûts ancje "
+"come klass) di listâ. (cence ordin)"
 
 msgid "Check if the specified element or plugin exists"
-msgstr ""
+msgstr "Controle se l'element specificât o il plugin al esist"
 
 msgid ""
 "When checking if an element or plugin exists, also check that its version is "
 "at least the version specified"
 msgstr ""
+"Cuant che al ven controlât se un element o un plugin a esistin, controle "
+"ancje che la sô version e sedi almancul de version specificade"
 
 msgid "Print supported URI schemes, with the elements that implement them"
-msgstr ""
+msgstr "Stampe i schemis URI supuartâts, cui elements che ju implementin"
 
 msgid ""
 "Disable colors in output. You can also achieve the same by setting "
 "'GST_INSPECT_NO_COLORS' environment variable to any value."
 msgstr ""
+"Disative i colôrs te jessude. Tu puedis ancje rivâ al stes risultât "
+"configurant la variabile di ambient 'GST_INSPECT_NO_COLORS'  a un valôr che "
+"ti garbe."
 
 msgid "Color output, even when not sending to a tty."
-msgstr ""
+msgstr "Colore la jessude, ancje cuant che no ven mandade suntun tty."
 
 #, c-format
 msgid "Could not load plugin file: %s\n"
@@ -1140,75 +1208,77 @@ msgstr "Impussibil cjariâ file di plugin: %s\n"
 
 #, c-format
 msgid "No such element or plugin '%s'\n"
-msgstr ""
+msgstr "Nol esist un element o plugin '%s'\n"
 
 msgid "Index statistics"
 msgstr ""
 
 msgid "Setting pipeline to PLAYING ...\n"
-msgstr ""
+msgstr "Daûr a meti la pipeline a RIPRODUZION ...\n"
 
 msgid "ERROR: pipeline doesn't want to play.\n"
-msgstr ""
+msgstr "ERÔR: la pipeline no vûl riprodusi.\n"
 
 #, c-format
 msgid "Got message #%u from element \"%s\" (%s): "
-msgstr ""
+msgstr "Ricevût messaç #%u dal element \"%s\" (%s): "
 
 #, c-format
 msgid "Got message #%u from pad \"%s:%s\" (%s): "
-msgstr ""
+msgstr "Ricevût messaç #%u dal pad \"%s:%s\" (%s): "
 
 #, c-format
 msgid "Got message #%u from object \"%s\" (%s): "
-msgstr ""
+msgstr "Ricevût messaç #%u dal ogjet \"%s\" (%s): "
 
 #, c-format
 msgid "Got message #%u (%s): "
-msgstr ""
+msgstr "Ricevût messaç #%u (%s): "
 
 #, c-format
 msgid "Got EOS from element \"%s\".\n"
-msgstr ""
+msgstr "Ricevût EOS dal element \"%s\".\n"
 
 msgid "EOS received - stopping pipeline...\n"
-msgstr ""
+msgstr "Ricevût EOS - daûr a fermâ la pipeline...\n"
 
 #, c-format
 msgid "FOUND TAG      : found by element \"%s\".\n"
-msgstr ""
+msgstr "CJATADE ETICHETE      : cjatade dal element \"%s\".\n"
 
 #, c-format
 msgid "FOUND TAG      : found by pad \"%s:%s\".\n"
-msgstr ""
+msgstr "CJATADE ETICHETE      : cjatade dal pad \"%s:%s\".\n"
 
 #, c-format
 msgid "FOUND TAG      : found by object \"%s\".\n"
-msgstr ""
+msgstr "CJATADE ETICHETE      : cjatade dal ogjet \"%s\".\n"
 
 msgid "FOUND TAG\n"
-msgstr ""
+msgstr "CJATADE ETICEHTE\n"
 
 #, c-format
 msgid "FOUND TOC      : found by element \"%s\".\n"
-msgstr ""
+msgstr "CJATÂT TOC      : cjatât dal element \"%s\".\n"
 
 #, c-format
 msgid "FOUND TOC      : found by object \"%s\".\n"
-msgstr ""
+msgstr "CJATÂT TOC      : cjatât dal ogjet \"%s\".\n"
 
 msgid "FOUND TOC\n"
-msgstr ""
+msgstr "CJATÂT TOC\n"
 
 #, c-format
 msgid ""
 "INFO:\n"
 "%s\n"
 msgstr ""
+"INFORMAZION:\n"
+"%s\n"
 
 #, c-format
 msgid "WARNING: from element %s: %s\n"
-msgstr ""
+msgstr "ATENZION: dal element %s: %s\n"
 
 msgid "Pipeline is PREROLLED ...\n"
 msgstr ""
@@ -1220,35 +1290,38 @@ msgid "Prerolled, waiting for progress to finish...\n"
 msgstr ""
 
 msgid "buffering..."
-msgstr ""
+msgstr "daûr a jemplâ la memorie tampon..."
 
 msgid "Done buffering, setting pipeline to PLAYING ...\n"
 msgstr ""
+"Terminât di jemplâ la memorie tampon, daûr a meti la pipeline a "
+"RIPRODUZION ...\n"
 
 #. we were not buffering but PLAYING, PAUSE  the pipeline.
 msgid "Buffering, setting pipeline to PAUSED ...\n"
 msgstr ""
+"Daûr a jemplâ la memorie tampon, configurazion de pipeline a IN PAUSE ...\n"
 
 msgid "Redistribute latency...\n"
-msgstr ""
+msgstr "Redistribuìs latence...\n"
 
 #, c-format
 msgid "Setting state to %s as requested by %s...\n"
-msgstr ""
+msgstr "Daûr a meti il stât a %s come domandât di %s...\n"
 
 #. this application message is posted when we caught an interrupt and
 #. * we need to stop the pipeline.
 msgid "Interrupt: Stopping pipeline ...\n"
-msgstr ""
+msgstr "Interuzion: daûr a fermâ la pipeline ...\n"
 
 msgid "Interrupt while waiting for EOS - stopping pipeline...\n"
-msgstr ""
+msgstr "Interuzion dilunc la spiete pal EOS - daûr a fermâ la pipeline...\n"
 
 msgid "EOS on shutdown enabled -- Forcing EOS on the pipeline\n"
-msgstr ""
+msgstr "EOS al distudâ abilitât -- Daûr a sfuarçâ il EOS su la pipeline\n"
 
 msgid "Waiting for EOS...\n"
-msgstr ""
+msgstr "Daûr a spietâ il EOS...\n"
 
 #, c-format
 msgid "Progress: (%s) %s\n"
@@ -1260,80 +1333,96 @@ msgstr "Element mancjant: %s\n"
 
 #, c-format
 msgid "Got context from element '%s': %s=%s\n"
-msgstr ""
+msgstr "Ricevût contest dal element '%s': %s=%s\n"
 
 msgid "ERROR: pipeline doesn't want to preroll.\n"
 msgstr ""
 
 msgid "An error happened while waiting for EOS\n"
-msgstr ""
+msgstr "Al è capitât un erôr intant che si spietave il EOS\n"
 
 #, c-format
 msgid "Use Windows high-resolution clock, precision: %u ms\n"
 msgstr ""
+"Dopre l'orloi di sisteme di Windows a alte risoluzion, precision: %u ms\n"
 
 msgid "Output tags (also known as metadata)"
-msgstr ""
+msgstr "Etichetis di jessude (cognossudis ancje come metadâts)"
 
 msgid "Output TOC (chapters and editions)"
-msgstr ""
+msgstr "TOC di jessude (cjapitui e edizions)"
 
 msgid "Output status information and property notifications"
-msgstr ""
+msgstr "Informazions di stât di jessude e notifichis di proprietâts"
 
 msgid "Do not print any progress information"
 msgstr "No stâ stampâ nissune informazion di progrès"
 
 msgid "Output messages"
-msgstr ""
+msgstr "Messaçs di jessude"
 
 msgid ""
 "Do not output status information for the specified property if verbose "
 "output is enabled (can be used multiple times)"
 msgstr ""
+"No sta mandâ fûr lis informazions di stât pe proprietât indicade se la "
+"jessude prolisse e je abilitade (al è pussibil doprâle plui voltis)"
 
 msgid "PROPERTY-NAME"
-msgstr ""
+msgstr "NON-PROPRIETÂT"
+
+msgid "Set the name of the program"
+msgstr "Stabilìs il non dal program"
+
+msgid "PROGRAM-NAME"
+msgstr "NON-PROGRAM"
 
 msgid "Do not install a fault handler"
-msgstr ""
+msgstr "No sta instalâ un gjestôr di erôrs"
 
 msgid "Force EOS on sources before shutting the pipeline down"
-msgstr ""
+msgstr "Sfuarce l'EOS su lis sorzints prime di distudâ la pipeline"
 
 msgid "Gather and print index statistics"
-msgstr ""
+msgstr "Recupere e stampe lis statistichis de tabele"
 
 msgid ""
 "Do not print current position of pipeline. If this option is unspecified, "
 "the position will be printed when stdout is a TTY. To enable printing "
 "position when stdout is not a TTY, use \"force-position\" option"
 msgstr ""
+"No sta stampâ la posizion corinte de pipeline. Se cheste opzion no ven "
+"specificade e se il stdout al è un TTY, la posizion e vignarà stampade. Par "
+"abilitâ la stampe de posizion cuant che il stdout nol è un TTY, dopre la "
+"opzion \"force-position\""
 
 msgid ""
 "Allow printing current position of pipeline even if stdout is not a TTY. "
 "This option has no effect if the \"no-position\" option is specified"
 msgstr ""
+"Permet di stampâ la posizion corinte de pipeline ancje se il stdout nol è un "
+"TTY. Cheste opzion no à efiet se e je stade specificade la opzion “no-"
+"position”"
 
 #, c-format
 msgid "ERROR: pipeline could not be constructed: %s.\n"
-msgstr ""
+msgstr "ERÔR: nol è stât pussibil costruî la pipeline: %s.\n"
 
 msgid "ERROR: pipeline could not be constructed.\n"
-msgstr ""
+msgstr "ERÔR: nol è stât pussibil costruî la pipeline.\n"
 
 #, c-format
 msgid "WARNING: erroneous pipeline: %s\n"
-msgstr ""
+msgstr "ATENZION: pipeline sbaliade: %s\n"
 
 msgid "ERROR: the 'pipeline' element wasn't found.\n"
-msgstr ""
+msgstr "ERÔR: nol è stât cjatât l'element 'pipeline'.\n"
 
 msgid "Setting pipeline to PAUSED ...\n"
-msgstr ""
+msgstr "Daûr a meti la pipeline a IN PAUSE ...\n"
 
 msgid "Failed to set pipeline to PAUSED.\n"
-msgstr ""
+msgstr "Impussibil meti la pipeline a IN PAUSE.\n"
 
 msgid "Pipeline is live and does not need PREROLL ...\n"
 msgstr ""
@@ -1342,10 +1431,13 @@ msgid "Pipeline is PREROLLING ...\n"
 msgstr ""
 
 msgid "Execution ended after %"
-msgstr ""
+msgstr "Esecuzion finide dopo %"
 
 msgid "Setting pipeline to NULL ...\n"
-msgstr ""
+msgstr "Daûr a meti la pipeline a NULE ...\n"
 
 msgid "Freeing pipeline ...\n"
-msgstr ""
+msgstr "Daûr a liberâ la pipeline ...\n"
+
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Abilite lis diagnostichis prolissis pal cjariament dai plugins"
diff --git a/po/gl.po b/po/gl.po
index 92f0ee2..75e6a9d 100644
--- a/po/gl.po
+++ b/po/gl.po
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.0.3\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2012-12-15 03:29+0200\n"
 "Last-Translator: Fran Dieguez <frandieguez@ubuntu.com>\n"
 "Language-Team: Galician <proxecto@trasno.net>\n"
@@ -59,9 +59,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Desactivar depuración"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Activar a saída detallada do diagnóstico de carga de engadidos"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Rutas separadas por punto e coma contendo os engadidos"
 
@@ -833,6 +830,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1067,6 +1070,10 @@ msgstr "O fluxo non contén datos."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Interfaces implementadas:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "lexíbel"
 
@@ -1083,6 +1090,9 @@ msgstr "controlábel"
 msgid "conditionally available"
 msgstr "controlábel"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "intercambiábel entre os estados NULL, READY, PAUSED ou PLAYING"
 
@@ -1335,6 +1345,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "Non instalar un manexador predeterminado"
 
@@ -1391,6 +1407,9 @@ msgstr "Estabelecendo a tubería a NULL...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Liberando a tubería...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Activar a saída detallada do diagnóstico de carga de engadidos"
+
 #~ msgid "link without source element"
 #~ msgstr "ligazón sen elemento orixe"
 
diff --git a/po/gstreamer-1.0.pot b/po/gstreamer-1.0.pot
index 9db0207..413987b 100644
--- a/po/gstreamer-1.0.pot
+++ b/po/gstreamer-1.0.pot
@@ -6,9 +6,9 @@
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer-1.22.0\n"
+"Project-Id-Version: gstreamer-1.24.12\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 19:29+0000\n"
+"POT-Creation-Date: 2025-01-29 20:12+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -64,44 +64,40 @@ msgid "Disable debugging"
 msgstr ""
 
 #: gst/gst.c:276
-msgid "Enable verbose plugin loading diagnostics"
-msgstr ""
-
-#: gst/gst.c:280
 msgid "Colon-separated paths containing plugins"
 msgstr ""
 
-#: gst/gst.c:280
+#: gst/gst.c:276
 msgid "PATHS"
 msgstr ""
 
-#: gst/gst.c:283
+#: gst/gst.c:279
 msgid ""
 "Comma-separated list of plugins to preload in addition to the list stored in "
 "environment variable GST_PLUGIN_PATH"
 msgstr ""
 
-#: gst/gst.c:285
+#: gst/gst.c:281
 msgid "PLUGINS"
 msgstr ""
 
-#: gst/gst.c:288
+#: gst/gst.c:284
 msgid "Disable trapping of segmentation faults during plugin loading"
 msgstr ""
 
-#: gst/gst.c:293
+#: gst/gst.c:289
 msgid "Disable updating the registry"
 msgstr ""
 
-#: gst/gst.c:298
+#: gst/gst.c:294
 msgid "Disable spawning a helper process while scanning the registry"
 msgstr ""
 
-#: gst/gst.c:303
+#: gst/gst.c:299
 msgid "GStreamer Options"
 msgstr ""
 
-#: gst/gst.c:304
+#: gst/gst.c:300
 msgid "Show GStreamer Options"
 msgstr ""
 
@@ -307,11 +303,11 @@ msgstr ""
 msgid "No standard error message for domain %s and code %d."
 msgstr ""
 
-#: gst/gstpipeline.c:593
+#: gst/gstpipeline.c:600
 msgid "Selected clock cannot be used in pipeline."
 msgstr ""
 
-#: gst/gstregistry.c:1808
+#: gst/gstregistry.c:1890
 #, c-format
 msgid "Error writing registry cache to %s: %s"
 msgstr ""
@@ -1021,32 +1017,40 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+#: gst/gsttaglist.c:415
+msgid "container-specific-track-id"
+msgstr ""
+
+#: gst/gsttaglist.c:415
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
-#: gst/gsttaglist.c:452
+#: gst/gsttaglist.c:454
 msgid ", "
 msgstr ""
 
-#: gst/gsturi.c:641 gst/gsturi.c:814
+#: gst/gsturi.c:645 gst/gsturi.c:818
 #, c-format
 msgid "Invalid URI: %s"
 msgstr ""
 
-#: gst/gsturi.c:656
+#: gst/gsturi.c:660
 #, c-format
 msgid "No URI handler for the %s protocol found"
 msgstr ""
 
-#: gst/gsturi.c:836
+#: gst/gsturi.c:840
 #, c-format
 msgid "URI scheme '%s' not supported"
 msgstr ""
 
-#: gst/gstutils.c:2679 tools/gst-launch.c:350
+#: gst/gstutils.c:2683 tools/gst-launch.c:351
 #, c-format
 msgid "ERROR: from element %s: %s\n"
 msgstr ""
 
-#: gst/gstutils.c:2681 tools/gst-launch.c:352 tools/gst-launch.c:714
+#: gst/gstutils.c:2685 tools/gst-launch.c:353 tools/gst-launch.c:715
 #, c-format
 msgid ""
 "Additional debug info:\n"
@@ -1056,115 +1060,115 @@ msgstr ""
 #. ******************************************************************************************
 #. *** helpers for pipeline-setup
 #. ******************************************************************************************
-#: gst/parse/grammar.y.in:235
+#: gst/parse/grammar.y.in:295
 #, c-format
 msgid "link has no source [sink=%s@%p]"
 msgstr ""
 
-#: gst/parse/grammar.y.in:240
+#: gst/parse/grammar.y.in:300
 #, c-format
 msgid "link has no sink [source=%s@%p]"
 msgstr ""
 
-#: gst/parse/grammar.y.in:438
+#: gst/parse/grammar.y.in:501
 msgid "No such property."
 msgstr ""
 
-#: gst/parse/grammar.y.in:438 gst/parse/grammar.y.in:624
-#: gst/parse/grammar.y.in:658 gst/parse/grammar.y.in:770
+#: gst/parse/grammar.y.in:501 gst/parse/grammar.y.in:687
+#: gst/parse/grammar.y.in:721 gst/parse/grammar.y.in:835
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:533
+#: gst/parse/grammar.y.in:596
 #, c-format
 msgid "Element \"%s\" is not a GstPreset"
 msgstr ""
 
-#: gst/parse/grammar.y.in:539
+#: gst/parse/grammar.y.in:602
 #, c-format
 msgid "could not set preset \"%s\" in element \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:570
+#: gst/parse/grammar.y.in:633
 #, c-format
 msgid "no element \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:613 gst/parse/grammar.y.in:793
+#: gst/parse/grammar.y.in:676 gst/parse/grammar.y.in:858
 #, c-format
 msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:667
+#: gst/parse/grammar.y.in:730
 #, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:854
+#: gst/parse/grammar.y.in:919
 msgid "Delayed linking failed."
 msgstr ""
 
-#: gst/parse/grammar.y.in:1067 gst/parse/grammar.y.in:1072
+#: gst/parse/grammar.y.in:1132 gst/parse/grammar.y.in:1137
 #, c-format
 msgid "could not link %s to %s, %s can't handle caps %s"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1077
+#: gst/parse/grammar.y.in:1142
 #, c-format
 msgid "could not link %s to %s, neither element can handle caps %s"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1081
+#: gst/parse/grammar.y.in:1146
 #, c-format
 msgid "could not link %s to %s with caps %s"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1087
+#: gst/parse/grammar.y.in:1152
 #, c-format
 msgid "could not link %s to %s"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1238
+#: gst/parse/grammar.y.in:1306
 #, c-format
 msgid "unexpected reference \"%s\" - ignoring"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1244
+#: gst/parse/grammar.y.in:1312
 #, c-format
 msgid "unexpected pad-reference \"%s\" - ignoring"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1276 gst/parse/grammar.y.in:1285
+#: gst/parse/grammar.y.in:1346 gst/parse/grammar.y.in:1357
 #, c-format
 msgid "could not parse caps \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:1313
+#: gst/parse/grammar.y.in:1385
 #, c-format
 msgid "no sink element for URI \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:1332
+#: gst/parse/grammar.y.in:1404
 #, c-format
 msgid "no source element for URI \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:1422
+#: gst/parse/grammar.y.in:1494
 msgid "syntax error"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1445
+#: gst/parse/grammar.y.in:1517
 #, c-format
 msgid "specified empty bin \"%s\", not allowed"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1455
+#: gst/parse/grammar.y.in:1527
 #, c-format
 msgid "no bin \"%s\", unpacking elements"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1486
+#: gst/parse/grammar.y.in:1558
 msgid "empty pipeline not allowed"
 msgstr ""
 
@@ -1172,24 +1176,24 @@ msgstr ""
 msgid "Pipeline construction is invalid, please add queues."
 msgstr ""
 
-#: libs/gst/base/gstbasesink.c:3144
+#: libs/gst/base/gstbasesink.c:3148
 msgid "A lot of buffers are being dropped."
 msgstr ""
 
-#: libs/gst/base/gstbasesink.c:3799
+#: libs/gst/base/gstbasesink.c:3806
 msgid "Internal data flow problem."
 msgstr ""
 
-#: libs/gst/base/gstbasesink.c:4633 libs/gst/base/gstbasesrc.c:2773
+#: libs/gst/base/gstbasesink.c:4648 libs/gst/base/gstbasesrc.c:2818
 msgid "Internal data flow error."
 msgstr ""
 
-#: libs/gst/base/gstbasesrc.c:2703
+#: libs/gst/base/gstbasesrc.c:2748
 msgid "Internal clock error."
 msgstr ""
 
-#: libs/gst/base/gstbasesrc.c:2731 plugins/elements/gstdownloadbuffer.c:850
-#: plugins/elements/gstdownloadbuffer.c:1275
+#: libs/gst/base/gstbasesrc.c:2776 plugins/elements/gstdownloadbuffer.c:850
+#: plugins/elements/gstdownloadbuffer.c:1277
 msgid "Failed to map buffer."
 msgstr ""
 
@@ -1211,74 +1215,74 @@ msgstr ""
 msgid "Filter caps change behaviour"
 msgstr ""
 
-#: plugins/elements/gstdownloadbuffer.c:935 plugins/elements/gstqueue2.c:1818
+#: plugins/elements/gstdownloadbuffer.c:935 plugins/elements/gstqueue2.c:1847
 msgid "No Temp directory specified."
 msgstr ""
 
-#: plugins/elements/gstdownloadbuffer.c:941 plugins/elements/gstqueue2.c:1824
+#: plugins/elements/gstdownloadbuffer.c:941 plugins/elements/gstqueue2.c:1853
 #, c-format
 msgid "Could not create temp file \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstdownloadbuffer.c:949 plugins/elements/gstfilesrc.c:558
-#: plugins/elements/gstqueue2.c:1832
+#: plugins/elements/gstdownloadbuffer.c:949 plugins/elements/gstfilesrc.c:590
+#: plugins/elements/gstqueue2.c:1861
 #, c-format
 msgid "Could not open file \"%s\" for reading."
 msgstr ""
 
-#: plugins/elements/gstdownloadbuffer.c:1284 plugins/elements/gstqueue2.c:2270
+#: plugins/elements/gstdownloadbuffer.c:1286 plugins/elements/gstqueue2.c:2275
 msgid "Error while writing to download file."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:453
+#: plugins/elements/gstfilesink.c:502
 msgid "No file name specified for writing."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:459
+#: plugins/elements/gstfilesink.c:508
 #, c-format
 msgid "Could not open file \"%s\" for writing."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:471 plugins/elements/gstfilesink.c:475
+#: plugins/elements/gstfilesink.c:520 plugins/elements/gstfilesink.c:524
 #, c-format
 msgid "Error closing file \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:660
+#: plugins/elements/gstfilesink.c:709
 #, c-format
 msgid "Error while seeking in file \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:668 plugins/elements/gstfilesink.c:675
-#: plugins/elements/gstfilesink.c:928 plugins/elements/gstfilesink.c:1012
+#: plugins/elements/gstfilesink.c:717 plugins/elements/gstfilesink.c:724
+#: plugins/elements/gstfilesink.c:977 plugins/elements/gstfilesink.c:1061
 #, c-format
 msgid "Error while writing to file \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstfilesrc.c:546
+#: plugins/elements/gstfilesrc.c:578
 msgid "No file name specified for reading."
 msgstr ""
 
-#: plugins/elements/gstfilesrc.c:567
+#: plugins/elements/gstfilesrc.c:599
 #, c-format
 msgid "Could not get info on \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstfilesrc.c:573
+#: plugins/elements/gstfilesrc.c:605
 #, c-format
 msgid "\"%s\" is a directory."
 msgstr ""
 
-#: plugins/elements/gstfilesrc.c:580
+#: plugins/elements/gstfilesrc.c:612
 #, c-format
 msgid "File \"%s\" is a socket."
 msgstr ""
 
-#: plugins/elements/gstidentity.c:848
+#: plugins/elements/gstidentity.c:850
 msgid "Failed after iterations as requested."
 msgstr ""
 
-#: plugins/elements/gstidentity.c:1066
+#: plugins/elements/gstidentity.c:1068
 msgid "eos-after and error-after can't both be defined."
 msgstr ""
 
@@ -1311,89 +1315,93 @@ msgstr ""
 msgid "Stream contains no data."
 msgstr ""
 
-#: tools/gst-inspect.c:358
+#: tools/gst-inspect.c:359
 #, c-format
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
-#: tools/gst-inspect.c:469
+#: tools/gst-inspect.c:471
 msgid "readable"
 msgstr ""
 
-#: tools/gst-inspect.c:474
+#: tools/gst-inspect.c:476
 msgid "writable"
 msgstr ""
 
-#: tools/gst-inspect.c:479
+#: tools/gst-inspect.c:481
 msgid "deprecated"
 msgstr ""
 
-#: tools/gst-inspect.c:483
+#: tools/gst-inspect.c:485
 msgid "controllable"
 msgstr ""
 
-#: tools/gst-inspect.c:488
+#: tools/gst-inspect.c:490
 msgid "conditionally available"
 msgstr ""
 
-#: tools/gst-inspect.c:494
+#: tools/gst-inspect.c:496
+msgid "can be set only at object construction time"
+msgstr ""
+
+#: tools/gst-inspect.c:499
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
-#: tools/gst-inspect.c:497
+#: tools/gst-inspect.c:502
 msgid "changeable only in NULL, READY or PAUSED state"
 msgstr ""
 
-#: tools/gst-inspect.c:500
+#: tools/gst-inspect.c:505
 msgid "changeable only in NULL or READY state"
 msgstr ""
 
-#: tools/gst-inspect.c:1248
+#: tools/gst-inspect.c:1273
 msgid "Blacklisted files:"
 msgstr ""
 
-#: tools/gst-inspect.c:1263 tools/gst-inspect.c:1400
+#: tools/gst-inspect.c:1288 tools/gst-inspect.c:1427
 #, c-format
 msgid "%sTotal count%s: %s"
 msgstr ""
 
-#: tools/gst-inspect.c:1265
+#: tools/gst-inspect.c:1290
 #, c-format
 msgid "%d blacklisted file"
 msgid_plural "%d blacklisted files"
 msgstr[0] ""
 msgstr[1] ""
 
-#: tools/gst-inspect.c:1402
+#: tools/gst-inspect.c:1429
 #, c-format
 msgid "%d plugin"
 msgid_plural "%d plugins"
 msgstr[0] ""
 msgstr[1] ""
 
-#: tools/gst-inspect.c:1405
+#: tools/gst-inspect.c:1432
 #, c-format
 msgid "%d blacklist entry"
 msgid_plural "%d blacklist entries"
 msgstr[0] ""
 msgstr[1] ""
 
-#: tools/gst-inspect.c:1410
+#: tools/gst-inspect.c:1437
 #, c-format
 msgid "%d feature"
 msgid_plural "%d features"
 msgstr[0] ""
 msgstr[1] ""
 
-#: tools/gst-inspect.c:2114
+#: tools/gst-inspect.c:2188
 msgid "Print all elements"
 msgstr ""
 
-#: tools/gst-inspect.c:2116
+#: tools/gst-inspect.c:2190
 msgid "Print list of blacklisted files"
 msgstr ""
 
-#: tools/gst-inspect.c:2118
+#: tools/gst-inspect.c:2192
 msgid ""
 "Print a machine-parsable list of features the specified plugin or all "
 "plugins provide.\n"
@@ -1401,313 +1409,321 @@ msgid ""
 "automatic plugin installation mechanisms"
 msgstr ""
 
-#: tools/gst-inspect.c:2123
+#: tools/gst-inspect.c:2197
 msgid "List the plugin contents"
 msgstr ""
 
-#: tools/gst-inspect.c:2125
+#: tools/gst-inspect.c:2199
 msgid ""
 "A slashes ('/') separated list of types of elements (also known as klass) to "
 "list. (unordered)"
 msgstr ""
 
-#: tools/gst-inspect.c:2128
+#: tools/gst-inspect.c:2202
 msgid "Check if the specified element or plugin exists"
 msgstr ""
 
-#: tools/gst-inspect.c:2131
+#: tools/gst-inspect.c:2205
 msgid ""
 "When checking if an element or plugin exists, also check that its version is "
 "at least the version specified"
 msgstr ""
 
-#: tools/gst-inspect.c:2135
+#: tools/gst-inspect.c:2209
 msgid "Print supported URI schemes, with the elements that implement them"
 msgstr ""
 
-#: tools/gst-inspect.c:2140
+#: tools/gst-inspect.c:2214
 msgid ""
 "Disable colors in output. You can also achieve the same by setting "
 "'GST_INSPECT_NO_COLORS' environment variable to any value."
 msgstr ""
 
-#: tools/gst-inspect.c:2148
+#: tools/gst-inspect.c:2222
 msgid "Color output, even when not sending to a tty."
 msgstr ""
 
-#: tools/gst-inspect.c:2306
+#: tools/gst-inspect.c:2396
 #, c-format
 msgid "Could not load plugin file: %s\n"
 msgstr ""
 
-#: tools/gst-inspect.c:2312
+#: tools/gst-inspect.c:2402
 #, c-format
 msgid "No such element or plugin '%s'\n"
 msgstr ""
 
-#: tools/gst-launch.c:277
+#: tools/gst-launch.c:278
 msgid "Index statistics"
 msgstr ""
 
-#: tools/gst-launch.c:560
+#: tools/gst-launch.c:561
 msgid "Setting pipeline to PLAYING ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:566
+#: tools/gst-launch.c:567
 msgid "ERROR: pipeline doesn't want to play.\n"
 msgstr ""
 
-#: tools/gst-launch.c:592
+#: tools/gst-launch.c:593
 #, c-format
 msgid "Got message #%u from element \"%s\" (%s): "
 msgstr ""
 
-#: tools/gst-launch.c:596
+#: tools/gst-launch.c:597
 #, c-format
 msgid "Got message #%u from pad \"%s:%s\" (%s): "
 msgstr ""
 
-#: tools/gst-launch.c:600
+#: tools/gst-launch.c:601
 #, c-format
 msgid "Got message #%u from object \"%s\" (%s): "
 msgstr ""
 
-#: tools/gst-launch.c:604
+#: tools/gst-launch.c:605
 #, c-format
 msgid "Got message #%u (%s): "
 msgstr ""
 
-#: tools/gst-launch.c:635
+#: tools/gst-launch.c:636
 #, c-format
 msgid "Got EOS from element \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:639
+#: tools/gst-launch.c:640
 msgid "EOS received - stopping pipeline...\n"
 msgstr ""
 
-#: tools/gst-launch.c:648
+#: tools/gst-launch.c:649
 #, c-format
 msgid "FOUND TAG      : found by element \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:651
+#: tools/gst-launch.c:652
 #, c-format
 msgid "FOUND TAG      : found by pad \"%s:%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:654
+#: tools/gst-launch.c:655
 #, c-format
 msgid "FOUND TAG      : found by object \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:657
+#: tools/gst-launch.c:658
 msgid "FOUND TAG\n"
 msgstr ""
 
-#: tools/gst-launch.c:672
+#: tools/gst-launch.c:673
 #, c-format
 msgid "FOUND TOC      : found by element \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:675
+#: tools/gst-launch.c:676
 #, c-format
 msgid "FOUND TOC      : found by object \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:678
+#: tools/gst-launch.c:679
 msgid "FOUND TOC\n"
 msgstr ""
 
-#: tools/gst-launch.c:695
+#: tools/gst-launch.c:696
 #, c-format
 msgid ""
 "INFO:\n"
 "%s\n"
 msgstr ""
 
-#: tools/gst-launch.c:712
+#: tools/gst-launch.c:713
 #, c-format
 msgid "WARNING: from element %s: %s\n"
 msgstr ""
 
-#: tools/gst-launch.c:733
+#: tools/gst-launch.c:734
 msgid "Pipeline is PREROLLED ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:737
+#: tools/gst-launch.c:738
 msgid "Prerolled, waiting for buffering to finish...\n"
 msgstr ""
 
-#: tools/gst-launch.c:741
+#: tools/gst-launch.c:742
 msgid "Prerolled, waiting for progress to finish...\n"
 msgstr ""
 
-#: tools/gst-launch.c:754
+#: tools/gst-launch.c:755
 msgid "buffering..."
 msgstr ""
 
-#: tools/gst-launch.c:771
+#: tools/gst-launch.c:772
 msgid "Done buffering, setting pipeline to PLAYING ...\n"
 msgstr ""
 
 #. we were not buffering but PLAYING, PAUSE  the pipeline.
-#: tools/gst-launch.c:778
+#: tools/gst-launch.c:779
 msgid "Buffering, setting pipeline to PAUSED ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:787
+#: tools/gst-launch.c:788
 msgid "Redistribute latency...\n"
 msgstr ""
 
-#: tools/gst-launch.c:798
+#: tools/gst-launch.c:799
 #, c-format
 msgid "Setting state to %s as requested by %s...\n"
 msgstr ""
 
 #. this application message is posted when we caught an interrupt and
 #. * we need to stop the pipeline.
-#: tools/gst-launch.c:814
+#: tools/gst-launch.c:815
 msgid "Interrupt: Stopping pipeline ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:820
+#: tools/gst-launch.c:821
 msgid "Interrupt while waiting for EOS - stopping pipeline...\n"
 msgstr ""
 
-#: tools/gst-launch.c:825
+#: tools/gst-launch.c:826
 msgid "EOS on shutdown enabled -- Forcing EOS on the pipeline\n"
 msgstr ""
 
-#: tools/gst-launch.c:828
+#: tools/gst-launch.c:829
 msgid "Waiting for EOS...\n"
 msgstr ""
 
-#: tools/gst-launch.c:858
+#: tools/gst-launch.c:859
 #, c-format
 msgid "Progress: (%s) %s\n"
 msgstr ""
 
-#: tools/gst-launch.c:872
+#: tools/gst-launch.c:873
 #, c-format
 msgid "Missing element: %s\n"
 msgstr ""
 
-#: tools/gst-launch.c:886
+#: tools/gst-launch.c:887
 #, c-format
 msgid "Got context from element '%s': %s=%s\n"
 msgstr ""
 
-#: tools/gst-launch.c:990
+#: tools/gst-launch.c:991
 msgid "ERROR: pipeline doesn't want to preroll.\n"
 msgstr ""
 
-#: tools/gst-launch.c:992
+#: tools/gst-launch.c:993
 msgid "An error happened while waiting for EOS\n"
 msgstr ""
 
-#: tools/gst-launch.c:1061
+#: tools/gst-launch.c:1062
 #, c-format
 msgid "Use Windows high-resolution clock, precision: %u ms\n"
 msgstr ""
 
-#: tools/gst-launch.c:1092
+#: tools/gst-launch.c:1093
 msgid "Output tags (also known as metadata)"
 msgstr ""
 
-#: tools/gst-launch.c:1094
+#: tools/gst-launch.c:1095
 msgid "Output TOC (chapters and editions)"
 msgstr ""
 
-#: tools/gst-launch.c:1096
+#: tools/gst-launch.c:1097
 msgid "Output status information and property notifications"
 msgstr ""
 
-#: tools/gst-launch.c:1098
+#: tools/gst-launch.c:1099
 msgid "Do not print any progress information"
 msgstr ""
 
-#: tools/gst-launch.c:1100
+#: tools/gst-launch.c:1101
 msgid "Output messages"
 msgstr ""
 
-#: tools/gst-launch.c:1102
+#: tools/gst-launch.c:1103
 msgid ""
 "Do not output status information for the specified property if verbose "
 "output is enabled (can be used multiple times)"
 msgstr ""
 
-#: tools/gst-launch.c:1104
+#: tools/gst-launch.c:1105
 msgid "PROPERTY-NAME"
 msgstr ""
 
-#: tools/gst-launch.c:1106
-msgid "Do not install a fault handler"
+#: tools/gst-launch.c:1107
+msgid "Set the name of the program"
 msgstr ""
 
 #: tools/gst-launch.c:1108
+msgid "PROGRAM-NAME"
+msgstr ""
+
+#: tools/gst-launch.c:1110
+msgid "Do not install a fault handler"
+msgstr ""
+
+#: tools/gst-launch.c:1112
 msgid "Force EOS on sources before shutting the pipeline down"
 msgstr ""
 
-#: tools/gst-launch.c:1111
+#: tools/gst-launch.c:1115
 msgid "Gather and print index statistics"
 msgstr ""
 
-#: tools/gst-launch.c:1115
+#: tools/gst-launch.c:1119
 msgid ""
 "Do not print current position of pipeline. If this option is unspecified, "
 "the position will be printed when stdout is a TTY. To enable printing "
 "position when stdout is not a TTY, use \"force-position\" option"
 msgstr ""
 
-#: tools/gst-launch.c:1121
+#: tools/gst-launch.c:1125
 msgid ""
 "Allow printing current position of pipeline even if stdout is not a TTY. "
 "This option has no effect if the \"no-position\" option is specified"
 msgstr ""
 
-#: tools/gst-launch.c:1194
+#: tools/gst-launch.c:1213
 #, c-format
 msgid "ERROR: pipeline could not be constructed: %s.\n"
 msgstr ""
 
-#: tools/gst-launch.c:1198
+#: tools/gst-launch.c:1217
 msgid "ERROR: pipeline could not be constructed.\n"
 msgstr ""
 
-#: tools/gst-launch.c:1202
+#: tools/gst-launch.c:1221
 #, c-format
 msgid "WARNING: erroneous pipeline: %s\n"
 msgstr ""
 
-#: tools/gst-launch.c:1219
+#: tools/gst-launch.c:1238
 msgid "ERROR: the 'pipeline' element wasn't found.\n"
 msgstr ""
 
-#: tools/gst-launch.c:1268
+#: tools/gst-launch.c:1287
 msgid "Setting pipeline to PAUSED ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:1273
+#: tools/gst-launch.c:1292
 msgid "Failed to set pipeline to PAUSED.\n"
 msgstr ""
 
-#: tools/gst-launch.c:1277
+#: tools/gst-launch.c:1296
 msgid "Pipeline is live and does not need PREROLL ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:1281
+#: tools/gst-launch.c:1300
 msgid "Pipeline is PREROLLING ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:1325
+#: tools/gst-launch.c:1344
 msgid "Execution ended after %"
 msgstr ""
 
-#: tools/gst-launch.c:1342
+#: tools/gst-launch.c:1361
 msgid "Setting pipeline to NULL ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:1360
+#: tools/gst-launch.c:1379
 msgid "Freeing pipeline ...\n"
 msgstr ""
diff --git a/po/gstreamer.pot b/po/gstreamer.pot
index 9db0207..413987b 100644
--- a/po/gstreamer.pot
+++ b/po/gstreamer.pot
@@ -6,9 +6,9 @@
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer-1.22.0\n"
+"Project-Id-Version: gstreamer-1.24.12\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 19:29+0000\n"
+"POT-Creation-Date: 2025-01-29 20:12+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -64,44 +64,40 @@ msgid "Disable debugging"
 msgstr ""
 
 #: gst/gst.c:276
-msgid "Enable verbose plugin loading diagnostics"
-msgstr ""
-
-#: gst/gst.c:280
 msgid "Colon-separated paths containing plugins"
 msgstr ""
 
-#: gst/gst.c:280
+#: gst/gst.c:276
 msgid "PATHS"
 msgstr ""
 
-#: gst/gst.c:283
+#: gst/gst.c:279
 msgid ""
 "Comma-separated list of plugins to preload in addition to the list stored in "
 "environment variable GST_PLUGIN_PATH"
 msgstr ""
 
-#: gst/gst.c:285
+#: gst/gst.c:281
 msgid "PLUGINS"
 msgstr ""
 
-#: gst/gst.c:288
+#: gst/gst.c:284
 msgid "Disable trapping of segmentation faults during plugin loading"
 msgstr ""
 
-#: gst/gst.c:293
+#: gst/gst.c:289
 msgid "Disable updating the registry"
 msgstr ""
 
-#: gst/gst.c:298
+#: gst/gst.c:294
 msgid "Disable spawning a helper process while scanning the registry"
 msgstr ""
 
-#: gst/gst.c:303
+#: gst/gst.c:299
 msgid "GStreamer Options"
 msgstr ""
 
-#: gst/gst.c:304
+#: gst/gst.c:300
 msgid "Show GStreamer Options"
 msgstr ""
 
@@ -307,11 +303,11 @@ msgstr ""
 msgid "No standard error message for domain %s and code %d."
 msgstr ""
 
-#: gst/gstpipeline.c:593
+#: gst/gstpipeline.c:600
 msgid "Selected clock cannot be used in pipeline."
 msgstr ""
 
-#: gst/gstregistry.c:1808
+#: gst/gstregistry.c:1890
 #, c-format
 msgid "Error writing registry cache to %s: %s"
 msgstr ""
@@ -1021,32 +1017,40 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+#: gst/gsttaglist.c:415
+msgid "container-specific-track-id"
+msgstr ""
+
+#: gst/gsttaglist.c:415
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
-#: gst/gsttaglist.c:452
+#: gst/gsttaglist.c:454
 msgid ", "
 msgstr ""
 
-#: gst/gsturi.c:641 gst/gsturi.c:814
+#: gst/gsturi.c:645 gst/gsturi.c:818
 #, c-format
 msgid "Invalid URI: %s"
 msgstr ""
 
-#: gst/gsturi.c:656
+#: gst/gsturi.c:660
 #, c-format
 msgid "No URI handler for the %s protocol found"
 msgstr ""
 
-#: gst/gsturi.c:836
+#: gst/gsturi.c:840
 #, c-format
 msgid "URI scheme '%s' not supported"
 msgstr ""
 
-#: gst/gstutils.c:2679 tools/gst-launch.c:350
+#: gst/gstutils.c:2683 tools/gst-launch.c:351
 #, c-format
 msgid "ERROR: from element %s: %s\n"
 msgstr ""
 
-#: gst/gstutils.c:2681 tools/gst-launch.c:352 tools/gst-launch.c:714
+#: gst/gstutils.c:2685 tools/gst-launch.c:353 tools/gst-launch.c:715
 #, c-format
 msgid ""
 "Additional debug info:\n"
@@ -1056,115 +1060,115 @@ msgstr ""
 #. ******************************************************************************************
 #. *** helpers for pipeline-setup
 #. ******************************************************************************************
-#: gst/parse/grammar.y.in:235
+#: gst/parse/grammar.y.in:295
 #, c-format
 msgid "link has no source [sink=%s@%p]"
 msgstr ""
 
-#: gst/parse/grammar.y.in:240
+#: gst/parse/grammar.y.in:300
 #, c-format
 msgid "link has no sink [source=%s@%p]"
 msgstr ""
 
-#: gst/parse/grammar.y.in:438
+#: gst/parse/grammar.y.in:501
 msgid "No such property."
 msgstr ""
 
-#: gst/parse/grammar.y.in:438 gst/parse/grammar.y.in:624
-#: gst/parse/grammar.y.in:658 gst/parse/grammar.y.in:770
+#: gst/parse/grammar.y.in:501 gst/parse/grammar.y.in:687
+#: gst/parse/grammar.y.in:721 gst/parse/grammar.y.in:835
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:533
+#: gst/parse/grammar.y.in:596
 #, c-format
 msgid "Element \"%s\" is not a GstPreset"
 msgstr ""
 
-#: gst/parse/grammar.y.in:539
+#: gst/parse/grammar.y.in:602
 #, c-format
 msgid "could not set preset \"%s\" in element \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:570
+#: gst/parse/grammar.y.in:633
 #, c-format
 msgid "no element \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:613 gst/parse/grammar.y.in:793
+#: gst/parse/grammar.y.in:676 gst/parse/grammar.y.in:858
 #, c-format
 msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:667
+#: gst/parse/grammar.y.in:730
 #, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:854
+#: gst/parse/grammar.y.in:919
 msgid "Delayed linking failed."
 msgstr ""
 
-#: gst/parse/grammar.y.in:1067 gst/parse/grammar.y.in:1072
+#: gst/parse/grammar.y.in:1132 gst/parse/grammar.y.in:1137
 #, c-format
 msgid "could not link %s to %s, %s can't handle caps %s"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1077
+#: gst/parse/grammar.y.in:1142
 #, c-format
 msgid "could not link %s to %s, neither element can handle caps %s"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1081
+#: gst/parse/grammar.y.in:1146
 #, c-format
 msgid "could not link %s to %s with caps %s"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1087
+#: gst/parse/grammar.y.in:1152
 #, c-format
 msgid "could not link %s to %s"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1238
+#: gst/parse/grammar.y.in:1306
 #, c-format
 msgid "unexpected reference \"%s\" - ignoring"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1244
+#: gst/parse/grammar.y.in:1312
 #, c-format
 msgid "unexpected pad-reference \"%s\" - ignoring"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1276 gst/parse/grammar.y.in:1285
+#: gst/parse/grammar.y.in:1346 gst/parse/grammar.y.in:1357
 #, c-format
 msgid "could not parse caps \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:1313
+#: gst/parse/grammar.y.in:1385
 #, c-format
 msgid "no sink element for URI \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:1332
+#: gst/parse/grammar.y.in:1404
 #, c-format
 msgid "no source element for URI \"%s\""
 msgstr ""
 
-#: gst/parse/grammar.y.in:1422
+#: gst/parse/grammar.y.in:1494
 msgid "syntax error"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1445
+#: gst/parse/grammar.y.in:1517
 #, c-format
 msgid "specified empty bin \"%s\", not allowed"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1455
+#: gst/parse/grammar.y.in:1527
 #, c-format
 msgid "no bin \"%s\", unpacking elements"
 msgstr ""
 
-#: gst/parse/grammar.y.in:1486
+#: gst/parse/grammar.y.in:1558
 msgid "empty pipeline not allowed"
 msgstr ""
 
@@ -1172,24 +1176,24 @@ msgstr ""
 msgid "Pipeline construction is invalid, please add queues."
 msgstr ""
 
-#: libs/gst/base/gstbasesink.c:3144
+#: libs/gst/base/gstbasesink.c:3148
 msgid "A lot of buffers are being dropped."
 msgstr ""
 
-#: libs/gst/base/gstbasesink.c:3799
+#: libs/gst/base/gstbasesink.c:3806
 msgid "Internal data flow problem."
 msgstr ""
 
-#: libs/gst/base/gstbasesink.c:4633 libs/gst/base/gstbasesrc.c:2773
+#: libs/gst/base/gstbasesink.c:4648 libs/gst/base/gstbasesrc.c:2818
 msgid "Internal data flow error."
 msgstr ""
 
-#: libs/gst/base/gstbasesrc.c:2703
+#: libs/gst/base/gstbasesrc.c:2748
 msgid "Internal clock error."
 msgstr ""
 
-#: libs/gst/base/gstbasesrc.c:2731 plugins/elements/gstdownloadbuffer.c:850
-#: plugins/elements/gstdownloadbuffer.c:1275
+#: libs/gst/base/gstbasesrc.c:2776 plugins/elements/gstdownloadbuffer.c:850
+#: plugins/elements/gstdownloadbuffer.c:1277
 msgid "Failed to map buffer."
 msgstr ""
 
@@ -1211,74 +1215,74 @@ msgstr ""
 msgid "Filter caps change behaviour"
 msgstr ""
 
-#: plugins/elements/gstdownloadbuffer.c:935 plugins/elements/gstqueue2.c:1818
+#: plugins/elements/gstdownloadbuffer.c:935 plugins/elements/gstqueue2.c:1847
 msgid "No Temp directory specified."
 msgstr ""
 
-#: plugins/elements/gstdownloadbuffer.c:941 plugins/elements/gstqueue2.c:1824
+#: plugins/elements/gstdownloadbuffer.c:941 plugins/elements/gstqueue2.c:1853
 #, c-format
 msgid "Could not create temp file \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstdownloadbuffer.c:949 plugins/elements/gstfilesrc.c:558
-#: plugins/elements/gstqueue2.c:1832
+#: plugins/elements/gstdownloadbuffer.c:949 plugins/elements/gstfilesrc.c:590
+#: plugins/elements/gstqueue2.c:1861
 #, c-format
 msgid "Could not open file \"%s\" for reading."
 msgstr ""
 
-#: plugins/elements/gstdownloadbuffer.c:1284 plugins/elements/gstqueue2.c:2270
+#: plugins/elements/gstdownloadbuffer.c:1286 plugins/elements/gstqueue2.c:2275
 msgid "Error while writing to download file."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:453
+#: plugins/elements/gstfilesink.c:502
 msgid "No file name specified for writing."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:459
+#: plugins/elements/gstfilesink.c:508
 #, c-format
 msgid "Could not open file \"%s\" for writing."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:471 plugins/elements/gstfilesink.c:475
+#: plugins/elements/gstfilesink.c:520 plugins/elements/gstfilesink.c:524
 #, c-format
 msgid "Error closing file \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:660
+#: plugins/elements/gstfilesink.c:709
 #, c-format
 msgid "Error while seeking in file \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstfilesink.c:668 plugins/elements/gstfilesink.c:675
-#: plugins/elements/gstfilesink.c:928 plugins/elements/gstfilesink.c:1012
+#: plugins/elements/gstfilesink.c:717 plugins/elements/gstfilesink.c:724
+#: plugins/elements/gstfilesink.c:977 plugins/elements/gstfilesink.c:1061
 #, c-format
 msgid "Error while writing to file \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstfilesrc.c:546
+#: plugins/elements/gstfilesrc.c:578
 msgid "No file name specified for reading."
 msgstr ""
 
-#: plugins/elements/gstfilesrc.c:567
+#: plugins/elements/gstfilesrc.c:599
 #, c-format
 msgid "Could not get info on \"%s\"."
 msgstr ""
 
-#: plugins/elements/gstfilesrc.c:573
+#: plugins/elements/gstfilesrc.c:605
 #, c-format
 msgid "\"%s\" is a directory."
 msgstr ""
 
-#: plugins/elements/gstfilesrc.c:580
+#: plugins/elements/gstfilesrc.c:612
 #, c-format
 msgid "File \"%s\" is a socket."
 msgstr ""
 
-#: plugins/elements/gstidentity.c:848
+#: plugins/elements/gstidentity.c:850
 msgid "Failed after iterations as requested."
 msgstr ""
 
-#: plugins/elements/gstidentity.c:1066
+#: plugins/elements/gstidentity.c:1068
 msgid "eos-after and error-after can't both be defined."
 msgstr ""
 
@@ -1311,89 +1315,93 @@ msgstr ""
 msgid "Stream contains no data."
 msgstr ""
 
-#: tools/gst-inspect.c:358
+#: tools/gst-inspect.c:359
 #, c-format
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
-#: tools/gst-inspect.c:469
+#: tools/gst-inspect.c:471
 msgid "readable"
 msgstr ""
 
-#: tools/gst-inspect.c:474
+#: tools/gst-inspect.c:476
 msgid "writable"
 msgstr ""
 
-#: tools/gst-inspect.c:479
+#: tools/gst-inspect.c:481
 msgid "deprecated"
 msgstr ""
 
-#: tools/gst-inspect.c:483
+#: tools/gst-inspect.c:485
 msgid "controllable"
 msgstr ""
 
-#: tools/gst-inspect.c:488
+#: tools/gst-inspect.c:490
 msgid "conditionally available"
 msgstr ""
 
-#: tools/gst-inspect.c:494
+#: tools/gst-inspect.c:496
+msgid "can be set only at object construction time"
+msgstr ""
+
+#: tools/gst-inspect.c:499
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
-#: tools/gst-inspect.c:497
+#: tools/gst-inspect.c:502
 msgid "changeable only in NULL, READY or PAUSED state"
 msgstr ""
 
-#: tools/gst-inspect.c:500
+#: tools/gst-inspect.c:505
 msgid "changeable only in NULL or READY state"
 msgstr ""
 
-#: tools/gst-inspect.c:1248
+#: tools/gst-inspect.c:1273
 msgid "Blacklisted files:"
 msgstr ""
 
-#: tools/gst-inspect.c:1263 tools/gst-inspect.c:1400
+#: tools/gst-inspect.c:1288 tools/gst-inspect.c:1427
 #, c-format
 msgid "%sTotal count%s: %s"
 msgstr ""
 
-#: tools/gst-inspect.c:1265
+#: tools/gst-inspect.c:1290
 #, c-format
 msgid "%d blacklisted file"
 msgid_plural "%d blacklisted files"
 msgstr[0] ""
 msgstr[1] ""
 
-#: tools/gst-inspect.c:1402
+#: tools/gst-inspect.c:1429
 #, c-format
 msgid "%d plugin"
 msgid_plural "%d plugins"
 msgstr[0] ""
 msgstr[1] ""
 
-#: tools/gst-inspect.c:1405
+#: tools/gst-inspect.c:1432
 #, c-format
 msgid "%d blacklist entry"
 msgid_plural "%d blacklist entries"
 msgstr[0] ""
 msgstr[1] ""
 
-#: tools/gst-inspect.c:1410
+#: tools/gst-inspect.c:1437
 #, c-format
 msgid "%d feature"
 msgid_plural "%d features"
 msgstr[0] ""
 msgstr[1] ""
 
-#: tools/gst-inspect.c:2114
+#: tools/gst-inspect.c:2188
 msgid "Print all elements"
 msgstr ""
 
-#: tools/gst-inspect.c:2116
+#: tools/gst-inspect.c:2190
 msgid "Print list of blacklisted files"
 msgstr ""
 
-#: tools/gst-inspect.c:2118
+#: tools/gst-inspect.c:2192
 msgid ""
 "Print a machine-parsable list of features the specified plugin or all "
 "plugins provide.\n"
@@ -1401,313 +1409,321 @@ msgid ""
 "automatic plugin installation mechanisms"
 msgstr ""
 
-#: tools/gst-inspect.c:2123
+#: tools/gst-inspect.c:2197
 msgid "List the plugin contents"
 msgstr ""
 
-#: tools/gst-inspect.c:2125
+#: tools/gst-inspect.c:2199
 msgid ""
 "A slashes ('/') separated list of types of elements (also known as klass) to "
 "list. (unordered)"
 msgstr ""
 
-#: tools/gst-inspect.c:2128
+#: tools/gst-inspect.c:2202
 msgid "Check if the specified element or plugin exists"
 msgstr ""
 
-#: tools/gst-inspect.c:2131
+#: tools/gst-inspect.c:2205
 msgid ""
 "When checking if an element or plugin exists, also check that its version is "
 "at least the version specified"
 msgstr ""
 
-#: tools/gst-inspect.c:2135
+#: tools/gst-inspect.c:2209
 msgid "Print supported URI schemes, with the elements that implement them"
 msgstr ""
 
-#: tools/gst-inspect.c:2140
+#: tools/gst-inspect.c:2214
 msgid ""
 "Disable colors in output. You can also achieve the same by setting "
 "'GST_INSPECT_NO_COLORS' environment variable to any value."
 msgstr ""
 
-#: tools/gst-inspect.c:2148
+#: tools/gst-inspect.c:2222
 msgid "Color output, even when not sending to a tty."
 msgstr ""
 
-#: tools/gst-inspect.c:2306
+#: tools/gst-inspect.c:2396
 #, c-format
 msgid "Could not load plugin file: %s\n"
 msgstr ""
 
-#: tools/gst-inspect.c:2312
+#: tools/gst-inspect.c:2402
 #, c-format
 msgid "No such element or plugin '%s'\n"
 msgstr ""
 
-#: tools/gst-launch.c:277
+#: tools/gst-launch.c:278
 msgid "Index statistics"
 msgstr ""
 
-#: tools/gst-launch.c:560
+#: tools/gst-launch.c:561
 msgid "Setting pipeline to PLAYING ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:566
+#: tools/gst-launch.c:567
 msgid "ERROR: pipeline doesn't want to play.\n"
 msgstr ""
 
-#: tools/gst-launch.c:592
+#: tools/gst-launch.c:593
 #, c-format
 msgid "Got message #%u from element \"%s\" (%s): "
 msgstr ""
 
-#: tools/gst-launch.c:596
+#: tools/gst-launch.c:597
 #, c-format
 msgid "Got message #%u from pad \"%s:%s\" (%s): "
 msgstr ""
 
-#: tools/gst-launch.c:600
+#: tools/gst-launch.c:601
 #, c-format
 msgid "Got message #%u from object \"%s\" (%s): "
 msgstr ""
 
-#: tools/gst-launch.c:604
+#: tools/gst-launch.c:605
 #, c-format
 msgid "Got message #%u (%s): "
 msgstr ""
 
-#: tools/gst-launch.c:635
+#: tools/gst-launch.c:636
 #, c-format
 msgid "Got EOS from element \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:639
+#: tools/gst-launch.c:640
 msgid "EOS received - stopping pipeline...\n"
 msgstr ""
 
-#: tools/gst-launch.c:648
+#: tools/gst-launch.c:649
 #, c-format
 msgid "FOUND TAG      : found by element \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:651
+#: tools/gst-launch.c:652
 #, c-format
 msgid "FOUND TAG      : found by pad \"%s:%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:654
+#: tools/gst-launch.c:655
 #, c-format
 msgid "FOUND TAG      : found by object \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:657
+#: tools/gst-launch.c:658
 msgid "FOUND TAG\n"
 msgstr ""
 
-#: tools/gst-launch.c:672
+#: tools/gst-launch.c:673
 #, c-format
 msgid "FOUND TOC      : found by element \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:675
+#: tools/gst-launch.c:676
 #, c-format
 msgid "FOUND TOC      : found by object \"%s\".\n"
 msgstr ""
 
-#: tools/gst-launch.c:678
+#: tools/gst-launch.c:679
 msgid "FOUND TOC\n"
 msgstr ""
 
-#: tools/gst-launch.c:695
+#: tools/gst-launch.c:696
 #, c-format
 msgid ""
 "INFO:\n"
 "%s\n"
 msgstr ""
 
-#: tools/gst-launch.c:712
+#: tools/gst-launch.c:713
 #, c-format
 msgid "WARNING: from element %s: %s\n"
 msgstr ""
 
-#: tools/gst-launch.c:733
+#: tools/gst-launch.c:734
 msgid "Pipeline is PREROLLED ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:737
+#: tools/gst-launch.c:738
 msgid "Prerolled, waiting for buffering to finish...\n"
 msgstr ""
 
-#: tools/gst-launch.c:741
+#: tools/gst-launch.c:742
 msgid "Prerolled, waiting for progress to finish...\n"
 msgstr ""
 
-#: tools/gst-launch.c:754
+#: tools/gst-launch.c:755
 msgid "buffering..."
 msgstr ""
 
-#: tools/gst-launch.c:771
+#: tools/gst-launch.c:772
 msgid "Done buffering, setting pipeline to PLAYING ...\n"
 msgstr ""
 
 #. we were not buffering but PLAYING, PAUSE  the pipeline.
-#: tools/gst-launch.c:778
+#: tools/gst-launch.c:779
 msgid "Buffering, setting pipeline to PAUSED ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:787
+#: tools/gst-launch.c:788
 msgid "Redistribute latency...\n"
 msgstr ""
 
-#: tools/gst-launch.c:798
+#: tools/gst-launch.c:799
 #, c-format
 msgid "Setting state to %s as requested by %s...\n"
 msgstr ""
 
 #. this application message is posted when we caught an interrupt and
 #. * we need to stop the pipeline.
-#: tools/gst-launch.c:814
+#: tools/gst-launch.c:815
 msgid "Interrupt: Stopping pipeline ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:820
+#: tools/gst-launch.c:821
 msgid "Interrupt while waiting for EOS - stopping pipeline...\n"
 msgstr ""
 
-#: tools/gst-launch.c:825
+#: tools/gst-launch.c:826
 msgid "EOS on shutdown enabled -- Forcing EOS on the pipeline\n"
 msgstr ""
 
-#: tools/gst-launch.c:828
+#: tools/gst-launch.c:829
 msgid "Waiting for EOS...\n"
 msgstr ""
 
-#: tools/gst-launch.c:858
+#: tools/gst-launch.c:859
 #, c-format
 msgid "Progress: (%s) %s\n"
 msgstr ""
 
-#: tools/gst-launch.c:872
+#: tools/gst-launch.c:873
 #, c-format
 msgid "Missing element: %s\n"
 msgstr ""
 
-#: tools/gst-launch.c:886
+#: tools/gst-launch.c:887
 #, c-format
 msgid "Got context from element '%s': %s=%s\n"
 msgstr ""
 
-#: tools/gst-launch.c:990
+#: tools/gst-launch.c:991
 msgid "ERROR: pipeline doesn't want to preroll.\n"
 msgstr ""
 
-#: tools/gst-launch.c:992
+#: tools/gst-launch.c:993
 msgid "An error happened while waiting for EOS\n"
 msgstr ""
 
-#: tools/gst-launch.c:1061
+#: tools/gst-launch.c:1062
 #, c-format
 msgid "Use Windows high-resolution clock, precision: %u ms\n"
 msgstr ""
 
-#: tools/gst-launch.c:1092
+#: tools/gst-launch.c:1093
 msgid "Output tags (also known as metadata)"
 msgstr ""
 
-#: tools/gst-launch.c:1094
+#: tools/gst-launch.c:1095
 msgid "Output TOC (chapters and editions)"
 msgstr ""
 
-#: tools/gst-launch.c:1096
+#: tools/gst-launch.c:1097
 msgid "Output status information and property notifications"
 msgstr ""
 
-#: tools/gst-launch.c:1098
+#: tools/gst-launch.c:1099
 msgid "Do not print any progress information"
 msgstr ""
 
-#: tools/gst-launch.c:1100
+#: tools/gst-launch.c:1101
 msgid "Output messages"
 msgstr ""
 
-#: tools/gst-launch.c:1102
+#: tools/gst-launch.c:1103
 msgid ""
 "Do not output status information for the specified property if verbose "
 "output is enabled (can be used multiple times)"
 msgstr ""
 
-#: tools/gst-launch.c:1104
+#: tools/gst-launch.c:1105
 msgid "PROPERTY-NAME"
 msgstr ""
 
-#: tools/gst-launch.c:1106
-msgid "Do not install a fault handler"
+#: tools/gst-launch.c:1107
+msgid "Set the name of the program"
 msgstr ""
 
 #: tools/gst-launch.c:1108
+msgid "PROGRAM-NAME"
+msgstr ""
+
+#: tools/gst-launch.c:1110
+msgid "Do not install a fault handler"
+msgstr ""
+
+#: tools/gst-launch.c:1112
 msgid "Force EOS on sources before shutting the pipeline down"
 msgstr ""
 
-#: tools/gst-launch.c:1111
+#: tools/gst-launch.c:1115
 msgid "Gather and print index statistics"
 msgstr ""
 
-#: tools/gst-launch.c:1115
+#: tools/gst-launch.c:1119
 msgid ""
 "Do not print current position of pipeline. If this option is unspecified, "
 "the position will be printed when stdout is a TTY. To enable printing "
 "position when stdout is not a TTY, use \"force-position\" option"
 msgstr ""
 
-#: tools/gst-launch.c:1121
+#: tools/gst-launch.c:1125
 msgid ""
 "Allow printing current position of pipeline even if stdout is not a TTY. "
 "This option has no effect if the \"no-position\" option is specified"
 msgstr ""
 
-#: tools/gst-launch.c:1194
+#: tools/gst-launch.c:1213
 #, c-format
 msgid "ERROR: pipeline could not be constructed: %s.\n"
 msgstr ""
 
-#: tools/gst-launch.c:1198
+#: tools/gst-launch.c:1217
 msgid "ERROR: pipeline could not be constructed.\n"
 msgstr ""
 
-#: tools/gst-launch.c:1202
+#: tools/gst-launch.c:1221
 #, c-format
 msgid "WARNING: erroneous pipeline: %s\n"
 msgstr ""
 
-#: tools/gst-launch.c:1219
+#: tools/gst-launch.c:1238
 msgid "ERROR: the 'pipeline' element wasn't found.\n"
 msgstr ""
 
-#: tools/gst-launch.c:1268
+#: tools/gst-launch.c:1287
 msgid "Setting pipeline to PAUSED ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:1273
+#: tools/gst-launch.c:1292
 msgid "Failed to set pipeline to PAUSED.\n"
 msgstr ""
 
-#: tools/gst-launch.c:1277
+#: tools/gst-launch.c:1296
 msgid "Pipeline is live and does not need PREROLL ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:1281
+#: tools/gst-launch.c:1300
 msgid "Pipeline is PREROLLING ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:1325
+#: tools/gst-launch.c:1344
 msgid "Execution ended after %"
 msgstr ""
 
-#: tools/gst-launch.c:1342
+#: tools/gst-launch.c:1361
 msgid "Setting pipeline to NULL ...\n"
 msgstr ""
 
-#: tools/gst-launch.c:1360
+#: tools/gst-launch.c:1379
 msgid "Freeing pipeline ...\n"
 msgstr ""
diff --git a/po/hr.po b/po/hr.po
index e2889f7..258f597 100644
--- a/po/hr.po
+++ b/po/hr.po
@@ -1,4 +1,4 @@
-# Translation of gstreamer messages to Croatian.
+# Translat of gstreamer messages to Croatian.
 # This file is put in the public domain.
 # Copyright (C) 2004-2010, 2019 GStreamer core team.
 # This file is distributed under the same license as the gstreamer package.
@@ -7,13 +7,13 @@
 # https://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/index.html
 #
 # Tomislav Krznar <tomislav.krznar@gmail.com>, 2012.
-# Božidar Putanec <bozidarp@yahoo.com>, 2016, 2017, 2018, 2019, 2021, 2022.
+# Božidar Putanec <bozidarp@yahoo.com>, 2016, 2017, 2018, 2019, 2021, 2022, 2024.
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer-1.21.90\n"
+"Project-Id-Version: gstreamer-1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
-"PO-Revision-Date: 2023-01-16 11:03-0800\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-03-08 10:47-0800\n"
 "Last-Translator: Božidar Putanec <bozidarp@yahoo.com>\n"
 "Language-Team: Croatian <lokalizacija@linux.hr>\n"
 "Language: hr_HR\n"
@@ -66,9 +66,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "onemogući debugiranje"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "omogući opširne poruke tijekom učitavanja plugina"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "popis STAZA (odvojenih dvotočkom) koje sadrže plugine"
 
@@ -839,6 +836,12 @@ msgstr "privatni-podaci"
 msgid "Private data"
 msgstr "Privatni podaci"
 
+msgid "container-specific-track-id"
+msgstr "kontejner-specifični-zapis-id"
+
+msgid "Container-specific Track ID"
+msgstr "Kontejner-specifični ID Zapisa"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -947,7 +950,7 @@ msgid "no source element for URI \"%s\""
 msgstr "nema elementa-izvor za URI „%s“"
 
 msgid "syntax error"
-msgstr "sintaktična greška"
+msgstr "sintaktička greška"
 
 #, c-format
 msgid "specified empty bin \"%s\", not allowed"
@@ -1073,6 +1076,10 @@ msgstr "Tok ne sadrži podatke."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sRealizirana sučelja%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sRealizirana sučelja%s:\n"
+
 msgid "readable"
 msgstr "čitljivo"
 
@@ -1088,6 +1095,9 @@ msgstr "upravljivo"
 msgid "conditionally available"
 msgstr "uvjetno dostupno"
 
+msgid "can be set only at object construction time"
+msgstr "može se postaviti samo u vrijeme izgradnje objekta"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "promjenjivo u stanje NULL, READY, PAUSED ili PLAYING"
 
@@ -1348,12 +1358,18 @@ msgid ""
 "Do not output status information for the specified property if verbose "
 "output is enabled (can be used multiple times)"
 msgstr ""
-"ne ispiše status za IME-SVOJSTVA iako je\n"
-"                                      aktivna opcija za opširno ispisivanje"
+"ne ispiše status za IME-SVOJSTVA iako je aktivna opcija za opširno "
+"ispisivanje"
 
 msgid "PROPERTY-NAME"
 msgstr "IME-SVOJSTVA"
 
+msgid "Set the name of the program"
+msgstr "Postavi ime programa"
+
+msgid "PROGRAM-NAME"
+msgstr "IME-PROGRAMA"
+
 msgid "Do not install a fault handler"
 msgstr "ne instalira rutinu za obradu greški"
 
@@ -1416,6 +1432,9 @@ msgstr "Postavljamo cjevovod na NULL ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Cjevovod se prazni...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "omogući opširne poruke tijekom učitavanja plugina"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "GREŠKA: Cjevovod ne želi pauzirati.\n"
 
@@ -1491,4 +1510,4 @@ msgstr "Cjevovod se prazni...\n"
 #~ msgstr "Nemoj instalirati rukovatelj signala za SIGUSR1 i SIGUSR2"
 
 #~ msgid "Print alloc trace (if enabled at compile time)"
-#~ msgstr "Ispiši alloc praćenje (ako je omogućeno pri kompajliranju)"
+#~ msgstr "xxggIspiši alloc praćenje (ako je omogućeno pri kompajliranju)"
diff --git a/po/hu.po b/po/hu.po
index 3af8f4c..1106261 100644
--- a/po/hu.po
+++ b/po/hu.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.19.2\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2022-10-18 21:55+0200\n"
 "Last-Translator: Balázs Úr <ur.balazs@fsf.hu>\n"
 "Language-Team: Hungarian <translation-team-hu@lists.sourceforge.net>\n"
@@ -61,9 +61,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Hibakeresés letiltása"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Részletes bővítménybetöltési diagnosztika engedélyezése"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Bővítményeket tartalmazó útvonalak vesszőkkel elválasztott listája"
 
@@ -829,6 +826,12 @@ msgstr "privát-adatok"
 msgid "Private data"
 msgstr "Privát adatok"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1067,6 +1070,10 @@ msgstr "Az adatfolyam nem tartalmaz adatokat."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sMegvalósított felületek%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sMegvalósított felületek%s:\n"
+
 msgid "readable"
 msgstr "olvasható"
 
@@ -1082,6 +1089,9 @@ msgstr "vezérelhető"
 msgid "conditionally available"
 msgstr "feltételesen elérhető"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "módosítható a NULL, KÉSZ, SZÜNETEL vagy LEJÁTSZÁS állapotban"
 
@@ -1336,6 +1346,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "TULAJDONSÁGNÉV"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "TULAJDONSÁGNÉV"
+
 msgid "Do not install a fault handler"
 msgstr "Ne telepítsen hibakezelőt"
 
@@ -1397,3 +1414,6 @@ msgstr "Az adatcsatorna beállítása NULL értékre…\n"
 
 msgid "Freeing pipeline ...\n"
 msgstr "Adatcsatorna felszabadítása…\n"
+
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Részletes bővítménybetöltési diagnosztika engedélyezése"
diff --git a/po/id.po b/po/id.po
index f75d65c..e9904be 100644
--- a/po/id.po
+++ b/po/id.po
@@ -1,14 +1,14 @@
 # Indonesian translations for gstreamer package.
 # This file is put in the public domain.
-# Andika Triwidada <andika@gmail.com>, 2013, 2021, 2023.
+# Andika Triwidada <andika@gmail.com>, 2013, 2021, 2023, 2024.
 # Andhika Padmawan <andhika.padmawan@gmail.com>, 2010-2016.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.21.90\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
-"PO-Revision-Date: 2023-01-16 09:15+0700\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-03-07 19:31+0700\n"
 "Last-Translator: Andika Triwidada <andika@gmail.com>\n"
 "Language-Team: Indonesian <translation-team-id@lists.sourceforge.net>\n"
 "Language: id\n"
@@ -17,7 +17,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "X-Bugs: Report translation errors to the Language-Team address.\n"
-"X-Generator: Poedit 3.2.2\n"
+"X-Generator: Poedit 3.4.2\n"
 
 msgid "Print the GStreamer version"
 msgstr "Cetak versi GStreamer"
@@ -61,9 +61,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Nonaktifkan awakutu"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Mengaktifkan plugin verbose ketika memuat diagnosis"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Alamat dipisahkan tanda titik dua berisi plugin"
 
@@ -834,6 +831,12 @@ msgstr "data-privat"
 msgid "Private data"
 msgstr "Data privat"
 
+msgid "container-specific-track-id"
+msgstr "container-specific-track-id"
+
+msgid "Container-specific Track ID"
+msgstr "ID Lacak Spesifik Kontainer"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1077,6 +1080,10 @@ msgstr "Arus tidak berisi data."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sAntarmuka Terimplementasi%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sAntarmuka Terimplementasi%s:\n"
+
 msgid "readable"
 msgstr "dapat dibaca"
 
@@ -1092,6 +1099,9 @@ msgstr "dapat dikendalikan"
 msgid "conditionally available"
 msgstr "tersedia bersyarat"
 
+msgid "can be set only at object construction time"
+msgstr "dapat ditata hanya pada saat konstruksi objek"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "dapat diubah dalam kondisi NULL, READY, PAUSED atau PLAYING"
 
@@ -1344,6 +1354,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "NAMA-PROPERTI"
 
+msgid "Set the name of the program"
+msgstr "Atur nama program"
+
+msgid "PROGRAM-NAME"
+msgstr "NAMA-PROGRAM"
+
 msgid "Do not install a fault handler"
 msgstr "Jangan instal penanganan galat"
 
diff --git a/po/it.po b/po/it.po
index 61e4aaf..eda7d9b 100644
--- a/po/it.po
+++ b/po/it.po
@@ -108,7 +108,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer-1.15.1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2019-01-29 09:16+0100\n"
 "Last-Translator: Milo Casagrande <milo@milo.name>\n"
 "Language-Team: Italian <tp@lists.linux.it>\n"
@@ -169,10 +169,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Disabilita debug"
 
-# --gst-plugin-spew
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Abilita diagnostica prolissa del caricamento plugin"
-
 # --gst-plugin-path=PERCORSI
 msgid "Colon-separated paths containing plugins"
 msgstr "Percorsi che contengono i plugin separati da due punti (:)"
@@ -987,6 +983,12 @@ msgstr "dati privati"
 msgid "Private data"
 msgstr "dati privati"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1227,6 +1229,10 @@ msgstr "Lo stream non contiene dati."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sInterfacce implementate%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sInterfacce implementate%s:\n"
+
 msgid "readable"
 msgstr "leggibile"
 
@@ -1243,6 +1249,9 @@ msgstr "controllabile"
 msgid "conditionally available"
 msgstr "controllabile"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "può passare allo stato  NULL, READY, PAUSED o PLAYING"
 
@@ -1520,6 +1529,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "NOME-PROPRIETÀ"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "NOME-PROPRIETÀ"
+
 # -f, --no-fault
 msgid "Do not install a fault handler"
 msgstr "Non installa un gestore di fault"
@@ -1584,6 +1600,10 @@ msgstr "Impostazione della pipeline a NULL ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Esecuzione di free sulla pipeline...\n"
 
+# --gst-plugin-spew
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Abilita diagnostica prolissa del caricamento plugin"
+
 #, c-format
 #~ msgid "Error creating pipe: %s\n"
 #~ msgstr "Errore nel creare la pipe: %s\n"
diff --git a/po/ja.po b/po/ja.po
index 9948747..c3acc0f 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.0.3\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2013-08-20 14:56+0900\n"
 "Last-Translator: Makoto Kato <makoto.kt@gmail.com>\n"
 "Language-Team: Japanese <translation-team-ja@lists.sourceforge.net>\n"
@@ -53,9 +53,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "デバッグを無効にする"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr ""
-
 msgid "Colon-separated paths containing plugins"
 msgstr "プラグインを含むコロン (:) で区切られたパス"
 
@@ -798,6 +795,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1029,6 +1032,10 @@ msgstr "ストリームでデータが含まれていません"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "実装されているインターフェイス:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "読み込み可能"
 
@@ -1045,6 +1052,9 @@ msgstr "コントロール可能"
 msgid "conditionally available"
 msgstr "コントロール可能"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1293,6 +1303,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "フォールトハンドラをインストールしない"
 
diff --git a/po/ka.po b/po/ka.po
index d6bee83..682324e 100644
--- a/po/ka.po
+++ b/po/ka.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.19.2\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2022-04-17 15:35+0200\n"
 "Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n"
 "Language-Team: Georgian <(nothing)>\n"
@@ -54,9 +54,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "გამართვის გამორთვა"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "დამატებების დიაგნოსტიკური შეტყობინებების გამორთვა"
-
 msgid "Colon-separated paths containing plugins"
 msgstr ""
 
@@ -793,6 +790,12 @@ msgstr "private-data"
 msgid "Private data"
 msgstr "პირადი მონაცემები"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1023,6 +1026,10 @@ msgstr ""
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "კითხვადი"
 
@@ -1038,6 +1045,9 @@ msgstr "კონტროლირებადი"
 msgid "conditionally available"
 msgstr "პირობითად ხელმისაწვდომი"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "შეცვლადია NULL, READY, PAUSED და PLAYING მდგომარეობაში"
 
@@ -1281,6 +1291,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr ""
 
@@ -1335,3 +1351,6 @@ msgstr ""
 
 msgid "Freeing pipeline ...\n"
 msgstr ""
+
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "დამატებების დიაგნოსტიკური შეტყობინებების გამორთვა"
diff --git a/po/ko.po b/po/ko.po
index ebd711e..3bd590b 100644
--- a/po/ko.po
+++ b/po/ko.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.19.2\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2021-10-07 17:01+0900\n"
 "Last-Translator: SooHyun Kim <soohyunkim@kw.ac.kr>\n"
 "Language-Team: Korean <translation-team-ko@googlegroups.com>\n"
@@ -57,9 +57,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "디버깅 끄기"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "상세한 플러그인 로딩 진단 활성화"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "플러그인을 포함하는 콜론(:)으로 구분된 경로"
 
@@ -791,6 +788,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1019,6 +1022,10 @@ msgstr ""
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr ""
 
@@ -1034,6 +1041,9 @@ msgstr ""
 msgid "conditionally available"
 msgstr ""
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1273,6 +1283,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "오류 핸들러 설치하지 않기"
 
@@ -1329,3 +1345,6 @@ msgstr "파이프라인을 NULL로 만드는 중 ...\n"
 
 msgid "Freeing pipeline ...\n"
 msgstr "파이프라인 비우는 중 ...\n"
+
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "상세한 플러그인 로딩 진단 활성화"
diff --git a/po/lt.po b/po/lt.po
index bd5e293..9040a79 100644
--- a/po/lt.po
+++ b/po/lt.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 0.10.29.2\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2010-07-16 00:50+0300\n"
 "Last-Translator: Žygimantas Beručka <uid0@akl.lt>\n"
 "Language-Team: Lithuanian <komp_lt@konferencijos.lt>\n"
@@ -61,9 +61,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Išjungti derinimą"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Įjungti informatyvią įskiepių įkėlimo diagnostiką"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Dvitaškiais skiriami keliai, kur yra įskiepių"
 
@@ -838,6 +835,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1071,6 +1074,10 @@ msgstr "Sraute nėra duomenų."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Realizuotos sÄ…sajos:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "skaitomas"
 
@@ -1087,6 +1094,9 @@ msgstr "valdomas"
 msgid "conditionally available"
 msgstr "valdomas"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1341,6 +1351,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "Neįdiegti klaidų apdorojimo posistemės"
 
@@ -1397,6 +1413,9 @@ msgstr "Nustatomas konvejeris į NULL...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Atlaisvinamas konvejeris...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Įjungti informatyvią įskiepių įkėlimo diagnostiką"
+
 #~ msgid "link without source element"
 #~ msgstr "saitas be šaltinio elemento"
 
diff --git a/po/lv.po b/po/lv.po
new file mode 100644
index 0000000..374db0d
--- /dev/null
+++ b/po/lv.po
@@ -0,0 +1,1424 @@
+# Translation for gstreamer messages to Latvian
+# This file is distributed under the same license as the gstreamer package.
+# Rihards Priedītis <rprieditis@gmail>, 2023.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: gstreamer-1.21.90\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2023-12-25 17:53+0000\n"
+"Last-Translator: Rihards Priedītis <rprieditis@gmail.com>\n"
+"Language-Team: Latvian <translation-team-lv@lists.sourceforge.net>\n"
+"Language: lv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==0 || (n%100>=11 && n%100<=19) ? 0 : "
+"n%10==1 && n%100!=11 ? 1 : 2);\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 3.4.2\n"
+
+msgid "Print the GStreamer version"
+msgstr "Izdrukāt GStreamer versiju"
+
+msgid "Make all warnings fatal"
+msgstr "Padarīt visus brīdinājumus fatālus"
+
+msgid "Print available debug categories and exit"
+msgstr "Izdrukāt pieejamās atkļūdošanas kategorijas un iziet"
+
+msgid ""
+"Default debug level from 1 (only error) to 9 (anything) or 0 for no output"
+msgstr ""
+"Atkļūdošanas līmenis pēc noklusējuma no 1 (tikai kļūdas) līdz 9 (jebkas) vai "
+"0, bez izvades"
+
+msgid "LEVEL"
+msgstr "LĪMENIS"
+
+msgid ""
+"Comma-separated list of category_name:level pairs to set specific levels for "
+"the individual categories. Example: GST_AUTOPLUG:5,GST_ELEMENT_*:3"
+msgstr ""
+"Ar komatu atdalīts kategoriju_nosaukums:līmenis pāru saraksts, lai iestatītu "
+"konkrētus līmeņus atsevišķām kategorijām. Piemērs: GST_AUTOPLUG:5,"
+"GST_ELEMENT_*:3"
+
+msgid "LIST"
+msgstr "SARAKSTS"
+
+msgid "Disable colored debugging output"
+msgstr "Atslēgt krāsaino atkļūdošanas izvadi"
+
+msgid ""
+"Changes coloring mode of the debug log. Possible modes: off, on, disable, "
+"auto, unix"
+msgstr ""
+"Maina atkļūdošanas žurnāla krāsošanas režīmu. Iespējamie režīmi: off, on, "
+"disable, auto, unix"
+
+msgid "Disable debugging"
+msgstr "Deaktivizēt atkļūdošanu"
+
+msgid "Colon-separated paths containing plugins"
+msgstr "Ar kolu atdalīti spraudņu atrašanās direktoriju ceļi"
+
+msgid "PATHS"
+msgstr "CEĻI"
+
+msgid ""
+"Comma-separated list of plugins to preload in addition to the list stored in "
+"environment variable GST_PLUGIN_PATH"
+msgstr ""
+"Ar komatu atdalīts to spraudņu saraksts, kurus paredzēts ielādēt papildus "
+"vides mainīgajā GST_PLUGIN_PATH saglabātajam sarakstam"
+
+msgid "PLUGINS"
+msgstr "SPRAUDÅ…I"
+
+msgid "Disable trapping of segmentation faults during plugin loading"
+msgstr "Segmentācijas kļūdu izķeršanas atspējošana spraudņa ielādēšanas laikā"
+
+msgid "Disable updating the registry"
+msgstr "Atslēgt reģistra atjaunināšanu"
+
+msgid "Disable spawning a helper process while scanning the registry"
+msgstr "Atspējot palīgprocesa palaišanu, kamēr tiek skenēts reģistrs"
+
+msgid "GStreamer Options"
+msgstr "GStreamer Opcijas"
+
+msgid "Show GStreamer Options"
+msgstr "Rādīt GStreamer Opcijas"
+
+#, c-format
+msgid "Unknown option"
+msgstr "Nezināma opcija"
+
+msgid "GStreamer encountered a general core library error."
+msgstr "GStreamer sastapās ar vispārēju kodola bibliotēkas kļūdu."
+
+msgid ""
+"GStreamer developers were too lazy to assign an error code to this error."
+msgstr ""
+"GStreamer izstrādātāji bija pārāk slinki, lai šai kļūdai piešķirtu kļūdas "
+"kodu."
+
+msgid "Internal GStreamer error: code not implemented."
+msgstr "GStreamer iekšējā kļūda: kods nav ieviests."
+
+msgid ""
+"GStreamer error: state change failed and some element failed to post a "
+"proper error message with the reason for the failure."
+msgstr ""
+"GStreamer kļūda: stāvokļa maiņa neizdevās, un kāds elements nespēja nosūtīt "
+"pienācīgu kļūdas ziņojumu ar kļūdas iemeslu."
+
+msgid "Internal GStreamer error: pad problem."
+msgstr "Iekšējā GStreamer kļūda: savienotnes problēma."
+
+msgid "Internal GStreamer error: thread problem."
+msgstr "Iekšējā GStreamer kļūda: pavediena problēma."
+
+msgid "GStreamer error: negotiation problem."
+msgstr "GStreamer kļūda: pārrunu problēma."
+
+msgid "Internal GStreamer error: event problem."
+msgstr "GStreamer iekšējā kļūda: notikuma problēma."
+
+msgid "Internal GStreamer error: seek problem."
+msgstr "GStreamer iekšējā kļūda: meklēšanas problēma."
+
+msgid "Internal GStreamer error: caps problem."
+msgstr "GStreamer iekšējā kļūda: spēju problēma."
+
+msgid "Internal GStreamer error: tag problem."
+msgstr "GStreamer iekšējā kļūda: birku problēma."
+
+msgid "Your GStreamer installation is missing a plug-in."
+msgstr "Jūsu GStreamer instalācijai trūkst spraudnis."
+
+msgid "GStreamer error: clock problem."
+msgstr "GStreamer kļūda: pulksteņa problēma."
+
+msgid ""
+"This application is trying to use GStreamer functionality that has been "
+"disabled."
+msgstr ""
+"Šī programma mēģina izmantot GStreamer funkcionalitāti, kas ir atspējota."
+
+msgid "GStreamer encountered a general supporting library error."
+msgstr "GStreamer sastapās ar vispārēju atbalsta bibliotēkas kļūdu."
+
+msgid "Could not initialize supporting library."
+msgstr "Nevarēja inicializēt atbalsta bibliotēku."
+
+msgid "Could not close supporting library."
+msgstr "Nevarēja aizvērt atbalsta bibliotēku."
+
+msgid "Could not configure supporting library."
+msgstr "Nav izdevies konfigurēt atbalsta bibliotēku."
+
+msgid "Encoding error."
+msgstr "Kodēšanas kļūda."
+
+msgid "GStreamer encountered a general resource error."
+msgstr "GStreamer saskārās ar vispārēju resursu kļūdu."
+
+msgid "Resource not found."
+msgstr "Resurss nav atrasts."
+
+msgid "Resource busy or not available."
+msgstr "Resurss ir aizņemts vai nav pieejams."
+
+msgid "Could not open resource for reading."
+msgstr "Nevar atvērt resursu lasīšanai."
+
+msgid "Could not open resource for writing."
+msgstr "Nevar atvērt resursu rakstīšanai."
+
+msgid "Could not open resource for reading and writing."
+msgstr "Nevarēja atvērt resursu lasīšanai un rakstīšanai."
+
+msgid "Could not close resource."
+msgstr "Nevarēja aizvērt resursu."
+
+msgid "Could not read from resource."
+msgstr "Nevar nolasīt no resursa."
+
+msgid "Could not write to resource."
+msgstr "Nevar rakstīt uz resursu."
+
+msgid "Could not perform seek on resource."
+msgstr "Nevarēja veikt meklēšanu uz resursa."
+
+msgid "Could not synchronize on resource."
+msgstr "Nebija iespējams sinhronizēt resursu."
+
+msgid "Could not get/set settings from/on resource."
+msgstr "Nebija iespējams iegūt/uzstādīt iestatījumus no/uz resursa."
+
+msgid "No space left on the resource."
+msgstr "Resursā vairs nav vietas."
+
+msgid "Not authorized to access resource."
+msgstr "Nav atļauts piekļūt resursam."
+
+msgid "GStreamer encountered a general stream error."
+msgstr "GStreamer sastapās ar vispārēju plūsmas kļūdu."
+
+msgid "Element doesn't implement handling of this stream. Please file a bug."
+msgstr "Elements neimplementē šīs plūsmas apstrādi. Lūdzu, ziņojiet par kļūdu."
+
+msgid "Could not determine type of stream."
+msgstr "Nevar noteikt straumes veidu."
+
+msgid "The stream is of a different type than handled by this element."
+msgstr "Elements nevar strādāt ar straumi, jo tā ir cita tipa."
+
+msgid "There is no codec present that can handle the stream's type."
+msgstr "Nav neviena kodeka, kas varētu apstrādāt plūsmas tipu."
+
+msgid "Could not decode stream."
+msgstr "Nevar dekodēt plūsmu."
+
+msgid "Could not encode stream."
+msgstr "Nevarēja kodēt straumi."
+
+msgid "Could not demultiplex stream."
+msgstr "Nevarēja demultipleksēt plūsmu."
+
+msgid "Could not multiplex stream."
+msgstr "Nevarēja multipleksēt straumi."
+
+msgid "The stream is in the wrong format."
+msgstr "Straume ir nepareizā formātā."
+
+msgid "The stream is encrypted and decryption is not supported."
+msgstr "Straume ir šifrēta, un atšifrēšana netiek atbalstīta."
+
+msgid ""
+"The stream is encrypted and can't be decrypted because no suitable key has "
+"been supplied."
+msgstr ""
+"Straume ir šifrēta, un to nevar atšifrēt, jo nav izsniegta piemērota atslēga."
+
+#, c-format
+msgid "No error message for domain %s."
+msgstr "Domēnam %s nav kļūdas ziņojuma."
+
+#, c-format
+msgid "No standard error message for domain %s and code %d."
+msgstr "Domēnam %s un kodam %d nav standarta kļūdas ziņojuma."
+
+msgid "Selected clock cannot be used in pipeline."
+msgstr "Izvēlēto pulksteni nevar izmantot cauruļvadā."
+
+#, c-format
+msgid "Error writing registry cache to %s: %s"
+msgstr "Kļūda reģistra kešatmiņas ierakstīšanā %s: %s"
+
+msgid "title"
+msgstr "virsraksts"
+
+msgid "commonly used title"
+msgstr "bieži lietots nosaukums"
+
+msgid "title sortname"
+msgstr "virsraksts šķirotājvārds"
+
+msgid "commonly used title for sorting purposes"
+msgstr "bieži lietots nosaukums šķirošanas nolūkos"
+
+msgid "artist"
+msgstr "mākslinieks"
+
+msgid "person(s) responsible for the recording"
+msgstr "par ierakstu atbildīgā(-ās) persona(-as)"
+
+msgid "artist sortname"
+msgstr "mākslinieka šķirotājvārds"
+
+msgid "person(s) responsible for the recording for sorting purposes"
+msgstr ""
+"persona(-as), kas atbildīga(-as) par ieraksta veikšanu šķirošanas nolūkos"
+
+msgid "album"
+msgstr "albums"
+
+msgid "album containing this data"
+msgstr "albums, kurā atrodas šie dati"
+
+msgid "album sortname"
+msgstr "albuma šķirotājvārds"
+
+msgid "album containing this data for sorting purposes"
+msgstr "albums, kurā ir šie dati šķirošanas vajadzībām"
+
+msgid "album artist"
+msgstr "albuma mākslinieks"
+
+msgid "The artist of the entire album, as it should be displayed"
+msgstr "Visa albuma izpildītājs, kā tas būtu jāattēlo"
+
+msgid "album artist sortname"
+msgstr "albuma mākslinieka šķirotājvārds"
+
+msgid "The artist of the entire album, as it should be sorted"
+msgstr "Visa albuma mākslinieks, kā tas būtu jāšķiro"
+
+msgid "date"
+msgstr "datums"
+
+msgid "date the data was created (as a GDate structure)"
+msgstr "datu izveides datums (kā GDate struktūra)"
+
+msgid "datetime"
+msgstr "datuma un laiks"
+
+msgid "date and time the data was created (as a GstDateTime structure)"
+msgstr "datu izveidošanas datums un laiks (kā GstDateTime struktūra)"
+
+msgid "genre"
+msgstr "žanrs"
+
+msgid "genre this data belongs to"
+msgstr "žanrs šie dati pieder"
+
+msgid "comment"
+msgstr "komentārs"
+
+msgid "free text commenting the data"
+msgstr "brīvā teksta komentāri par datiem"
+
+msgid "extended comment"
+msgstr "paplašināts komentārs"
+
+msgid "free text commenting the data in key=value or key[en]=comment form"
+msgstr ""
+"brīvā teksta komentārs par datiem atslēga=vērtība vai atslēga[lv]=komentārs "
+"formā"
+
+msgid "track number"
+msgstr "celiņa numurs"
+
+msgid "track number inside a collection"
+msgstr "celiņa numurs kolekcijā"
+
+msgid "track count"
+msgstr "celiņu skaits"
+
+msgid "count of tracks inside collection this track belongs to"
+msgstr "celiņu skaits kolekcijā, kurai pieder šis celiņš"
+
+msgid "disc number"
+msgstr "diska numurs"
+
+msgid "disc number inside a collection"
+msgstr "diska numurs kolekcijā"
+
+msgid "disc count"
+msgstr "disku skaits"
+
+msgid "count of discs inside collection this disc belongs to"
+msgstr "disku skaits kolekcijā, kurai pieder šis disks"
+
+msgid "location"
+msgstr "atrašanās vieta"
+
+msgid ""
+"Origin of media as a URI (location, where the original of the file or stream "
+"is hosted)"
+msgstr ""
+"Multivides izcelsme kā URI (atrašanās vieta, kur ir izvietots faila vai "
+"plūsmas oriģināls)"
+
+msgid "homepage"
+msgstr "mājas lapa"
+
+msgid "Homepage for this media (i.e. artist or movie homepage)"
+msgstr ""
+"Šī multivides līdzekļa mājaslapa (t. i., mākslinieka vai filmas mājaslapa)"
+
+msgid "description"
+msgstr "apraksts"
+
+msgid "short text describing the content of the data"
+msgstr "īss teksts, kas apraksta datu saturu"
+
+msgid "version"
+msgstr "versija"
+
+msgid "version of this data"
+msgstr "šo datu versija"
+
+msgid "ISRC"
+msgstr "ISRC"
+
+msgid "International Standard Recording Code - see http://www.ifpi.org/isrc/"
+msgstr ""
+"Starptautiskais standarta ieraksta kods - skatīt http://www.ifpi.org/isrc/"
+
+msgid "organization"
+msgstr "organizācija"
+
+msgid "copyright"
+msgstr "autortiesības"
+
+msgid "copyright notice of the data"
+msgstr "paziņojums par datu autortiesībām"
+
+msgid "copyright uri"
+msgstr "autortiesības uri"
+
+msgid "URI to the copyright notice of the data"
+msgstr "URI uz datu autortiesību paziņojumu"
+
+msgid "encoded by"
+msgstr "kodēja"
+
+msgid "name of the encoding person or organization"
+msgstr "personas vai organizācijas nosaukums, kas kodēja"
+
+msgid "contact"
+msgstr "kontaktpersona"
+
+msgid "contact information"
+msgstr "kontaktinformācija"
+
+msgid "license"
+msgstr "licence"
+
+msgid "license of data"
+msgstr "datu licence"
+
+msgid "license uri"
+msgstr "licences uri"
+
+msgid "URI to the license of the data"
+msgstr "URI uz datu licenci"
+
+msgid "performer"
+msgstr "izpildītājs"
+
+msgid "person(s) performing"
+msgstr "persona(-as), kas izpildīja"
+
+msgid "composer"
+msgstr "komponistu"
+
+msgid "person(s) who composed the recording"
+msgstr "persona(-as), kura(-as) ir ieraksta autors(-es)"
+
+msgid "conductor"
+msgstr "diriģents"
+
+msgid "conductor/performer refinement"
+msgstr "diriģenta/izpildītāja pilnveidošana"
+
+msgid "duration"
+msgstr "ilgums"
+
+msgid "length in GStreamer time units (nanoseconds)"
+msgstr "garums GStreamer laika vienībās (nanosekundēs)"
+
+msgid "codec"
+msgstr "kodekss"
+
+msgid "codec the data is stored in"
+msgstr "kodekss, kurā dati tiek glabāti"
+
+msgid "video codec"
+msgstr "video kodekss"
+
+msgid "codec the video data is stored in"
+msgstr "kodekss, kurā tiek glabāti video dati"
+
+msgid "audio codec"
+msgstr "audio kodekss"
+
+msgid "codec the audio data is stored in"
+msgstr "kodekss, kurā tiek glabāti audio dati"
+
+msgid "subtitle codec"
+msgstr "subtitru kodekss"
+
+msgid "codec the subtitle data is stored in"
+msgstr "kodekss, kurā tiek saglabāti subtitru dati"
+
+msgid "container format"
+msgstr "konteinera formāts"
+
+msgid "container format the data is stored in"
+msgstr "konteinera formāts, kurā tiek glabāti dati"
+
+msgid "bitrate"
+msgstr "bitu pārraides ātrums"
+
+msgid "exact or average bitrate in bits/s"
+msgstr "precīzs vai vidējais bitu pārraides ātrums bitos/s"
+
+msgid "nominal bitrate"
+msgstr "nominālais bitu pārraides ātrums"
+
+msgid "nominal bitrate in bits/s"
+msgstr "nominālais bitu pārraides ātrums bitos/s"
+
+msgid "minimum bitrate"
+msgstr "minimālais bitu pārraides ātrums"
+
+msgid "minimum bitrate in bits/s"
+msgstr "minimālais bitu pārraides ātrums bitos/s"
+
+msgid "maximum bitrate"
+msgstr "maksimālais bitu pārraides ātrums"
+
+msgid "maximum bitrate in bits/s"
+msgstr "maksimālais bitu pārraides ātrums bitos/s"
+
+msgid "encoder"
+msgstr "kodētājs"
+
+msgid "encoder used to encode this stream"
+msgstr "kodētājs, kas izmantots šīs plūsmas kodēšanai"
+
+msgid "encoder version"
+msgstr "kodētāja versija"
+
+msgid "version of the encoder used to encode this stream"
+msgstr "šīs plūsmas kodēšanai izmantotā kodētāja versija"
+
+msgid "serial"
+msgstr "sērijas"
+
+msgid "serial number of track"
+msgstr "celiņa sērijas numurs"
+
+msgid "replaygain track gain"
+msgstr "replaygain celiņa pastiprinājums"
+
+msgid "track gain in db"
+msgstr "celiņa pastiprinājums db"
+
+msgid "replaygain track peak"
+msgstr "replaygain celiņa virsotne"
+
+msgid "peak of the track"
+msgstr "celiņa virsotne"
+
+msgid "replaygain album gain"
+msgstr "replaygain albuma pastiprinājums"
+
+msgid "album gain in db"
+msgstr "albuma pastiprinājums db"
+
+msgid "replaygain album peak"
+msgstr "replaygain albuma virsotne"
+
+msgid "peak of the album"
+msgstr "albuma virsotne"
+
+msgid "replaygain reference level"
+msgstr "replaygain atskaites līmenis"
+
+msgid "reference level of track and album gain values"
+msgstr "celiņa un albuma pastiprinājuma atskaites līmenis"
+
+msgid "language code"
+msgstr "valodas kods"
+
+msgid "language code for this stream, conforming to ISO-639-1 or ISO-639-2"
+msgstr "šīs plūsmas valodas kods, kas atbilst ISO-639-1 vai ISO-639-2"
+
+msgid "language name"
+msgstr "valodas nosaukums"
+
+msgid "freeform name of the language this stream is in"
+msgstr "valodas, kurā ir šī plūsma, nosaukums brīvā formā"
+
+msgid "image"
+msgstr "attēls"
+
+msgid "image related to this stream"
+msgstr "attēls, kas saistīts ar šo straumi"
+
+#. TRANSLATORS: 'preview image' = image that shows a preview of the full image
+msgid "preview image"
+msgstr "priekšskatījuma attēls"
+
+msgid "preview image related to this stream"
+msgstr "ar šo straumi saistītais priekšskatījuma attēls"
+
+msgid "attachment"
+msgstr "pielikums"
+
+msgid "file attached to this stream"
+msgstr "šai straumei pievienotais fails"
+
+msgid "beats per minute"
+msgstr "sitieni minūtē"
+
+msgid "number of beats per minute in audio"
+msgstr "sitienu skaits minūtē audio ierakstā"
+
+msgid "keywords"
+msgstr "atslēgas vārdi"
+
+msgid "comma separated keywords describing the content"
+msgstr "ar komatu atdalīti saturu raksturojoši atslēgvārdi"
+
+msgid "geo location name"
+msgstr "ģeogrāfiskās atrašanās vietas nosaukums"
+
+msgid ""
+"human readable descriptive location of where the media has been recorded or "
+"produced"
+msgstr ""
+"cilvēka lasāma aprakstoša atrašanās vieta, kur medijs ir ierakstīts vai "
+"izgatavots"
+
+msgid "geo location latitude"
+msgstr "ģeogrāfiskās atrašanās vietas platums"
+
+msgid ""
+"geo latitude location of where the media has been recorded or produced in "
+"degrees according to WGS84 (zero at the equator, negative values for "
+"southern latitudes)"
+msgstr ""
+"ģeogrāfiskais platuma grāds, kur ir ierakstīts vai radīts informācijas "
+"nesējs, saskaņā ar WGS84 (nulle pie ekvatora, negatīvas vērtības dienvidu "
+"platuma grādos)"
+
+msgid "geo location longitude"
+msgstr "ģeogrāfiskā atrašanās vietas garums"
+
+msgid ""
+"geo longitude location of where the media has been recorded or produced in "
+"degrees according to WGS84 (zero at the prime meridian in Greenwich/UK,  "
+"negative values for western longitudes)"
+msgstr ""
+"ģeogrāfiskais garums vietas, kur ir ierakstīts vai radīts informācijas "
+"nesējs, atrašanās vieta grādos saskaņā ar WGS84 (nulle pie Griničas "
+"meridiāna Lielbritānijā, negatīvas vērtības rietumu garuma grādiem)"
+
+msgid "geo location elevation"
+msgstr "ģeogrāfiskās atrašanās vietas augstums"
+
+msgid ""
+"geo elevation of where the media has been recorded or produced in meters "
+"according to WGS84 (zero is average sea level)"
+msgstr ""
+"ģeogrāfiskais augstums metros vietā, kur medijs ir ierakstīts vai radīts, "
+"saskaņā ar WGS84 (nulle ir vidējais jūras līmenis)"
+
+msgid "geo location country"
+msgstr "ģeogrāfiskā atrašanās vieta valsts"
+
+msgid "country (english name) where the media has been recorded or produced"
+msgstr ""
+"valsts (angliskais nosaukums), kurā plašsaziņas līdzeklis ir ierakstīts vai "
+"producēts"
+
+msgid "geo location city"
+msgstr "ģeogrāfiskā atrašanās vieta pilsēta"
+
+msgid "city (english name) where the media has been recorded or produced"
+msgstr ""
+"pilsēta (angliskais nosaukums), kurā plašsaziņas līdzeklis ir ierakstīts vai "
+"sagatavots"
+
+msgid "geo location sublocation"
+msgstr "ģeogrāfiskās atrašanās vietas apakšvieta"
+
+msgid ""
+"a location within a city where the media has been produced or created (e.g. "
+"the neighborhood)"
+msgstr "vieta pilsētā, kur medijs ir radīts vai veidots (piemēram, apkaime)"
+
+msgid "geo location horizontal error"
+msgstr "ģeogrāfiskās atrašanās vietas horizontālā kļūda"
+
+msgid "expected error of the horizontal positioning measures (in meters)"
+msgstr "horizontālās pozicionēšanas mērījumu paredzamā kļūda (metros)"
+
+msgid "geo location movement speed"
+msgstr "ģeogrāfiskās atrašanās vietas pārvietošanās ātrums"
+
+msgid ""
+"movement speed of the capturing device while performing the capture in m/s"
+msgstr "uztveršanas ierīces kustības ātrums uztveršanas laikā m/s"
+
+msgid "geo location movement direction"
+msgstr "ģeogrāfiskās atrašanās vietas kustības virziens"
+
+msgid ""
+"indicates the movement direction of the device performing the capture of a "
+"media. It is represented as degrees in floating point representation, 0 "
+"means the geographic north, and increases clockwise"
+msgstr ""
+"norāda tās ierīces kustības virzienu, kas veic datu nesēja uzņemšanu. Tas "
+"tiek attēlots grādos peldošā komata izteiksmē, 0 nozīmē ģeogrāfiskos "
+"ziemeļus un palielinās pulksteņrādītāja virzienā"
+
+msgid "geo location capture direction"
+msgstr "ģeogrāfiskās atrašanās vietas uzņemšanas virziens"
+
+msgid ""
+"indicates the direction the device is pointing to when capturing  a media. "
+"It is represented as degrees in floating point  representation, 0 means the "
+"geographic north, and increases clockwise"
+msgstr ""
+"norāda virzienu, uz kuru ierīce ir vērsta, kad tiek uztverts multivides "
+"nesējs. Tas tiek attēlots grādos peldošā komata izteiksmē, 0 nozīmē "
+"ģeogrāfiskos ziemeļus un palielinās pulksteņrādītāja rādītāja virzienā"
+
+#. TRANSLATORS: 'show name' = 'TV/radio/podcast show name' here
+msgid "show name"
+msgstr "parādīt nosaukumu"
+
+msgid "Name of the tv/podcast/series show the media is from"
+msgstr "Televīzijas/podkāsta/seriāla raidījuma nosaukums, no kura ir medijs"
+
+#. TRANSLATORS: 'show sortname' = 'TV/radio/podcast show name as used for sorting purposes' here
+msgid "show sortname"
+msgstr "parādīt šķiroto nosaukumu"
+
+msgid ""
+"Name of the tv/podcast/series show the media is from, for sorting purposes"
+msgstr ""
+"Televīzijas/podkāsta/seriāla raidījuma nosaukums, no kura ir medijs, "
+"šķirošanas nolūkos"
+
+msgid "episode number"
+msgstr "epizodes numurs"
+
+msgid "The episode number in the season the media is part of"
+msgstr "Epizodes numurs sezonā, kurā ir plašsaziņas līdzeklis"
+
+msgid "season number"
+msgstr "sezonas numurs"
+
+msgid "The season number of the show the media is part of"
+msgstr "Raidījuma sezonas numurs, kurā medijs piedalās"
+
+msgid "lyrics"
+msgstr "dziesmu vārdi"
+
+msgid "The lyrics of the media, commonly used for songs"
+msgstr "Medija vārdi, parasti izmanto dziesmām"
+
+msgid "composer sortname"
+msgstr "komponista šķirotājvārds"
+
+msgid "person(s) who composed the recording, for sorting purposes"
+msgstr ""
+"persona(-as), kura(-as) ir ieraksta komponists(-es), šķirošanas nolūkos"
+
+msgid "grouping"
+msgstr "grupēšana"
+
+msgid ""
+"Groups related media that spans multiple tracks, like the different pieces "
+"of a concerto. It is a higher level than a track, but lower than an album"
+msgstr ""
+"Grupē saistītus multivides materiālus, kas aptver vairākus skaņdarbus, "
+"piemēram, dažādus koncerta skaņdarbus. Tas ir augstāks līmenis nekā dziesma, "
+"bet zemāks nekā albums"
+
+msgid "user rating"
+msgstr "lietotāja vērtējums"
+
+msgid ""
+"Rating attributed by a user. The higher the rank, the more the user likes "
+"this media"
+msgstr ""
+"Lietotāja piešķirtais vērtējums. Jo augstāks rangs, jo vairāk lietotājam "
+"patīk šis medijs"
+
+msgid "device manufacturer"
+msgstr "ierīces ražotājs"
+
+msgid "Manufacturer of the device used to create this media"
+msgstr ""
+"Tā ierīces ražotājs, kas izmantota, lai izveidotu šo multivides līdzekli"
+
+msgid "device model"
+msgstr "ierīces modelis"
+
+msgid "Model of the device used to create this media"
+msgstr "Ierīces modelis, kas izmantots, lai izveidotu šo multivides kopiju"
+
+msgid "application name"
+msgstr "lietojumprogrammas nosaukums"
+
+msgid "Application used to create the media"
+msgstr "Multivides izveidei izmantotā lietojumprogramma"
+
+msgid "application data"
+msgstr "lietojumprogrammas dati"
+
+msgid "Arbitrary application data to be serialized into the media"
+msgstr "Multivides nesējā serializējamie patvaļīgi lietojumprogrammas dati"
+
+msgid "image orientation"
+msgstr "attēla orientācija"
+
+msgid "How the image should be rotated or flipped before display"
+msgstr "Kā attēls pirms rādīšanas ir jāpagriež vai jāapvērš"
+
+msgid "publisher"
+msgstr "izdevējs"
+
+msgid "Name of the label or publisher"
+msgstr "Marķējuma vai izdevniecības nosaukums"
+
+msgid "interpreted-by"
+msgstr "interpretēts"
+
+msgid "Information about the people behind a remix and similar interpretations"
+msgstr ""
+"Informācija par cilvēkiem, kas radījuši remiksu, un līdzīgas interpretācijas"
+
+msgid "midi-base-note"
+msgstr "midi-bāzes-nots"
+
+msgid "Midi note number of the audio track."
+msgstr "Audio celiņa Midi nots numurs."
+
+msgid "private-data"
+msgstr "privātie dati"
+
+msgid "Private data"
+msgstr "Privātie dati"
+
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
+#. separator between two strings
+msgid ", "
+msgstr ", "
+
+#, c-format
+msgid "Invalid URI: %s"
+msgstr "Nederīgs URI: %s"
+
+#, c-format
+msgid "No URI handler for the %s protocol found"
+msgstr "Nav atrasts URI apstrādātājs %s protokolam"
+
+#, c-format
+msgid "URI scheme '%s' not supported"
+msgstr "URI shēma '%s' netiek atbalstīta"
+
+#, c-format
+msgid "ERROR: from element %s: %s\n"
+msgstr "Kļūda: no elementa %s: %s\n"
+
+#, c-format
+msgid ""
+"Additional debug info:\n"
+"%s\n"
+msgstr ""
+"Papildu atkļūdošanas informācija:\n"
+"%s\n"
+
+#. ******************************************************************************************
+#. *** helpers for pipeline-setup
+#. ******************************************************************************************
+#, c-format
+msgid "link has no source [sink=%s@%p]"
+msgstr "saitei nav avota [izlietne=%s@%p]"
+
+#, c-format
+msgid "link has no sink [source=%s@%p]"
+msgstr "saitei nav izlietnes [avots=%s@%p]"
+
+msgid "No such property."
+msgstr "Šādas īpašības nav."
+
+#, c-format
+msgid "no property \"%s\" in element \"%s\""
+msgstr "nav īpašības \"%s\" elementā \"%s\""
+
+#, c-format
+msgid "Element \"%s\" is not a GstPreset"
+msgstr "Elements \"%s\" nav GstPreset"
+
+#, c-format
+msgid "could not set preset \"%s\" in element \"%s\""
+msgstr "nevarēja iestatīt iepriekš-noteikto \"%s\" elementā \"%s\""
+
+#, c-format
+msgid "no element \"%s\""
+msgstr "nav elementa \"%s\""
+
+#, c-format
+msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
+msgstr "nevarēja iestatīt īpašību \"%s\" elementā \"%s\" uz \"%s\""
+
+#, c-format
+msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
+msgstr "nevarēja iestatīt īpašību \"%s\" bērna elementā \"%s\" uz \"%s\""
+
+msgid "Delayed linking failed."
+msgstr "Aizkavēta savienošana neizdevās."
+
+#, c-format
+msgid "could not link %s to %s, %s can't handle caps %s"
+msgstr "nevarēja savienot %s ar %s, %s nevar apstrādāt iespējas %s"
+
+#, c-format
+msgid "could not link %s to %s, neither element can handle caps %s"
+msgstr ""
+"nevarēja savienot %s ar %s, neviens no elementiem nevar apstrādāt iespējas %s"
+
+#, c-format
+msgid "could not link %s to %s with caps %s"
+msgstr "nevarēja savienot %s ar %s ar iespējām %s"
+
+#, c-format
+msgid "could not link %s to %s"
+msgstr "nevarēja savienot %s ar %s"
+
+#, c-format
+msgid "unexpected reference \"%s\" - ignoring"
+msgstr "negaidīta atsauce \"%s\" - tiks ignorēts"
+
+#, c-format
+msgid "unexpected pad-reference \"%s\" - ignoring"
+msgstr "negaidīta pad-reference \"%s\" - tiks ignorēts"
+
+#, c-format
+msgid "could not parse caps \"%s\""
+msgstr "nevarēja analizēt iespējas \"%s\""
+
+#, c-format
+msgid "no sink element for URI \"%s\""
+msgstr "nav izlietnes elementa priekš URI \"%s\""
+
+#, c-format
+msgid "no source element for URI \"%s\""
+msgstr "nav avota elementa priekš URI \"%s\""
+
+msgid "syntax error"
+msgstr "sintakses kļūda"
+
+#, c-format
+msgid "specified empty bin \"%s\", not allowed"
+msgstr "norādīta tukša tvertne \"%s\", nav atļauts"
+
+#, c-format
+msgid "no bin \"%s\", unpacking elements"
+msgstr "nav tvertne \"%s\", elementu izpakošana"
+
+msgid "empty pipeline not allowed"
+msgstr "tukšs cauruļvads nav atļauts"
+
+msgid "Pipeline construction is invalid, please add queues."
+msgstr "Cauruļvada konstrukcija ir nederīga, lūdzu, pievienojiet rindas."
+
+msgid "A lot of buffers are being dropped."
+msgstr "Daudzi buferi tiek izmesti."
+
+msgid "Internal data flow problem."
+msgstr "Iekšējās datu plūsmas problēma."
+
+msgid "Internal data flow error."
+msgstr "Iekšējā datu plūsmas kļūda."
+
+msgid "Internal clock error."
+msgstr "Iekšējā pulksteņa kļūda."
+
+msgid "Failed to map buffer."
+msgstr "Neizdevās kartēt buferi."
+
+msgid "Filter caps"
+msgstr "Filtra iespējas"
+
+msgid ""
+"Restrict the possible allowed capabilities (NULL means ANY). Setting this "
+"property takes a reference to the supplied GstCaps object."
+msgstr ""
+"Ierobežojiet iespējamās atļautās iespējas (NULL nozīmē jebkuras). Nosakot šo "
+"īpašību, tiek iegūta atsauce uz norādīto GstCaps objektu."
+
+msgid "Caps Change Mode"
+msgstr "Iespējas Maiņas Režīms"
+
+msgid "Filter caps change behaviour"
+msgstr "Filtra iespēju maiņas uzvedība"
+
+msgid "No Temp directory specified."
+msgstr "Nav norādīta Temp direktorija."
+
+#, c-format
+msgid "Could not create temp file \"%s\"."
+msgstr "Nevar izveidot pagaidu failu \"%s\"."
+
+#, c-format
+msgid "Could not open file \"%s\" for reading."
+msgstr "Nevar atvērt failu \"%s\" lasīšanai."
+
+msgid "Error while writing to download file."
+msgstr "Kļūda, rakstot uz lejupielādes failu."
+
+msgid "No file name specified for writing."
+msgstr "Ierakstīšanai nav norādīts faila nosaukums."
+
+#, c-format
+msgid "Could not open file \"%s\" for writing."
+msgstr "Nevar atvērt failu \"%s\" rakstīšanai."
+
+#, c-format
+msgid "Error closing file \"%s\"."
+msgstr "Kļūda, aizverot failu \"%s\"."
+
+#, c-format
+msgid "Error while seeking in file \"%s\"."
+msgstr "Kļūda, meklējot failā \"%s\"."
+
+#, c-format
+msgid "Error while writing to file \"%s\"."
+msgstr "Kļūda, rakstot uz failu \"%s\"."
+
+msgid "No file name specified for reading."
+msgstr "Nav norādīts lasīšanai paredzētā faila nosaukums."
+
+#, c-format
+msgid "Could not get info on \"%s\"."
+msgstr "Nevar iegūt informāciju par \"%s\"."
+
+#, c-format
+msgid "\"%s\" is a directory."
+msgstr "\"%s\" ir direktorija."
+
+#, c-format
+msgid "File \"%s\" is a socket."
+msgstr "Fails \"%s\" ir kontaktligzda."
+
+msgid "Failed after iterations as requested."
+msgstr "Neizdevās pēc iterācijām, kā pieprasīts."
+
+msgid "eos-after and error-after can't both be defined."
+msgstr "eos-after un error-after nevar abi būt definēti."
+
+msgid "caps"
+msgstr "iespējas"
+
+msgid "detected capabilities in stream"
+msgstr "atrastās iespējas straumē"
+
+msgid "minimum"
+msgstr "minimālais"
+
+msgid "force caps"
+msgstr "piespiedu iespējas"
+
+msgid "force caps without doing a typefind"
+msgstr "piespiedu iespējas, neveicot tipa meklēšanu"
+
+msgid "Stream doesn't contain enough data."
+msgstr "Straumē nav pietiekami daudz datu."
+
+msgid "Stream contains no data."
+msgstr "Straumē nav datu."
+
+#, c-format
+msgid "%sImplemented Interfaces%s:\n"
+msgstr "%sĪstenotās Saskarnes%s:\n"
+
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sĪstenotās Saskarnes%s:\n"
+
+msgid "readable"
+msgstr "lasāms"
+
+msgid "writable"
+msgstr "rakstāms"
+
+msgid "deprecated"
+msgstr "novecojis"
+
+msgid "controllable"
+msgstr "kontrolējams"
+
+msgid "conditionally available"
+msgstr "nosacīti pieejams"
+
+msgid "can be set only at object construction time"
+msgstr ""
+
+msgid "changeable in NULL, READY, PAUSED or PLAYING state"
+msgstr "maināms NULL, READY, PAUSED vai PLAYING stāvoklī"
+
+msgid "changeable only in NULL, READY or PAUSED state"
+msgstr "maināms tikai NULL, READY vai PAUSED stāvoklī"
+
+msgid "changeable only in NULL or READY state"
+msgstr "maināms tikai NULL vai READY stāvoklī"
+
+msgid "Blacklisted files:"
+msgstr "Melnajā sarakstā iekļautie faili:"
+
+#, c-format
+msgid "%sTotal count%s: %s"
+msgstr "%sKopējais Skaits%s: %s"
+
+#, c-format
+msgid "%d blacklisted file"
+msgid_plural "%d blacklisted files"
+msgstr[0] "%d melnajā sarakstā iekļauti faili"
+msgstr[1] "%d melnajā sarakstā iekļauts fails"
+msgstr[2] "%d melnajā sarakstā iekļauti faili"
+
+#, c-format
+msgid "%d plugin"
+msgid_plural "%d plugins"
+msgstr[0] "%d spraudņu"
+msgstr[1] "%d spraudnis"
+msgstr[2] "%d spraudņi"
+
+#, c-format
+msgid "%d blacklist entry"
+msgid_plural "%d blacklist entries"
+msgstr[0] "%d melnā saraksta ierakstu"
+msgstr[1] "%d melnā saraksta ieraksts"
+msgstr[2] "%d melnā saraksta ieraksti"
+
+#, c-format
+msgid "%d feature"
+msgid_plural "%d features"
+msgstr[0] "%d funkciju"
+msgstr[1] "%d funkcija"
+msgstr[2] "%d funkcijas"
+
+msgid "Print all elements"
+msgstr "Drukāt visus elementus"
+
+msgid "Print list of blacklisted files"
+msgstr "Izdrukāt melnajā sarakstā iekļauto failu sarakstu"
+
+msgid ""
+"Print a machine-parsable list of features the specified plugin or all "
+"plugins provide.\n"
+"                                       Useful in connection with external "
+"automatic plugin installation mechanisms"
+msgstr ""
+"Izdrukāt mašīnlasāmu norādītā spraudņa vai visu spraudņu funkciju sarakstu.\n"
+"                                       Lietderīgi saistībā ar ārējiem "
+"automātiskās spraudņu instalēšanas mehānismiem"
+
+msgid "List the plugin contents"
+msgstr "Uzskaitīt spraudņa saturu"
+
+msgid ""
+"A slashes ('/') separated list of types of elements (also known as klass) to "
+"list. (unordered)"
+msgstr ""
+"Ar slīpsvītrām ('/') atdalīts saraksts ar elementu tipiem (pazīstams arī kā "
+"klass), ko uzskaitīt. (nesakārtots)"
+
+msgid "Check if the specified element or plugin exists"
+msgstr "Pārbaudiet, vai norādītais elements vai spraudnis pastāv"
+
+msgid ""
+"When checking if an element or plugin exists, also check that its version is "
+"at least the version specified"
+msgstr ""
+"Pārbaudot, vai elements vai spraudnis eksistē, pārbaudiet arī, vai tā "
+"versija ir vismaz norādītā versija"
+
+msgid "Print supported URI schemes, with the elements that implement them"
+msgstr "Drukāt atbalstītās URI shēmas ar elementiem, kas tās īsteno"
+
+msgid ""
+"Disable colors in output. You can also achieve the same by setting "
+"'GST_INSPECT_NO_COLORS' environment variable to any value."
+msgstr ""
+"Atslēgt krāsas izvadē. To pašu var panākt, iestatot vides mainīgajam "
+"'GST_INSPECT_NO_COLORS' jebkuru vērtību."
+
+msgid "Color output, even when not sending to a tty."
+msgstr "Krāsu izvade, pat ja netiek sūtīta uz tty."
+
+#, c-format
+msgid "Could not load plugin file: %s\n"
+msgstr "Nevar ielādēt spraudņa failu: %s\n"
+
+#, c-format
+msgid "No such element or plugin '%s'\n"
+msgstr "Nav šāda elementa vai spraudņa '%s'\n"
+
+msgid "Index statistics"
+msgstr "Indeksa statistika"
+
+msgid "Setting pipeline to PLAYING ...\n"
+msgstr "Cauruļvada iestatīšana uz PLAYING ...\n"
+
+msgid "ERROR: pipeline doesn't want to play.\n"
+msgstr "Kļūda: cauruļvads nevēlas spēlēt.\n"
+
+#, c-format
+msgid "Got message #%u from element \"%s\" (%s): "
+msgstr "Saņemts ziņojums #%u no elementa \"%s\" (%s): "
+
+#, c-format
+msgid "Got message #%u from pad \"%s:%s\" (%s): "
+msgstr "Saņemts ziņojums #%u no savienotnes \"%s:%s\" (%s): "
+
+#, c-format
+msgid "Got message #%u from object \"%s\" (%s): "
+msgstr "Saņemts ziņojums #%u no objekta \"%s\" (%s): "
+
+#, c-format
+msgid "Got message #%u (%s): "
+msgstr "Saņemts ziņojums #%u (%s): "
+
+#, c-format
+msgid "Got EOS from element \"%s\".\n"
+msgstr "Iegūts EOS no elementa \"%s\".\n"
+
+msgid "EOS received - stopping pipeline...\n"
+msgstr "EOS saņemts - cauruļvada apstādināšana...\n"
+
+#, c-format
+msgid "FOUND TAG      : found by element \"%s\".\n"
+msgstr "ATRASTA BIRKA      : atrasta ar elementu \"%s\".\n"
+
+#, c-format
+msgid "FOUND TAG      : found by pad \"%s:%s\".\n"
+msgstr "ATRASTA BIRKA      : atrasta ar savienotni \"%s:%s\".\n"
+
+#, c-format
+msgid "FOUND TAG      : found by object \"%s\".\n"
+msgstr "ATRASTA BIRKA      : atrasta ar objektu \"%s\".\n"
+
+msgid "FOUND TAG\n"
+msgstr "ATRASTA BIRKA\n"
+
+#, c-format
+msgid "FOUND TOC      : found by element \"%s\".\n"
+msgstr "ATRASTS SATURS      : atrasts ar elementu \"%s\".\n"
+
+#, c-format
+msgid "FOUND TOC      : found by object \"%s\".\n"
+msgstr "ATRASTS SATURS      : atrasts ar objektu \"%s\".\n"
+
+msgid "FOUND TOC\n"
+msgstr "ATRASTS SATURS\n"
+
+#, c-format
+msgid ""
+"INFO:\n"
+"%s\n"
+msgstr ""
+"INFO:\n"
+"%s\n"
+
+#, c-format
+msgid "WARNING: from element %s: %s\n"
+msgstr "BRĪDINĀJUMS: no elementa %s: %s\n"
+
+msgid "Pipeline is PREROLLED ...\n"
+msgstr "Cauruļvads ir PRIEKŠLĀDĒTS...\n"
+
+msgid "Prerolled, waiting for buffering to finish...\n"
+msgstr "Priekšielādēts, gaida, kad beigsies buferēšana...\n"
+
+msgid "Prerolled, waiting for progress to finish...\n"
+msgstr "Priekšielādēts, gaida, lai progress pabeigtu...\n"
+
+msgid "buffering..."
+msgstr "buferēšana..."
+
+msgid "Done buffering, setting pipeline to PLAYING ...\n"
+msgstr "Pabeigta buferizēšana, iestata cauruļvadu uz PLAYING ...\n"
+
+#. we were not buffering but PLAYING, PAUSE  the pipeline.
+msgid "Buffering, setting pipeline to PAUSED ...\n"
+msgstr "Buferēšana, iestata cauruļvadu uz PAUSED ...\n"
+
+msgid "Redistribute latency...\n"
+msgstr "Pārdalīt aizturi...\n"
+
+#, c-format
+msgid "Setting state to %s as requested by %s...\n"
+msgstr "Iestata stāvokli uz %s pēc %s pieprasījuma...\n"
+
+#. this application message is posted when we caught an interrupt and
+#. * we need to stop the pipeline.
+msgid "Interrupt: Stopping pipeline ...\n"
+msgstr "Pārtraukums: Cauruļvada apturēšana ...\n"
+
+msgid "Interrupt while waiting for EOS - stopping pipeline...\n"
+msgstr "Pārtraukums, gaidot EOS - cauruļvada apturēšana ...\n"
+
+msgid "EOS on shutdown enabled -- Forcing EOS on the pipeline\n"
+msgstr "Ieslēgta izslēgšana uz EOS -- EOS tiek uzspiests uz cauruļvada\n"
+
+msgid "Waiting for EOS...\n"
+msgstr "Gaida EOS...\n"
+
+#, c-format
+msgid "Progress: (%s) %s\n"
+msgstr "Progress: (%s) %s\n"
+
+#, c-format
+msgid "Missing element: %s\n"
+msgstr "Trūkstošais elements: %s\n"
+
+#, c-format
+msgid "Got context from element '%s': %s=%s\n"
+msgstr "Iegūt kontekstu no elementa '%s': %s=%s\n"
+
+msgid "ERROR: pipeline doesn't want to preroll.\n"
+msgstr "Kļūda: cauruļvads nevēlas veikt priekšielādi.\n"
+
+msgid "An error happened while waiting for EOS\n"
+msgstr "Gaidot EOS, notika kļūda\n"
+
+#, c-format
+msgid "Use Windows high-resolution clock, precision: %u ms\n"
+msgstr ""
+"Izmantojiet Windows augstas izšķirtspējas pulksteni, precizitāte: %u ms\n"
+
+msgid "Output tags (also known as metadata)"
+msgstr "Izvades birkas (zināmi arī kā metadati)"
+
+msgid "Output TOC (chapters and editions)"
+msgstr "Izvadīt Saturu (nodaļas un izdevumi)"
+
+msgid "Output status information and property notifications"
+msgstr "Izvadīt statusa informāciju un īpašības paziņojumus"
+
+msgid "Do not print any progress information"
+msgstr "Nedrukāt nekādu progresa informāciju"
+
+msgid "Output messages"
+msgstr "Izvada paziņojumi"
+
+msgid ""
+"Do not output status information for the specified property if verbose "
+"output is enabled (can be used multiple times)"
+msgstr ""
+"Neizvadīt norādītās īpašības statusa informāciju, ja ir iespējota detalizētā "
+"izvade (var izmantot vairākas reizes)"
+
+msgid "PROPERTY-NAME"
+msgstr "ĪPAŠĪBAS-NOSAUKUMS"
+
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "ĪPAŠĪBAS-NOSAUKUMS"
+
+msgid "Do not install a fault handler"
+msgstr "Neuzstādīt defektu apstrādātāju"
+
+msgid "Force EOS on sources before shutting the pipeline down"
+msgstr "Pirms avotu cauruļvada izslēgšanas uzspiest EOS"
+
+msgid "Gather and print index statistics"
+msgstr "Vākt un izdrukāt indeksa statistiku"
+
+msgid ""
+"Do not print current position of pipeline. If this option is unspecified, "
+"the position will be printed when stdout is a TTY. To enable printing "
+"position when stdout is not a TTY, use \"force-position\" option"
+msgstr ""
+"Nedrukāt cauruļvada pašreizējo pozīciju. Ja šī opcija nav norādīta, pozīcija "
+"tiks drukāta, ja stdout ir TTY. Lai ieslēgtu pozīcijas drukāšanu, ja stdout "
+"nav TTY, izmantojiet opciju \"force-position\""
+
+msgid ""
+"Allow printing current position of pipeline even if stdout is not a TTY. "
+"This option has no effect if the \"no-position\" option is specified"
+msgstr ""
+"Ļauj drukāt cauruļvada pašreizējo pozīciju pat tad, ja stdout nav TTY. Šai "
+"opcijai nav ietekmes, ja ir norādīta opcija \"no-position\""
+
+#, c-format
+msgid "ERROR: pipeline could not be constructed: %s.\n"
+msgstr "KĻŪDA: cauruļvadu nav iespējams izveidot: %s.\n"
+
+msgid "ERROR: pipeline could not be constructed.\n"
+msgstr "KĻŪDA: cauruļvadu nav iespējams izveidot.\n"
+
+#, c-format
+msgid "WARNING: erroneous pipeline: %s\n"
+msgstr "BRĪDINĀJUMS: kļūdains cauruļvads: %s\n"
+
+msgid "ERROR: the 'pipeline' element wasn't found.\n"
+msgstr "KĻŪDA: elements 'pipeline' nav atrasts.\n"
+
+msgid "Setting pipeline to PAUSED ...\n"
+msgstr "Cauruļvada iestatīšana uz PAUSED ...\n"
+
+msgid "Failed to set pipeline to PAUSED.\n"
+msgstr "Neizdevās iestatīt cauruļvadu uz PAUSED.\n"
+
+msgid "Pipeline is live and does not need PREROLL ...\n"
+msgstr "Cauruļvads ir dzīvs, un tam nav nepieciešams PREROLL ...\n"
+
+msgid "Pipeline is PREROLLING ...\n"
+msgstr "Cauruļvads ir PREROLLING ...\n"
+
+msgid "Execution ended after %"
+msgstr "Izpilde beidzās pēc %"
+
+msgid "Setting pipeline to NULL ...\n"
+msgstr "Cauruļvada iestatīšana uz NULL ...\n"
+
+msgid "Freeing pipeline ...\n"
+msgstr "Cauruļvada atbrīvošana ...\n"
+
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Ieslēgt detalizētu spraudņa ielādes diagnostiku"
diff --git a/po/nb.po b/po/nb.po
index d301287..20b9274 100644
--- a/po/nb.po
+++ b/po/nb.po
@@ -2,14 +2,14 @@
 # This file is put in the public domain.
 #
 # Kjartan Maraas <kmaraas@gnome.org>, 2004-2010.
-# Johnny A. Solbu <johnny@solbu.net>, 2015-2023
+# Johnny A. Solbu <johnny@solbu.net>, 2015-2024
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.21.90\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
-"PO-Revision-Date: 2023-01-15 14:22+0100\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-09-11 12:09+0200\n"
 "Last-Translator: Johnny A. Solbu <johnny@solbu.net>\n"
 "Language-Team: Norwegian Bokmaal <l10n-no@lister.huftis.org>\n"
 "Language: nb_NO\n"
@@ -18,7 +18,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 2.2.3\n"
+"X-Generator: Poedit 2.4.2\n"
 
 msgid "Print the GStreamer version"
 msgstr "Skriv ut versjonsnummer for GStreamer"
@@ -61,9 +61,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Slå av feilsøking"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Aktiver utførlig diagnostikk ved lasting av programtillegg"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Kolon-separerte stier som inneholder programtillegg"
 
@@ -422,7 +419,7 @@ msgid "encoded by"
 msgstr "kodet av"
 
 msgid "name of the encoding person or organization"
-msgstr "Navnet på personen eller organisasjonen som kodet"
+msgstr "navnet på personen eller organisasjonen som kodet"
 
 msgid "contact"
 msgstr "kontakt"
@@ -787,13 +784,13 @@ msgid "Model of the device used to create this media"
 msgstr "Modell av enheten som brukes til å lage dette mediet"
 
 msgid "application name"
-msgstr "Programnavn"
+msgstr "programnavn"
 
 msgid "Application used to create the media"
 msgstr "Program brukt til å lage mediet"
 
 msgid "application data"
-msgstr "Programdata"
+msgstr "programdata"
 
 msgid "Arbitrary application data to be serialized into the media"
 msgstr "Vilkårlige programdata som skal serialiseres i mediet"
@@ -828,6 +825,12 @@ msgstr "private-data"
 msgid "Private data"
 msgstr "Private data"
 
+msgid "container-specific-track-id"
+msgstr "container-specific-track-id"
+
+msgid "Container-specific Track ID"
+msgstr "Beholderspesifikk Spor-ID"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -876,7 +879,7 @@ msgstr "ingen egenskap «%s» i element «%s»"
 
 #, c-format
 msgid "Element \"%s\" is not a GstPreset"
-msgstr "Elementet «%s» er ikke en GstPreset."
+msgstr "Elementet «%s» er ikke en GstPreset"
 
 #, c-format
 msgid "could not set preset \"%s\" in element \"%s\""
@@ -936,7 +939,7 @@ msgid "no source element for URI \"%s\""
 msgstr "ingen kilde-element for URI «%s»"
 
 msgid "syntax error"
-msgstr "Syntaksfeil"
+msgstr "syntaksfeil"
 
 #, c-format
 msgid "specified empty bin \"%s\", not allowed"
@@ -947,7 +950,7 @@ msgid "no bin \"%s\", unpacking elements"
 msgstr "intet lager «%s», pakker ut elementer"
 
 msgid "empty pipeline not allowed"
-msgstr "Tom rørledning ikke tillatt"
+msgstr "tom rørledning ikke tillatt"
 
 msgid "Pipeline construction is invalid, please add queues."
 msgstr "Datakanal-konstruksjon er ugyldig, vennligst legg til køer."
@@ -962,7 +965,7 @@ msgid "Internal data flow error."
 msgstr "Intern feil med dataflyt."
 
 msgid "Internal clock error."
-msgstr "Feil i intern klokke"
+msgstr "Feil i intern klokke."
 
 msgid "Failed to map buffer."
 msgstr "Klarte ikke å kartlegge buffer."
@@ -1062,6 +1065,10 @@ msgstr "Strømmen inneholder ikke data."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sImplementerte grensesnitt%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sImplementerte grensesnitt%s:\n"
+
 msgid "readable"
 msgstr "lesbar"
 
@@ -1077,6 +1084,9 @@ msgstr "kontrollerbar"
 msgid "conditionally available"
 msgstr "betinget tilgjengelig"
 
+msgid "can be set only at object construction time"
+msgstr "kan kun settes på objektkonstruksjonstidspunktet"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "kan bare endres i NULL-, KLAR-, PAUSE- eller SPILLER-tilstand"
 
@@ -1308,7 +1318,7 @@ msgid "Use Windows high-resolution clock, precision: %u ms\n"
 msgstr "Bruk Windows høyoppløselig klokke, presisjon: %u ms\n"
 
 msgid "Output tags (also known as metadata)"
-msgstr "skriv ut tagger (også kjent som metadata)"
+msgstr "Skriv ut tagger (også kjent som metadata)"
 
 msgid "Output TOC (chapters and editions)"
 msgstr "Skriv ut TOC (kapitler og utgaver)"
@@ -1332,8 +1342,14 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "EGENSKAPSNAVN"
 
+msgid "Set the name of the program"
+msgstr "Angi navnet på programmet"
+
+msgid "PROGRAM-NAME"
+msgstr "PROGRAMNAVN"
+
 msgid "Do not install a fault handler"
-msgstr "ikke installer feilhåndterer"
+msgstr "Ikke installer feilhåndterer"
 
 msgid "Force EOS on sources before shutting the pipeline down"
 msgstr "Tvinge EOS på kilder før rørledningen stenges"
@@ -1349,7 +1365,7 @@ msgstr ""
 "Ikke skriv ut nåværende posisjon for rørledningen. Hvis dette alternativet "
 "er uspesifisert, blir posisjonen skrevet ut når std.ut er en TTY. For å "
 "aktivere utskriftsposisjon når std.ut ikke er en TTY, bruk «force-position»-"
-"alternativet "
+"alternativet"
 
 msgid ""
 "Allow printing current position of pipeline even if stdout is not a TTY. "
@@ -1394,6 +1410,9 @@ msgstr "Setter rørledning til NULL ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Frigjør rør ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Aktiver utførlig diagnostikk ved lasting av programtillegg"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "FEIL: rørledningen vil ikke pause\n"
 
diff --git a/po/nl.po b/po/nl.po
index 94dd657..2cf08c7 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -5,13 +5,14 @@
 #
 # Thomas Vander Stichele <thomas@apestaart.org>, 2004.
 # Taco Witte <tcwitte@cs.uu.nl>, 2006.
-# Freek de Kruijf <f.de.kruijf@gmail.com>, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2022.
+# SPDX-FileCopyrightText: 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2022, 2023, 2024
+# Freek de Kruijf <f.de.kruijf@gmail.com>, 2024
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.19.2\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
-"PO-Revision-Date: 2022-02-08 13:38+0100\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-10-14 13:52+0200\n"
 "Last-Translator: Freek de Kruijf <f.de.kruijf@gmail.com>\n"
 "Language-Team: Dutch <vertaling@vrijschrift.org>\n"
 "Language: nl\n"
@@ -20,7 +21,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Lokalize 21.12.2\n"
+"X-Generator: Lokalize 24.08.2\n"
 
 msgid "Print the GStreamer version"
 msgstr "Toon de GStreamer versie"
@@ -64,9 +65,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Debugging uit zetten"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Uitgebreide diagnostiek voor het laden van plugins aan zetten"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Dubbele punt-gescheiden lijst met paden met plugins"
 
@@ -841,6 +839,12 @@ msgstr "privégegevens"
 msgid "Private data"
 msgstr "Privégegevens"
 
+msgid "container-specific-track-id"
+msgstr "container-specifieke-track-id"
+
+msgid "Container-specific Track ID"
+msgstr "Container-specifieke-track-ID"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -881,7 +885,7 @@ msgid "link has no sink [source=%s@%p]"
 msgstr "link heeft geen sink [bron=%s@%p]"
 
 msgid "No such property."
-msgstr ""
+msgstr "Geen zo'n eigenschap."
 
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
@@ -903,9 +907,10 @@ msgstr "geen element \"%s\""
 msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
 msgstr "kon eigenschap \"%s\" in element \"%s\" niet op \"%s\" instellen"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
-msgstr "kon eigenschap \"%s\" in element \"%s\" niet op \"%s\" instellen"
+msgstr ""
+"kon eigenschap \"%s\" in kind van element \"%s\" niet op \"%s\" instellen"
 
 msgid "Delayed linking failed."
 msgstr "Vertraagd koppelen is mislukt."
@@ -1075,6 +1080,10 @@ msgstr "Stroom zonder gegevens."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sGeïmplementeerde interfaces%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sGeïmplementeerde interfaces%s:\n"
+
 msgid "readable"
 msgstr "leesbaar"
 
@@ -1090,6 +1099,9 @@ msgstr "controleerbaar"
 msgid "conditionally available"
 msgstr "voorwaardelijk beschikbaar"
 
+msgid "can be set only at object construction time"
+msgstr "kan alleen gezet worden bij constructiemoment van object"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "te veranderen in NUL, GEREED-, GEPAUZEERD- of SPEEL-status"
 
@@ -1346,6 +1358,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "NAAM-EIGENSCHAP"
 
+msgid "Set the name of the program"
+msgstr "Zet de naam van het programma"
+
+msgid "PROGRAM-NAME"
+msgstr "PROGRAMMA-NAAM"
+
 msgid "Do not install a fault handler"
 msgstr "Geen foutafhandelaar installeren"
 
@@ -1408,6 +1426,9 @@ msgstr "Pijplijn gezet op NULL ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Pijplijn wordt vrijgemaakt ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Uitgebreide diagnostiek voor het laden van plugins aan zetten"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "FOUT: pijplijn wil niet pauzeren.\n"
 
diff --git a/po/pl.po b/po/pl.po
index ae5b22d..5e56199 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -1,13 +1,13 @@
 # Polish translation for gstreamer.
 # This file is distributed under the same license as the gstreamer package.
-# Jakub Bogusz <qboosh@pld-linux.org>, 2007-2023.
+# Jakub Bogusz <qboosh@pld-linux.org>, 2007-2024.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.21.90\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
-"PO-Revision-Date: 2023-01-15 20:51+0100\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-03-07 20:30+0100\n"
 "Last-Translator: Jakub Bogusz <qboosh@pld-linux.org>\n"
 "Language-Team: Polish <translation-team-pl@lists.sourceforge.net>\n"
 "Language: pl\n"
@@ -60,9 +60,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Wyłączenie diagnostyki"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Włączenie szczegółowej diagnostyki wczytywania wtyczek"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Rozdzielone przecinkami ścieżki zawierające wtyczki"
 
@@ -834,6 +831,12 @@ msgstr "dane-prywatne"
 msgid "Private data"
 msgstr "Dane prywatne"
 
+msgid "container-specific-track-id"
+msgstr "id-ścieżki-zależne-od-kontenera"
+
+msgid "Container-specific Track ID"
+msgstr "Zależny od kontenera identyfikator ścieżki"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1069,6 +1072,10 @@ msgstr "Strumień nie zawiera danych."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sZaimplementowane interfejsy%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sZaimplementowane interfejsy%s:\n"
+
 msgid "readable"
 msgstr "odczyt"
 
@@ -1084,6 +1091,9 @@ msgstr "sterowanie"
 msgid "conditionally available"
 msgstr "warunkowo dostępne"
 
+msgid "can be set only at object construction time"
+msgstr "można ustawić tylko w czasie tworzenia obiektu"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "możliwa zmiana w stanie NULL, GOTOWOŚĆ, PAUZOWANIE lub ODTWARZANIE"
 
@@ -1345,6 +1355,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "NAZWA-WŁASNOŚCI"
 
+msgid "Set the name of the program"
+msgstr "Ustawienie nazwy programu"
+
+msgid "PROGRAM-NAME"
+msgstr "NAZWA-PROGRAMU"
+
 msgid "Do not install a fault handler"
 msgstr "Nie instalowanie obsługi błędów"
 
diff --git a/po/pt_BR.po b/po/pt_BR.po
index f7ee5f2..ae7e94c 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -1,7 +1,8 @@
 # Brazilian Portuguese translation of GStreamer.
-# Copyright (C) 2008-2021 Free Software Foundation, Inc.
+# Copyright (C) 2008-2024 Free Software Foundation, Inc.
 # This file is distributed under the same license as the GStreamer package.
 # Fabrício Godoy <skarllot@gmail.com>, 2008-2021.
+# Rafael Fontenelle <rafaelff@gnome.org>, 2024.
 #
 # pipeline -> fila de processamento
 # sink -> consumidor
@@ -16,11 +17,11 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer-1.19.2\n"
+"Project-Id-Version: gstreamer-1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
-"PO-Revision-Date: 2021-09-25 15:17-0300\n"
-"Last-Translator: Fabrício Godoy <skarllot@gmail.com>\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-10-09 11:12-0300\n"
+"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n"
 "Language-Team: Brazilian Portuguese <ldpbr-translation@lists.sourceforge."
 "net>\n"
 "Language: pt_BR\n"
@@ -28,8 +29,8 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "X-Bugs: Report translation errors to the Language-Team address.\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: Poedit 3.0\n"
+"Plural-Forms: nplurals=2; plural=(n > 1)\n"
+"X-Generator: Gtranslator 47.0\n"
 
 msgid "Print the GStreamer version"
 msgstr "Exibir a versão do GStreamer"
@@ -73,9 +74,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Desabilitar depuração"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Habilitar diagnóstico detalhado do carregamento do plug-in"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Caminhos, separados por dois-pontos, de plug-ins"
 
@@ -832,7 +830,7 @@ msgid "Name of the label or publisher"
 msgstr "Nome da gravadora ou editora"
 
 msgid "interpreted-by"
-msgstr "interpretado por"
+msgstr "interpretado-por"
 
 msgid "Information about the people behind a remix and similar interpretations"
 msgstr ""
@@ -850,6 +848,12 @@ msgstr "dados-privados"
 msgid "Private data"
 msgstr "Dados privados"
 
+msgid "container-specific-track-id"
+msgstr "id-trilha-específica-contêiner"
+
+msgid "Container-specific Track ID"
+msgstr "ID da trilha específico do contêiner"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -890,7 +894,7 @@ msgid "link has no sink [source=%s@%p]"
 msgstr "não há consumidor no link [source=%s@%p]"
 
 msgid "No such property."
-msgstr ""
+msgstr "Não existe tal propriedade."
 
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
@@ -914,11 +918,11 @@ msgstr ""
 "não foi possível definir a propriedade \"%s\" no elemento \"%s\" para o "
 "valor \"%s\""
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
 msgstr ""
-"não foi possível definir a propriedade \"%s\" no elemento \"%s\" para o "
-"valor \"%s\""
+"não foi possível definir a propriedade \"%s\" no filho do elemento \"%s\" "
+"para o valor \"%s\""
 
 msgid "Delayed linking failed."
 msgstr "Falha no vínculo postergado."
@@ -1089,6 +1093,10 @@ msgstr "O fluxo não contém dados."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sInterfaces implementadas%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sInterfaces implementadas%s:\n"
+
 msgid "readable"
 msgstr "legível"
 
@@ -1104,6 +1112,9 @@ msgstr "controlável"
 msgid "conditionally available"
 msgstr "condicionalmente disponível"
 
+msgid "can be set only at object construction time"
+msgstr "pode ser definido apenas em tempo de construção do objeto"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "estado alterável para NULO, PRONTO, PAUSADO ou REPRODUZINDO"
 
@@ -1342,16 +1353,16 @@ msgid "Use Windows high-resolution clock, precision: %u ms\n"
 msgstr "Usar o relógio de alta precisão do Windows: precisão de %u ms\n"
 
 msgid "Output tags (also known as metadata)"
-msgstr "Exibir etiquetas (metadados)"
+msgstr "Exibe etiquetas (metadados)"
 
 msgid "Output TOC (chapters and editions)"
-msgstr "Exibir TOC (capítulos e edições)"
+msgstr "Exibe TOC (capítulos e edições)"
 
 msgid "Output status information and property notifications"
-msgstr "Exibir informações de estado e notificações de propriedade"
+msgstr "Exibe informações de status e notificações de propriedade"
 
 msgid "Do not print any progress information"
-msgstr "Não imprimir nenhuma informação de progresso"
+msgstr "Não imprime nenhuma informação de progresso"
 
 msgid "Output messages"
 msgstr "Exibir mensagens"
@@ -1360,29 +1371,35 @@ msgid ""
 "Do not output status information for the specified property if verbose "
 "output is enabled (can be used multiple times)"
 msgstr ""
-"Não exibir informações de status para a propriedade especificada se o modo "
+"Não exibe informações de status para a propriedade especificada se o modo "
 "detalhado de saída estiver ativado (pode ser usado várias vezes)"
 
 msgid "PROPERTY-NAME"
 msgstr "NOME-PROPRIEDADE"
 
+msgid "Set the name of the program"
+msgstr "Definir "
+
+msgid "PROGRAM-NAME"
+msgstr "NOME-PROGRAMA"
+
 msgid "Do not install a fault handler"
-msgstr "Não instale um manipulador de falhas"
+msgstr "Não instal um manipulador de falhas"
 
 msgid "Force EOS on sources before shutting the pipeline down"
 msgstr ""
-"Forçar finalização do fluxo nos elementos fonte antes de desligar a fila de "
+"Força finalização do fluxo nos elementos fonte antes de desligar a fila de "
 "processamento"
 
 msgid "Gather and print index statistics"
-msgstr "Reunir e imprimir a tabela de estatísticas"
+msgstr "Reúne e imprime a tabela de estatísticas"
 
 msgid ""
 "Do not print current position of pipeline. If this option is unspecified, "
 "the position will be printed when stdout is a TTY. To enable printing "
 "position when stdout is not a TTY, use \"force-position\" option"
 msgstr ""
-"Não exibir a posição atual da fila de processamento. Se essa opção não for "
+"Não exibe a posição atual da fila de processamento. Se essa opção não for "
 "especificada, a posição será exibida quando a saída for um TTY. Para "
 "habilitar a exibição da posição quando a saída não for um TTY, utilize a "
 "opção \"force-position\""
@@ -1431,6 +1448,9 @@ msgstr "Definindo a fila de processamento para NULO...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Liberando a fila de processamento...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Habilitar diagnóstico detalhado do carregamento do plug-in"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "ERRO: A fila do processamento não quer pausar.\n"
 
@@ -1460,7 +1480,7 @@ msgstr "Liberando a fila de processamento...\n"
 #~ msgstr "Erro interno no fluxo de dados."
 
 #~ msgid "Do not output status information of TYPE"
-#~ msgstr "Não é possível obter informações do estado de saída do TIPO"
+#~ msgstr "Não é possível obter informações do status de saída do TIPO"
 
 #~ msgid "TYPE1,TYPE2,..."
 #~ msgstr "TIPO1,TIPO2,..."
diff --git a/po/ro.po b/po/ro.po
index c2cdccd..6be1744 100644
--- a/po/ro.po
+++ b/po/ro.po
@@ -1,9 +1,10 @@
-# Romanian translation for gstreamer
+# Romanian translation for gstreamer.
+# Mesajele în limba română pentru pachetul gstreamer.
 # This file is distributed under the same license as the gstreamer package.
 #
 # Lucian Adrian Grijincu <lucian.grijincu@gmail.com>, 2010.
 # Florentina Mușat <florentina.musat.28@gmail.com>, 2020.
-# Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>. 2022 - 2023.
+# Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>. 2022 - 2024.
 #
 # Cronologia traducerii fișierului „gstreamer”:
 # Traducerea inițială, făcută de LAG, pentru versiunea gstreamer 0.10.29.2
@@ -12,14 +13,15 @@
 # Eliminare a mesajelor ce-au dispărut în ultima versiune.
 # Actualizare a traducerii pentru versiunea 1.19.2, făcută de R-GC, ian-2022.
 # Actualizare a traducerii pentru versiunea 1.21.90, făcută de R-GC, ian-2023.
+# Actualizare a traducerii pentru versiunea 1.24.0, făcută de R-GC, mar-2024.
 # Actualizare a traducerii pentru versiunea Y, făcută de X, Z(anul).
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.21.90\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
-"PO-Revision-Date: 2023-01-15 19:23+0100\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-03-08 14:24+0100\n"
 "Last-Translator: Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>\n"
 "Language-Team: Romanian <translation-team-ro@lists.sourceforge.net>\n"
 "Language: ro\n"
@@ -82,21 +84,17 @@ msgid ""
 "Changes coloring mode of the debug log. Possible modes: off, on, disable, "
 "auto, unix"
 msgstr ""
-"Modifică modul de colorare al jurnalului de depanare. Moduri posibile: "
-"oprit, pornit, dezactivat, auto, unix"
+"Modifică modul de colorare al jurnalului de depanare. Moduri posibile: „off” "
+"oprit, „on” pornit, „disable” dezactivat, auto, unix"
 
 msgid "Disable debugging"
 msgstr "Dezactivează depanarea"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr ""
-"Activează diagnosticele detaliate pentru încărcarea modulelor de extensie"
-
 msgid "Colon-separated paths containing plugins"
-msgstr "Căile către modulele de extensie, separate prin două puncte (:)"
+msgstr "Rutele către modulele de extensie, separate prin două puncte (:)"
 
 msgid "PATHS"
-msgstr "CĂI"
+msgstr "RUTE"
 
 msgid ""
 "Comma-separated list of plugins to preload in addition to the list stored in "
@@ -123,7 +121,7 @@ msgid "GStreamer Options"
 msgstr "Opțiuni GStreamer"
 
 msgid "Show GStreamer Options"
-msgstr "Arată opțiunile GStreamer"
+msgstr "Afișează opțiunile GStreamer"
 
 #, c-format
 msgid "Unknown option"
@@ -152,7 +150,7 @@ msgstr ""
 "posteze un mesaj de eroare adecvat cu motivul eșecului."
 
 msgid "Internal GStreamer error: pad problem."
-msgstr "Eroare internă GStreamer: problemă de contact la pini(pad)."
+msgstr "Eroare internă GStreamer: problemă de contact la pini."
 
 msgid "Internal GStreamer error: thread problem."
 msgstr "Eroare internă GStreamer: problemă cu firele de execuție."
@@ -249,7 +247,7 @@ msgstr "GStreamer a întâlnit o eroare generală de flux."
 msgid "Element doesn't implement handling of this stream. Please file a bug."
 msgstr ""
 "Elementul nu implementează gestionarea acestui flux. Trimiteți o sesizare de "
-"defecțiune."
+"eroare."
 
 msgid "Could not determine type of stream."
 msgstr "Nu se poate determina tipul fluxului."
@@ -261,10 +259,10 @@ msgid "There is no codec present that can handle the stream's type."
 msgstr "Nu există niciun codec care să poată gestiona acest tip de flux."
 
 msgid "Could not decode stream."
-msgstr "Nu se poate decoda fluxul."
+msgstr "Nu se poate decodifica fluxul."
 
 msgid "Could not encode stream."
-msgstr "Nu se poate coda fluxul."
+msgstr "Nu se poate codifica fluxul."
 
 msgid "Could not demultiplex stream."
 msgstr "Nu se poate demultiplexa fluxul."
@@ -276,7 +274,7 @@ msgid "The stream is in the wrong format."
 msgstr "Fluxul este într-un format greșit."
 
 msgid "The stream is encrypted and decryption is not supported."
-msgstr "Fluxul este criptat și decriptarea nu este suportată."
+msgstr "Fluxul este criptat și decriptarea nu este acceptată."
 
 msgid ""
 "The stream is encrypted and can't be decrypted because no suitable key has "
@@ -434,15 +432,15 @@ msgid ""
 "Origin of media as a URI (location, where the original of the file or stream "
 "is hosted)"
 msgstr ""
-"Originea fișierului media ca un URI (locație unde este stocată versiunea "
-"originală a fișierului sau fluxului)"
+"Originea fișierului media ca o adresă URI (locație unde este stocată "
+"versiunea originală a fișierului sau fluxului)"
 
 msgid "homepage"
-msgstr "pagina de pornire"
+msgstr "pagina principală"
 
 msgid "Homepage for this media (i.e. artist or movie homepage)"
 msgstr ""
-"Pagina de pornire pentru acest fișier media (adică pagina de pornire a "
+"Pagina de principală a acestui fișier(e) media (adică pagina de pornire a "
 "artistului sau a filmului)"
 
 msgid "description"
@@ -481,10 +479,10 @@ msgid "URI to the copyright notice of the data"
 msgstr "URI către notița asupra drepturilor de autor pentru aceste date (URI)"
 
 msgid "encoded by"
-msgstr "codat de"
+msgstr "codificat de"
 
 msgid "name of the encoding person or organization"
-msgstr "numele persoanei sau organizației care codează"
+msgstr "numele persoanei sau organizației care codifică"
 
 msgid "contact"
 msgstr "contact"
@@ -589,13 +587,13 @@ msgid "encoder"
 msgstr "codificator"
 
 msgid "encoder used to encode this stream"
-msgstr "codificatorul folosit pentru a coda acest flux"
+msgstr "codificatorul folosit pentru a codifica acest flux"
 
 msgid "encoder version"
 msgstr "versiunea codificatorului"
 
 msgid "version of the encoder used to encode this stream"
-msgstr "versiunea codificatorului folosit pentru a coda acest flux"
+msgstr "versiunea codificatorului folosit pentru a codifica acest flux"
 
 msgid "serial"
 msgstr "serial"
@@ -836,7 +834,7 @@ msgid "The episode number in the season the media is part of"
 msgstr "Numărul episodului din care acest fișier media face parte"
 
 msgid "season number"
-msgstr "numărul sezon"
+msgstr "număr sezon"
 
 msgid "The season number of the show the media is part of"
 msgstr "Numărul sezonului din care acest fișier media face parte"
@@ -929,21 +927,27 @@ msgstr "date-private"
 msgid "Private data"
 msgstr "Date private"
 
+msgid "container-specific-track-id"
+msgstr "id-pistă-specific-containerului"
+
+msgid "Container-specific Track ID"
+msgstr "ID-PISTÄ‚-specific-containerului"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
 
 #, c-format
 msgid "Invalid URI: %s"
-msgstr "URI-ul: %s nu este valid"
+msgstr "adresa URI: %s nu este validă"
 
 #, c-format
 msgid "No URI handler for the %s protocol found"
-msgstr "Nu există niciun manipulant de URI pentru protocolul %s găsit"
+msgstr "Nu există niciun gestionar de adresă URI pentru protocolul %s găsit"
 
 #, c-format
 msgid "URI scheme '%s' not supported"
-msgstr "Schema URL „%s” nu este suportată"
+msgstr "Schema URL „%s” nu este acceptată"
 
 #, c-format
 msgid "ERROR: from element %s: %s\n"
@@ -1080,20 +1084,20 @@ msgid "Failed to map buffer."
 msgstr "Nu s-a putut cartografia memoria tampon."
 
 msgid "Filter caps"
-msgstr "Filtrare majuscule"
+msgstr "Filtrare capacități"
 
 msgid ""
 "Restrict the possible allowed capabilities (NULL means ANY). Setting this "
 "property takes a reference to the supplied GstCaps object."
 msgstr ""
-"Restricționează caracteristicele permise (NULL înseamnă ORICE). Definirea "
+"Restricționează caapacitățile permise (NULL înseamnă ORICE). Definirea "
 "acestei proprietăți preia o referință către obiectul GstCaps furnizat."
 
 msgid "Caps Change Mode"
-msgstr "Modul de modificare a majusculelor"
+msgstr "Modul de modificare a capacităților"
 
 msgid "Filter caps change behaviour"
-msgstr "Majusculele de filtru schimbă comportamentul"
+msgstr "Filtrul de capacități schimbă comportamentul"
 
 msgid "No Temp directory specified."
 msgstr "Niciun director temporar specificat."
@@ -1150,20 +1154,20 @@ msgid "eos-after and error-after can't both be defined."
 msgstr "eos-after și error-after nu pot fi amândouă definite."
 
 msgid "caps"
-msgstr "majuscule"
+msgstr "capacități"
 
 msgid "detected capabilities in stream"
-msgstr "caracteristici detectate în flux"
+msgstr "capacități detectate în flux"
 
 msgid "minimum"
 msgstr "minim"
 
 msgid "force caps"
-msgstr "forțează folosirea majusculelor"
+msgstr "forțează folosirea capacităților"
 
 msgid "force caps without doing a typefind"
 msgstr ""
-"forțează folosirea majusculelor fără a efectua un tip de găsire(typefind)"
+"forțează folosirea capacităților fără a efectua un tip de găsire(typefind)"
 
 msgid "Stream doesn't contain enough data."
 msgstr "Fluxul nu conține destule date."
@@ -1175,6 +1179,10 @@ msgstr "Fluxul nu conține date."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sInterfețe implementate%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sInterfețe implementate%s:\n"
+
 msgid "readable"
 msgstr "se poate citi"
 
@@ -1190,14 +1198,19 @@ msgstr "se poate controla"
 msgid "conditionally available"
 msgstr "condiționare disponibilă"
 
+msgid "can be set only at object construction time"
+msgstr "poate fi stabilit numai în momentul construirii obiectului"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
-msgstr "modificabil în stările NULL, GATA, PAUZAT sau REDARE"
+msgstr ""
+"modificabil în stările NULL, „READY” GATA, „PAUSED” PAUZAT sau „PLAYING” "
+"REDARE"
 
 msgid "changeable only in NULL, READY or PAUSED state"
-msgstr "modificabil doar în stările NULL, GATA sau PAUZAT"
+msgstr "modificabil doar în stările NULL, „READY” GATA sau „PAUSED” PAUZAT"
 
 msgid "changeable only in NULL or READY state"
-msgstr "modificabil doar în stările NULL sau GATA"
+msgstr "modificabil doar în stările NULL sau „READY” GATA"
 
 msgid "Blacklisted files:"
 msgstr "Fișierele de pe lista neagră:"
@@ -1273,7 +1286,7 @@ msgstr ""
 
 msgid "Print supported URI schemes, with the elements that implement them"
 msgstr ""
-"Imprimă schemele URI suportate, cu elementele pe care acestea le "
+"Imprimă schemele URI acceptate, cu elementele pe care acestea le "
 "implementează"
 
 msgid ""
@@ -1455,8 +1468,14 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "NUME-PROPRIETATE"
 
+msgid "Set the name of the program"
+msgstr "Stabilește numele programului"
+
+msgid "PROGRAM-NAME"
+msgstr "NUME-PROGRAM"
+
 msgid "Do not install a fault handler"
-msgstr "Nu instala un gestionar de erori"
+msgstr "Nu instalează un gestionar de erori"
 
 msgid "Force EOS on sources before shutting the pipeline down"
 msgstr "Forțează EOS pe surse înainte de a închide linia de asamblare"
@@ -1516,3 +1535,7 @@ msgstr "Se stabilește linia de asamblare la NULL ...\n"
 
 msgid "Freeing pipeline ...\n"
 msgstr "Se eliberează linia de asamblare...\n"
+
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr ""
+#~ "Activează diagnosticele detaliate pentru încărcarea modulelor de extensie"
diff --git a/po/ru.po b/po/ru.po
index 4d9c20c..cbd1bfb 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -9,7 +9,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.21.90\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2023-01-15 12:54+0300\n"
 "Last-Translator: Yuri Kozlov <yuray@komyakino.ru>\n"
 "Language-Team: Russian <gnu@d07.ru>\n"
@@ -63,9 +63,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Отключить отладку"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Выводить дополнительную информацию при загрузке модулей"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Список путей поиска модулей, разделённых двоеточиями"
 
@@ -833,6 +830,12 @@ msgstr "private-data"
 msgid "Private data"
 msgstr "Частная информация"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1068,6 +1071,10 @@ msgstr "Поток не содержит данных."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sРеализованные интерфейсы%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sРеализованные интерфейсы%s:\n"
+
 msgid "readable"
 msgstr "считываемый"
 
@@ -1083,6 +1090,9 @@ msgstr "контролируемый"
 msgid "conditionally available"
 msgstr "условно доступно"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "может быть равно состоянию NULL, READY, PAUSED или PLAYING"
 
@@ -1341,6 +1351,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "ИМЯ-СВОЙСТВА"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "ИМЯ-СВОЙСТВА"
+
 msgid "Do not install a fault handler"
 msgstr "Не устанавливать обработчик ошибок"
 
@@ -1401,6 +1418,9 @@ msgstr "Установка конвейера в состояние NULL…\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Освобождение конвейера…\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Выводить дополнительную информацию при загрузке модулей"
+
 #~ msgid "Error creating pipe: %s\n"
 #~ msgstr "Ошибка создания канала: %s\n"
 
diff --git a/po/rw.po b/po/rw.po
index 8d5f979..26dacf8 100644
--- a/po/rw.po
+++ b/po/rw.po
@@ -15,7 +15,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 0.8.8\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2005-04-04 10:55-0700\n"
 "Last-Translator: Steven Michael Murphy <murf@e-tools.com>\n"
 "Language-Team: Kinyarwanda <translation-team-rw@lists.sourceforge.net>\n"
@@ -98,10 +98,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr ""
 
-#, fuzzy
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Itangira..."
-
 msgid "Colon-separated paths containing plugins"
 msgstr ""
 
@@ -997,6 +993,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1242,6 +1244,10 @@ msgstr "iyi Ibyatanzwe"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr ""
 
@@ -1258,6 +1264,9 @@ msgstr ""
 msgid "conditionally available"
 msgstr ""
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1505,6 +1514,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 #, fuzzy
 msgid "Do not install a fault handler"
 msgstr "OYA Kwinjiza porogaramu a"
@@ -1563,6 +1578,10 @@ msgstr ""
 msgid "Freeing pipeline ...\n"
 msgstr ""
 
+#, fuzzy
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Itangira..."
+
 #, fuzzy
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "Kuri Gukina"
diff --git a/po/sk.po b/po/sk.po
index b9f06b8..62cf283 100644
--- a/po/sk.po
+++ b/po/sk.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.7.90\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2016-05-20 11:32+0100\n"
 "Last-Translator: Peter Tuhársky <tuharsky@misbb.sk>\n"
 "Language-Team: Slovak <sk-i18n@lists.linux.sk>\n"
@@ -63,9 +63,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Zakázať ladenie"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Povoliť podrobnú diagnostiku načítavania zásuvných modulov"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Dvojbodkou oddelené cesty, ktoré obsahujú zásuvné moduly"
 
@@ -831,6 +828,12 @@ msgstr "súkromné-dáta"
 msgid "Private data"
 msgstr "Súkromné dáta"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1063,6 +1066,10 @@ msgstr "Prúd neobsahuje údaje."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Implementované rozhrania:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "čitateľné"
 
@@ -1079,6 +1086,9 @@ msgstr "ovládateľné"
 msgid "conditionally available"
 msgstr "ovládateľné"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "meniteľné v stave NULOVÝ, PRIPRAVENÝ, POZASTAVENÝ alebo HRAJÚCI"
 
@@ -1337,6 +1347,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "Meno vlastníctva"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "Meno vlastníctva"
+
 msgid "Do not install a fault handler"
 msgstr "Neinštalovať obsluhu výnimiek"
 
@@ -1393,6 +1410,9 @@ msgstr "Nastavujem rúru na NULOVÚ ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Uvoľňujem rúru ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Povoliť podrobnú diagnostiku načítavania zásuvných modulov"
+
 #~ msgid "bin"
 #~ msgstr "zásobník"
 
diff --git a/po/sl.po b/po/sl.po
index 63a46d5..e1ef0bb 100644
--- a/po/sl.po
+++ b/po/sl.po
@@ -3,16 +3,16 @@
 # Copyright (C) 2005 - 2014 Free Software Foundation, Inc.
 #
 # Matej Urbančič <matej.urban@gmail.com>, 2010 - 2011.
-# Martin Srebotnjak <miles@filmsi.net>, 2011.
 # Klemen Košir <klemen913@gmail.com>, 2011 - 2014.
+# Martin Srebotnjak <miles@filmsi.net>, 2011, 2024.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer-1.2.1\n"
+"Project-Id-Version: gstreamer-1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
-"PO-Revision-Date: 2014-04-09 22:38+0100\n"
-"Last-Translator: Klemen Košir <klemen913@gmail.com>\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-08-05 15:36+0200\n"
+"Last-Translator: Martin Srebotnjak <miles@filmsi.net>\n"
 "Language-Team: Slovenian <translation-team-sl@lists.sourceforge.net>\n"
 "Language: sl\n"
 "MIME-Version: 1.0\n"
@@ -21,7 +21,7 @@ msgstr ""
 "X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
 "n%100==4 ? 3 : 0);\n"
-"X-Generator: Poedit 1.6.4\n"
+"X-Generator: Poedit 2.2.1\n"
 
 msgid "Print the GStreamer version"
 msgstr "Izpiše različico programa GStreamer"
@@ -64,9 +64,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Onemogoči razhroščevanje"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Omogoči podrobno diagnostiko nalaganja vstavkov"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Z vejico ločen seznam poti do vstavkov"
 
@@ -205,9 +202,8 @@ msgstr "Nastavitev vira ni mogoče pridobiti ali določiti."
 msgid "No space left on the resource."
 msgstr "Na viru ni prostora."
 
-#, fuzzy
 msgid "Not authorized to access resource."
-msgstr "Na viru ni prostora."
+msgstr "Ni pooblatila za dostop do virov."
 
 msgid "GStreamer encountered a general stream error."
 msgstr "V programu GStreamer je prišlo do splošne napake pretakanja."
@@ -458,10 +454,10 @@ msgid "person(s) who composed the recording"
 msgstr "oseba, ki je skladatelj posnetka"
 
 msgid "conductor"
-msgstr ""
+msgstr "dirigent"
 
 msgid "conductor/performer refinement"
-msgstr ""
+msgstr "izboljšava dirigenta/izvajalca"
 
 msgid "duration"
 msgstr "trajanje"
@@ -819,16 +815,22 @@ msgid "Information about the people behind a remix and similar interpretations"
 msgstr "Podatki o avtorjih predelav in drugih različic"
 
 msgid "midi-base-note"
-msgstr ""
+msgstr "midi-osnova-nota"
 
 msgid "Midi note number of the audio track."
-msgstr ""
+msgstr "Številka note midi zvočnega posnetka."
 
 msgid "private-data"
-msgstr ""
+msgstr "zasebni-podatki"
 
 msgid "Private data"
-msgstr ""
+msgstr "Zasebni podatki"
+
+msgid "container-specific-track-id"
+msgstr "ID-steze-specifične-za-vsebnik"
+
+msgid "Container-specific Track ID"
+msgstr "ID steze, specifičen za vsebnik"
 
 #. separator between two strings
 msgid ", "
@@ -836,7 +838,7 @@ msgstr ", "
 
 #, c-format
 msgid "Invalid URI: %s"
-msgstr ""
+msgstr "Neveljaven naslov URI: %s"
 
 #, c-format
 msgid "No URI handler for the %s protocol found"
@@ -863,27 +865,26 @@ msgstr ""
 #. ******************************************************************************************
 #, c-format
 msgid "link has no source [sink=%s@%p]"
-msgstr ""
+msgstr "povezava nima vira [ponor=%s@%p]"
 
 #, c-format
 msgid "link has no sink [source=%s@%p]"
-msgstr ""
+msgstr "povezava nima ponora [vir=%s@%p]"
 
 msgid "No such property."
-msgstr ""
+msgstr "Takšne lastnosti ni."
 
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
 msgstr "lastnost \"%s\" v predmetu \"%s\" ne obstaja"
 
-#, fuzzy, c-format
+#, c-format
 msgid "Element \"%s\" is not a GstPreset"
-msgstr "Datoteka \"%s\" je vtič."
+msgstr "Element »%s« ni GstPreset"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not set preset \"%s\" in element \"%s\""
-msgstr ""
-"lastnosti \"%s\" v predmetu \"%s\" ni mogoče nastaviti na vrednost \"%s\""
+msgstr "ni možno nastaviti »%s« v predmetu »%s«"
 
 #, c-format
 msgid "no element \"%s\""
@@ -894,25 +895,27 @@ msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
 msgstr ""
 "lastnosti \"%s\" v predmetu \"%s\" ni mogoče nastaviti na vrednost \"%s\""
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
 msgstr ""
-"lastnosti \"%s\" v predmetu \"%s\" ni mogoče nastaviti na vrednost \"%s\""
+"lastnosti »%s« v podrejenem predmetu »%s« ni mogoče nastaviti na vrednost "
+"»%s«"
 
 msgid "Delayed linking failed."
-msgstr ""
+msgstr "Zapoznelo povezovanje ni uspelo."
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not link %s to %s, %s can't handle caps %s"
-msgstr "%s in %s ni mogoče povezati"
+msgstr "%s ne morem povezati s %s, %s ne more ravnati z velikimi črkami %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not link %s to %s, neither element can handle caps %s"
-msgstr "predmeta korita za naslov URI \"%s\" ni mogoče povezati"
+msgstr ""
+"%s ni mogel povezati z %s, noben element ne more obravnavati velikih črk %s"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not link %s to %s with caps %s"
-msgstr "%s in %s ni mogoče povezati"
+msgstr "%s ni mogoče povezati z %s z velikimi črkami %s"
 
 #, c-format
 msgid "could not link %s to %s"
@@ -920,11 +923,11 @@ msgstr "%s in %s ni mogoče povezati"
 
 #, c-format
 msgid "unexpected reference \"%s\" - ignoring"
-msgstr ""
+msgstr "nepričakovani sklic »%s« - prezrt bo"
 
 #, c-format
 msgid "unexpected pad-reference \"%s\" - ignoring"
-msgstr ""
+msgstr "nepričakovan sklic pad »%s« - prezrt bo"
 
 #, c-format
 msgid "could not parse caps \"%s\""
@@ -939,21 +942,21 @@ msgid "no source element for URI \"%s\""
 msgstr "izvorni predmet za naslov URI \"%s\" ne obstaja"
 
 msgid "syntax error"
-msgstr ""
+msgstr "skladenjska napaka"
 
 #, c-format
 msgid "specified empty bin \"%s\", not allowed"
 msgstr "določena je prazna dvojiška datoteka \"%s\", kar ni dovoljeno"
 
-#, fuzzy, c-format
+#, c-format
 msgid "no bin \"%s\", unpacking elements"
-msgstr "dvojiška datoteka \"%s\" ne obstaja, zato bo dejanje izpuščeno"
+msgstr "dvojiška datoteka »%s« ne obstaja, sledi razpakiranje elementov"
 
 msgid "empty pipeline not allowed"
 msgstr "cevovod brez vsebine ni dovoljen"
 
 msgid "Pipeline construction is invalid, please add queues."
-msgstr ""
+msgstr "Gradnja cevovoda je neveljavna, dodajte čakalne vrste."
 
 msgid "A lot of buffers are being dropped."
 msgstr "Veliko medpomnilnikov se prazni."
@@ -981,10 +984,10 @@ msgstr ""
 "priloženi predmet GstCaps."
 
 msgid "Caps Change Mode"
-msgstr ""
+msgstr "Način spreminjanja velikih črk"
 
 msgid "Filter caps change behaviour"
-msgstr ""
+msgstr "Sprememba vedenja velikih črk v filtrih"
 
 msgid "No Temp directory specified."
 msgstr "Začasna mapa ni določena."
@@ -1038,7 +1041,7 @@ msgid "Failed after iterations as requested."
 msgstr "Po več ponovitvah je bilo (po zahtevi) opravilo neuspešno prekinjeno."
 
 msgid "eos-after and error-after can't both be defined."
-msgstr ""
+msgstr "eos-after in error-after ni mogoče določiti."
 
 msgid "caps"
 msgstr "velike črke"
@@ -1055,16 +1058,19 @@ msgstr "vsili velike črke"
 msgid "force caps without doing a typefind"
 msgstr "vsili velike črke brez potrjevanja pisave"
 
-#, fuzzy
 msgid "Stream doesn't contain enough data."
-msgstr "Pretok ne vsebuje podatkov."
+msgstr "Tok ne vsebuje dovolj podatkov."
 
 msgid "Stream contains no data."
 msgstr "Pretok ne vsebuje podatkov."
 
-#, fuzzy, c-format
+#, c-format
 msgid "%sImplemented Interfaces%s:\n"
-msgstr "Vgrajeni vmesniki:\n"
+msgstr "%sVgrajeni vmesniki%s:\n"
+
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sVgrajeni vmesniki%s:\n"
 
 msgid "readable"
 msgstr "berljivo"
@@ -1073,14 +1079,16 @@ msgid "writable"
 msgstr "zapisljivo"
 
 msgid "deprecated"
-msgstr ""
+msgstr "zastarelo"
 
 msgid "controllable"
 msgstr "nadzorljivo"
 
-#, fuzzy
 msgid "conditionally available"
-msgstr "nadzorljivo"
+msgstr "pogojno na voljo"
+
+msgid "can be set only at object construction time"
+msgstr "lahko se nastavi samo v času gradnje objekta"
 
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "spremenljivo le v stanjih NULL, READY, PAUSED in PLAYING"
@@ -1094,9 +1102,9 @@ msgstr "spremenljivo le v stanjih NULL in READY"
 msgid "Blacklisted files:"
 msgstr "Datoteke na črnem seznamu:"
 
-#, fuzzy, c-format
+#, c-format
 msgid "%sTotal count%s: %s"
-msgstr "Skupno: "
+msgstr "%sSkupno število%s: %s"
 
 #, c-format
 msgid "%d blacklisted file"
@@ -1154,6 +1162,8 @@ msgid ""
 "A slashes ('/') separated list of types of elements (also known as klass) to "
 "list. (unordered)"
 msgstr ""
+"S poševnico (»/») ločen seznam vrst elementov (znanih tudi kot klass), ki "
+"jih je treba našteti (neurejeno)."
 
 msgid "Check if the specified element or plugin exists"
 msgstr "Preveri, če podan predmet ali vstavek že obstaja"
@@ -1172,9 +1182,11 @@ msgid ""
 "Disable colors in output. You can also achieve the same by setting "
 "'GST_INSPECT_NO_COLORS' environment variable to any value."
 msgstr ""
+"Onemogoči barve v izhodu. Enako lahko dosežete tudi tako, da spremenljivko "
+"okolja »GST_INSPECT_NO_COLORS« nastavite na poljubno vrednost."
 
 msgid "Color output, even when not sending to a tty."
-msgstr ""
+msgstr "Barvni izhod, tudi če ni poslano na tty."
 
 #, c-format
 msgid "Could not load plugin file: %s\n"
@@ -1315,7 +1327,7 @@ msgstr "Med čakanjem na EOS je prišlo do napake\n"
 
 #, c-format
 msgid "Use Windows high-resolution clock, precision: %u ms\n"
-msgstr ""
+msgstr "Uporabi uro visoke ločljivosti Windows, natančnost: %u ms\n"
 
 msgid "Output tags (also known as metadata)"
 msgstr "Izhodne oznake (znane tudi kot metapodatki)"
@@ -1336,9 +1348,17 @@ msgid ""
 "Do not output status information for the specified property if verbose "
 "output is enabled (can be used multiple times)"
 msgstr ""
+"Ne izpisuj informacij o stanju za določeno lastnost, če je omogočen podrobni "
+"izhod (lahko se uporabi večkrat)"
 
 msgid "PROPERTY-NAME"
-msgstr ""
+msgstr "IME-LASTNOSTI"
+
+msgid "Set the name of the program"
+msgstr "Nastavite ime programa"
+
+msgid "PROGRAM-NAME"
+msgstr "IME-PROGRAMA"
 
 msgid "Do not install a fault handler"
 msgstr "Na namesti ročnika napak"
@@ -1354,11 +1374,16 @@ msgid ""
 "the position will be printed when stdout is a TTY. To enable printing "
 "position when stdout is not a TTY, use \"force-position\" option"
 msgstr ""
+"Ne tiskaj trenutnega položaja cevovoda. Če ta možnost ni določena, bo "
+"položaj natisnjen, ko je stdout TTY. Če želite omogočiti položaj tiskanja, "
+"ko stdout ni TTY, uporabite možnost »force-position«"
 
 msgid ""
 "Allow printing current position of pipeline even if stdout is not a TTY. "
 "This option has no effect if the \"no-position\" option is specified"
 msgstr ""
+"Dovoli tiskanje trenutnega položaja cevovoda, tudi če stdout ni TTY. Ta "
+"možnost nima učinka, če je določena možnost »no-position«"
 
 #, c-format
 msgid "ERROR: pipeline could not be constructed: %s.\n"
@@ -1377,9 +1402,8 @@ msgstr "NAPAKA: predmeta \"cevovoda\" ni mogoče najti.\n"
 msgid "Setting pipeline to PAUSED ...\n"
 msgstr "Nastavljanje cevovoda na PAUSED ...\n"
 
-#, fuzzy
 msgid "Failed to set pipeline to PAUSED.\n"
-msgstr "Nastavljanje cevovoda na PAUSED ...\n"
+msgstr "Nastavljanje cevovoda na PAUSED je spodletelo.\n"
 
 msgid "Pipeline is live and does not need PREROLL ...\n"
 msgstr "Cevovod je živ in ga ni potrebno pripraviti ...\n"
@@ -1395,31 +1419,3 @@ msgstr "Nastavljanje cevovoda na NULL ...\n"
 
 msgid "Freeing pipeline ...\n"
 msgstr "Sproščanje cevovoda ...\n"
-
-#~ msgid "link without source element"
-#~ msgstr "povezava brez predmeta vira"
-
-#~ msgid "link without sink element"
-#~ msgstr "povezava brez predmeta ponora"
-
-#, c-format
-#~ msgid "no element to link URI \"%s\" to"
-#~ msgstr "ni predmeta za povezovanje naslova \"%s\" na"
-
-#~ msgid "Internal data stream error."
-#~ msgstr "Notranja napaka pretoka podatkov."
-
-#~ msgid "Do not output status information of TYPE"
-#~ msgstr "Ne izpiši podrobnosti stanja VRSTE"
-
-#~ msgid "TYPE1,TYPE2,..."
-#~ msgstr "VRSTA1, VRSTA2 ..."
-
-#~ msgid "ERROR: Pipeline doesn't want to pause.\n"
-#~ msgstr "NAPAKA: cevovoda ni mogoče postaviti v mirovanje.\n"
-
-#~ msgid "EOS on shutdown enabled -- waiting for EOS after Error\n"
-#~ msgstr "EOS ob izklopu je omogočen -- čakanje na EOS, ki sledi napaki\n"
-
-#~ msgid "Setting pipeline to READY ...\n"
-#~ msgstr "Nastavljanje cevovoda na READY ...\n"
diff --git a/po/sq.po b/po/sq.po
index 4bd06e5..7d2c3ed 100644
--- a/po/sq.po
+++ b/po/sq.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.19.2\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2022-03-22 10:52-0400\n"
 "Last-Translator: Agron Selimaj <as9902613@gmail.com>\n"
 "Language-Team: Albanian <translation-team-sq@lists.sourceforge.net>\n"
@@ -62,9 +62,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Ç'aktivo debug"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Aktivo kërkesën e plugin të ngarkimit të diagnostikimeve"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Shtigjet e ndara me pikpresje qe permbajne plugins"
 
@@ -845,6 +842,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1077,6 +1080,10 @@ msgstr "albumi që përmban këtë të dhënë"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr ""
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr ""
 
@@ -1092,6 +1099,9 @@ msgstr ""
 msgid "conditionally available"
 msgstr ""
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr ""
 
@@ -1335,6 +1345,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "Mos instalo një ushqyes të dëmtuar"
 
@@ -1391,6 +1407,9 @@ msgstr ""
 msgid "Freeing pipeline ...\n"
 msgstr "DUKE ZBATUAR pipeline ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Aktivo kërkesën e plugin të ngarkimit të diagnostikimeve"
+
 #~ msgid "Disable accelerated CPU instructions"
 #~ msgstr "Ç'aktivo instruksionet e përshpejtimit të CPU"
 
diff --git a/po/sr.po b/po/sr.po
index 21b466a..2c661c5 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -2,13 +2,13 @@
 # Copyright © 2020 Free Software Foundation, Inc.
 # This file is distributed under the same license as the gstreamer package.
 # Danilo Segan <dsegan@gmx.net>, 2004-2005.
-# Мирослав Николић <miroslavnikolic@rocketmail.com>, 2011–2021.
+# Мирослав Николић <miroslavnikolic@rocketmail.com>, 2011-2024.
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer-1.19.2\n"
+"Project-Id-Version: gstreamer-1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
-"PO-Revision-Date: 2021-10-01 22:08+0200\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-05-07 07:40+0200\n"
 "Last-Translator: Мирослав Николић <miroslavnikolic@rocketmail.com>\n"
 "Language-Team: Serbian <(nothing)>\n"
 "Language: sr\n"
@@ -18,7 +18,6 @@ msgstr ""
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
 "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
 "X-Bugs: Report translation errors to the Language-Team address.\n"
-"X-Project-Style: gnome\n"
 
 msgid "Print the GStreamer version"
 msgstr "Исписује издање Гстримера"
@@ -61,9 +60,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Искључује уклањање грешака"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Укључује опширну дијагностику учитавања прикључка"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Двотачком раздвојене путање које садрже прикључке"
 
@@ -833,6 +829,12 @@ msgstr "приватни подаци"
 msgid "Private data"
 msgstr "Приватни подаци"
 
+msgid "container-specific-track-id"
+msgstr "ид-нумере-контејнеру-специфичан"
+
+msgid "Container-specific Track ID"
+msgstr "ИД нумере контејнеру специфичан"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -873,7 +875,7 @@ msgid "link has no sink [source=%s@%p]"
 msgstr "веза нема усклађивање [source=%s@%p]"
 
 msgid "No such property."
-msgstr ""
+msgstr "Нема таквог својства."
 
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
@@ -895,9 +897,9 @@ msgstr "нема елемента „%s“"
 msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
 msgstr "не могу да поставим особину „%s“ у елементу „%s“ на „%s“"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
-msgstr "не могу да поставим особину „%s“ у елементу „%s“ на „%s“"
+msgstr "не могу да поставим особину „%s“ у породу елемента „%s“ на „%s“"
 
 msgid "Delayed linking failed."
 msgstr "Одложено повезивање није успело."
@@ -1069,6 +1071,10 @@ msgstr "Овај ток не садржи податке."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sПримењени уређаји%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sПримењени уређаји%s:\n"
+
 msgid "readable"
 msgstr "читљив"
 
@@ -1084,6 +1090,9 @@ msgstr "управљив"
 msgid "conditionally available"
 msgstr "условно доступан"
 
+msgid "can be set only at object construction time"
+msgstr "може се поставити само у време конструкције објекта"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "измењив у стање НИШТА, СПРЕМАН, ПАУЗИРАН или ПУШТАМ"
 
@@ -1344,6 +1353,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "СВОЈСТВО-НАЗИВ"
 
+msgid "Set the name of the program"
+msgstr "Поставља назив програма"
+
+msgid "PROGRAM-NAME"
+msgstr "НАЗИВ-ПРОГРАМА"
+
 msgid "Do not install a fault handler"
 msgstr "Неће инсталирати руковаоца грешкама"
 
@@ -1405,6 +1420,9 @@ msgstr "Постављам спојку низа на НИШТА ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Ослобађам спојку низа...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Укључује опширну дијагностику учитавања прикључка"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "ГРЕШКА: Спојка низа не жели да иде на паузу.\n"
 
diff --git a/po/sv.po b/po/sv.po
index 8b0453e..81e4f78 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -1,16 +1,16 @@
 # Swedish messages for gstreamer.
-# Copyright © 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2015, 2016, 2017, 2019, 2022 Free Software Foundation, Inc.
+# Copyright © 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2015, 2016, 2017, 2019, 2022, 2023, 2024 Free Software Foundation, Inc.
 # This file is distributed under the same license as the gstreamer package.
 # Christian Rose <menthos@menthos.com>, 2004, 2005.
 # Daniel Nylander <po@danielnylander.se>, 2007, 2008, 2009, 2010, 2011.
-# Sebastian Rasmussen <sebras@gmail.com>, 2014, 2015, 2016, 2017, 2019, 2022.
+# Sebastian Rasmussen <sebras@gmail.com>, 2014, 2015, 2016, 2017, 2019, 2022, 2023, 2024.
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.19.2\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
-"PO-Revision-Date: 2022-10-27 01:35+0200\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-03-07 18:17+0800\n"
 "Last-Translator: Sebastian Rasmussen <sebras@gmail.com>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
 "Language: sv\n"
@@ -19,7 +19,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Bugs: Report translation errors to the Language-Team address.\n"
-"X-Generator: Poedit 3.1.1\n"
+"X-Generator: Poedit 3.4.2\n"
 
 msgid "Print the GStreamer version"
 msgstr "Skriv ut GStreamer-versionen"
@@ -62,9 +62,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Inaktivera felsökning"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Aktivera utförlig diagnostik vid inläsning av insticksmoduler"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Kolonseparerade sökvägar som innehåller insticksmoduler"
 
@@ -832,6 +829,12 @@ msgstr "privat-data"
 msgid "Private data"
 msgstr "Privat data"
 
+msgid "container-specific-track-id"
+msgstr "container-specific-track-id"
+
+msgid "Container-specific Track ID"
+msgstr "Behållarspecifikt spår-ID"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -872,7 +875,7 @@ msgid "link has no sink [source=%s@%p]"
 msgstr "länk har ingen utgång [källa=%s@%p]"
 
 msgid "No such property."
-msgstr ""
+msgstr "Ingen sådan egenskap."
 
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
@@ -894,9 +897,10 @@ msgstr "inget ”%s”-element"
 msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
 msgstr "kunde inte ställa in egenskapen ”%s” i elementet ”%s” till ”%s”"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
-msgstr "kunde inte ställa in egenskapen ”%s” i elementet ”%s” till ”%s”"
+msgstr ""
+"kunde inte ställa in egenskapen ”%s” i barn till elementet ”%s” till ”%s”"
 
 msgid "Delayed linking failed."
 msgstr "Fördröjd länkning misslyckades."
@@ -1065,6 +1069,10 @@ msgstr "Strömmen innehåller inget data."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sImplementerade gränssnitt%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sImplementerade gränssnitt%s:\n"
+
 msgid "readable"
 msgstr "läsbar"
 
@@ -1080,6 +1088,9 @@ msgstr "kontrollerbar"
 msgid "conditionally available"
 msgstr "villkorligt tillgänglig"
 
+msgid "can be set only at object construction time"
+msgstr "kan bara sättas vid tidpunkten då objektet konstrueras"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "ändringsbart i tillstånden NULL, READY, PAUSED eller PLAYING"
 
@@ -1339,6 +1350,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "EGENSKAPSNAMN"
 
+msgid "Set the name of the program"
+msgstr "Sätt namnet på programmet"
+
+msgid "PROGRAM-NAME"
+msgstr "PROGRAMNAMN"
+
 msgid "Do not install a fault handler"
 msgstr "Installera inte en felhanterare"
 
@@ -1356,14 +1373,14 @@ msgstr ""
 "Skriv inte ut aktuell position för rörledningen. Om denna flagga inte är "
 "angivet, kommer positionen att skrivas ut då standard ut är en TTY. För att "
 "aktivera utskrift av position när standard ut inte är en TTY använd ”force-"
-"position”-flaggan."
+"position”-flaggan"
 
 msgid ""
 "Allow printing current position of pipeline even if stdout is not a TTY. "
 "This option has no effect if the \"no-position\" option is specified"
 msgstr ""
 "Tillåt utskrift av aktuell position av rörledningen även om standard ut inte "
-"är en TTY. Denna flagga har ingen effekt om flaggan ”no-position” är angiven."
+"är en TTY. Denna flagga har ingen effekt om flaggan ”no-position” är angiven"
 
 #, c-format
 msgid "ERROR: pipeline could not be constructed: %s.\n"
@@ -1402,6 +1419,9 @@ msgstr "Ställer in rörledningen till NULL...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Frigör rörledning ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Aktivera utförlig diagnostik vid inläsning av insticksmoduler"
+
 #~ msgid "Error creating pipe: %s\n"
 #~ msgstr "Fel vid stängning av rörledning: %s\n"
 
diff --git a/po/tr.po b/po/tr.po
index f94e210..167381e 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -3,20 +3,21 @@
 # This file is distributed under the same license as the gstreamer package.
 # Baris Cicek <baris@teamforce.name.tr>, 2004, 2015.
 # Mehmet Kececi <mkececi@mehmetkececi.com>, 2017, 2019, 2021.
+# Emin Tufan Çetin <etcetin@gmail.com>, 2023, 2024.
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.19.2\n"
+"Project-Id-Version: gstreamer 1.21.90\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
-"PO-Revision-Date: 2021-10-04 13:42+0300\n"
-"Last-Translator: Mehmet Kececi <mkececi@mehmetkececi.com>\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-02-25 08:00+0300\n"
+"Last-Translator: Emin Tufan Çetin <etcetin@gmail.com>\n"
 "Language-Team: Turkish <gnome-turk@gnome.org>\n"
 "Language: tr\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 3.0\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Poedit 3.2.2\n"
 "X-Bugs: Report translation errors to the Language-Team address.\n"
 "X-Project-Style: gnome\n"
 
@@ -32,17 +33,17 @@ msgstr "Geçerli hata ayıklama sınıflarını yazdır ve çık"
 msgid ""
 "Default debug level from 1 (only error) to 9 (anything) or 0 for no output"
 msgstr ""
-"Öntanımlı hata ayıklama seviyesi 1'den (sadece hatalar) 9'a (her şey) ya da "
+"Öntanımlı hata ayıklama düzeyi 1'den (yalnızca hatalar) 9'a (her şey) ya da "
 "çıktı olmaması için 0"
 
 msgid "LEVEL"
-msgstr "SEVİYE"
+msgstr "DÜZEY"
 
 msgid ""
 "Comma-separated list of category_name:level pairs to set specific levels for "
 "the individual categories. Example: GST_AUTOPLUG:5,GST_ELEMENT_*:3"
 msgstr ""
-"Ayrı sınıfların belirli seviyeleri için sınıf_ismi:seviye çiftlerinin virgül "
+"Ayrı sınıfların belirli düzeyleri için sınıf_adı:düzey çiftlerinin virgül "
 "ile ayrılmış listesi. Örnek: GST_AUTOPLUG:5,GST_ELEMENT_*:3"
 
 msgid "LIST"
@@ -55,15 +56,12 @@ msgid ""
 "Changes coloring mode of the debug log. Possible modes: off, on, disable, "
 "auto, unix"
 msgstr ""
-"Hata ayıklama günlüklerini renklendirme kipini değiştirir. Olası kipler: "
-"kapalı, açık, devredışı, otomatik, unix"
+"Hata ayıklama günlüklerini renklendirme kipini değiştirir. Olası kipler: off "
+"(kapalı), on (açık), disable (devre dışı), auto (kendiliğinden), unix"
 
 msgid "Disable debugging"
 msgstr "Hata ayıklamayı kapat"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Ayrıntılı eklenti yükleme detaylarını etkinleştir"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Eklentileri içeren iki nokta üst üste ile ayrılmış yollar"
 
@@ -213,14 +211,14 @@ msgstr "GStreamer genel bir akış hatası ile karşılaştı."
 
 msgid "Element doesn't implement handling of this stream. Please file a bug."
 msgstr ""
-"Öğe bu akımın işlemesini gerçekleştiremiyor. Lütfen hata bildiriminde "
+"Öge bu akımın işlemesini gerçekleştiremiyor. Lütfen hata bildiriminde "
 "bulunun."
 
 msgid "Could not determine type of stream."
 msgstr "Akım türü belirlenemedi."
 
 msgid "The stream is of a different type than handled by this element."
-msgstr "Akım bu öğe tarafından işlenen türden farklı bir türde."
+msgstr "Akım bu ögece işlenen türden başka bir türde."
 
 msgid "There is no codec present that can handle the stream's type."
 msgstr "Akım türünü işleyebilecek kodek bulunmuyor."
@@ -537,34 +535,34 @@ msgid "serial number of track"
 msgstr "parçanın seri numarası"
 
 msgid "replaygain track gain"
-msgstr "tekrarkazanç parça kazancı"
+msgstr "yeniden kazanç parça kazancı"
 
 msgid "track gain in db"
 msgstr "db olarak parça kazancı"
 
 msgid "replaygain track peak"
-msgstr "tekrarkazanç parça üst sınırı"
+msgstr "yeniden kazanç parça üst sınırı"
 
 msgid "peak of the track"
 msgstr "parçanın üst sınırı"
 
 msgid "replaygain album gain"
-msgstr "tekrarkazanç albüm kazancı"
+msgstr "yeniden kazanç albüm kazancı"
 
 msgid "album gain in db"
 msgstr "db olarak albüm kazancı"
 
 msgid "replaygain album peak"
-msgstr "tekrarkazanç albüm üst sınırı"
+msgstr "yeniden kazanç albüm üst sınırı"
 
 msgid "peak of the album"
 msgstr "albüm üst sınırı"
 
 msgid "replaygain reference level"
-msgstr "yeniden kazanç kaynak seviyesi"
+msgstr "yeniden kazanç kaynak düzeyi"
 
 msgid "reference level of track and album gain values"
-msgstr "şarkı ve albüm kazanç değerlerinin kaynak seviyesi"
+msgstr "şarkı ve albüm kazanç değerlerinin kaynak düzeyi"
 
 msgid "language code"
 msgstr "dil kodu"
@@ -586,10 +584,10 @@ msgstr "bu akış ile ilişkili görüntü"
 
 #. TRANSLATORS: 'preview image' = image that shows a preview of the full image
 msgid "preview image"
-msgstr "görüntüyü önizle"
+msgstr "görüntüyü ön izle"
 
 msgid "preview image related to this stream"
-msgstr "bu akış ile ilişkili görüntüyü önizle"
+msgstr "bu akış ile ilişkili görüntüyü ön izle"
 
 msgid "attachment"
 msgstr "ek"
@@ -648,7 +646,7 @@ msgid ""
 "according to WGS84 (zero is average sea level)"
 msgstr ""
 "WGS84'e göre ortamın kaydedildiği veya metre olarak üretildiği yerin coğrafi "
-"yüksekliği (sıfır ortalama deniz seviyesidir)"
+"yüksekliği (sıfır ortalama deniz düzeyidir)"
 
 msgid "geo location country"
 msgstr "ülke coğrafi konumu"
@@ -754,8 +752,8 @@ msgid ""
 "Groups related media that spans multiple tracks, like the different pieces "
 "of a concerto. It is a higher level than a track, but lower than an album"
 msgstr ""
-"Grup ilgili ortam çoklu şarkılar içerir, bir konçertonun farklı parçaları "
-"gibi. Bu şarkıdan daha üst seviyedir ancak albümden alt seviyedir"
+"Grup ilgili ortam çoklu şarkılar içerir, bir konçertonun başka parçaları "
+"gibi. Bir şarkıdan daha üst düzeydir ancak albümden alt düzeydir"
 
 msgid "user rating"
 msgstr "kullanıcı değerlendirmesi"
@@ -764,8 +762,8 @@ msgid ""
 "Rating attributed by a user. The higher the rank, the more the user likes "
 "this media"
 msgstr ""
-"Kullanıcı tarafından verilmiş puanlama. En yüksek puanlama, bir çok "
-"kullanıcı bu ortamı beğenmiş"
+"Kullanıcıca verilmiş puanlama. En yüksek puanlama, bir çok kullanıcı bu "
+"ortamı beğenmiş"
 
 msgid "device manufacturer"
 msgstr "aygıt üreticisi"
@@ -807,7 +805,8 @@ msgid "interpreted-by"
 msgstr "tarafından-yorumlanmış"
 
 msgid "Information about the people behind a remix and similar interpretations"
-msgstr "Yeniden düzenleme ve benzer yorumların arkasındaki kişi hakkında bilgi"
+msgstr ""
+"Yeniden düzenleme ve benzer yorumların arkasındaki kişiyle ilgili bilgi"
 
 msgid "midi-base-note"
 msgstr "midi-base-note"
@@ -821,6 +820,12 @@ msgstr "özel-veri"
 msgid "Private data"
 msgstr "Özel veri"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -831,7 +836,7 @@ msgstr "Geçersiz URI: %s"
 
 #, c-format
 msgid "No URI handler for the %s protocol found"
-msgstr "%s protokolü için URI işleyicisi bulunamadı"
+msgstr "%s iletişim kuralı için URI işleyicisi bulunamadı"
 
 #, c-format
 msgid "URI scheme '%s' not supported"
@@ -839,7 +844,7 @@ msgstr "URI ÅŸema '%s' desteklenmez"
 
 #, c-format
 msgid "ERROR: from element %s: %s\n"
-msgstr "HATA: %s öğesinden: %s\n"
+msgstr "HATA: %s ögesinden: %s\n"
 
 #, c-format
 msgid ""
@@ -861,31 +866,31 @@ msgid "link has no sink [source=%s@%p]"
 msgstr "bağlantı alış noktası yok [kaynak=%s@%p]"
 
 msgid "No such property."
-msgstr ""
+msgstr "Böyle bir özellik yok."
 
 #, c-format
 msgid "no property \"%s\" in element \"%s\""
-msgstr "\"%s\" öğesinde \"%s\" özelliği yok"
+msgstr "\"%2$s\" ögesinde \"%1$s\" özelliği yok"
 
 #, c-format
 msgid "Element \"%s\" is not a GstPreset"
-msgstr "\"%s\" öğesi bir GstPreset değildir"
+msgstr "\"%s\" ögesi bir GstPreset değildir"
 
 #, c-format
 msgid "could not set preset \"%s\" in element \"%s\""
-msgstr "\"%s\" öğesinde kurulu ayar \"%s\" ayarlanamadı"
+msgstr "\"%2$s\" ögesinde kurulu ayar \"%1$s\" ayarlanamadı"
 
 #, c-format
 msgid "no element \"%s\""
-msgstr "\"%s\" öğesi yok"
+msgstr "\"%s\" ögesi yok"
 
 #, c-format
 msgid "could not set property \"%s\" in element \"%s\" to \"%s\""
-msgstr "\"%s\" öğesindeki \"%s\" özelliğine \"%s\" değeri atanamadı"
+msgstr "\"%2$s\" ögesindeki \"%1$s\" özelliğine \"%3$s\" değeri atanamadı"
 
-#, fuzzy, c-format
+#, c-format
 msgid "could not set property \"%s\" in child of element \"%s\" to \"%s\""
-msgstr "\"%s\" öğesindeki \"%s\" özelliğine \"%s\" değeri atanamadı"
+msgstr "\"%2$s\" alt ögesindeki \"%1$s\" özelliğine \"%3$s\" değeri atanamadı"
 
 msgid "Delayed linking failed."
 msgstr "Gecikmeli bağlama başarısız oldu."
@@ -896,7 +901,7 @@ msgstr "%s i %s e bağlanamadı, %s başlıklar işlenemiyor %s"
 
 #, c-format
 msgid "could not link %s to %s, neither element can handle caps %s"
-msgstr "%s i %s e bağlanamadı, hiçbir başlık öğesi işlenemiyor %s"
+msgstr "%s i %s e bağlanamadı, hiçbir başlık ögesi işlenemiyor %s"
 
 #, c-format
 msgid "could not link %s to %s with caps %s"
@@ -920,11 +925,11 @@ msgstr "\"%s\" kabiliyetleri ayrıştırılamadı"
 
 #, c-format
 msgid "no sink element for URI \"%s\""
-msgstr "\"%s\" URI'si için sink öğesi yok"
+msgstr "\"%s\" URI'si için sink ögesi yok"
 
 #, c-format
 msgid "no source element for URI \"%s\""
-msgstr "\"%s\" URI'si için kaynak öğesi yok"
+msgstr "\"%s\" URI'si için kaynak ögesi yok"
 
 msgid "syntax error"
 msgstr "söz dizim hatası"
@@ -938,7 +943,7 @@ msgid "no bin \"%s\", unpacking elements"
 msgstr "\"%s\" ikilisi yok, öge açılamıyor"
 
 msgid "empty pipeline not allowed"
-msgstr "boş boruhattına izin verilmiyor"
+msgstr "boş boru hattına izin verilmiyor"
 
 msgid "Pipeline construction is invalid, please add queues."
 msgstr "Ardışık düzen yapısı geçersiz, lütfen sıralar ekleyin."
@@ -1053,6 +1058,10 @@ msgstr "Akış hiçbir veri içermiyor."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%serçeklenmiş Arayüzler%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%serçeklenmiş Arayüzler%s:\n"
+
 msgid "readable"
 msgstr "okunabilir"
 
@@ -1068,6 +1077,9 @@ msgstr "yöneltilebilir"
 msgid "conditionally available"
 msgstr "koşullu olarak kullanılabilir"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "BOŞ, HAZIR, DURDURULMUŞ veya YÜRÜTÜLÜYOR durumlarına değiştirilebilir"
 
@@ -1088,28 +1100,24 @@ msgstr "%sToplam sayı%s: %s"
 msgid "%d blacklisted file"
 msgid_plural "%d blacklisted files"
 msgstr[0] "%d kara listeye alınan dosya"
-msgstr[1] "%d kara listeye alınan dosya"
 
 #, c-format
 msgid "%d plugin"
 msgid_plural "%d plugins"
 msgstr[0] "%d eklentisi"
-msgstr[1] "%d eklentisi"
 
 #, c-format
 msgid "%d blacklist entry"
 msgid_plural "%d blacklist entries"
 msgstr[0] "%d kara liste girdisi"
-msgstr[1] "%d kara liste girdisi"
 
 #, c-format
 msgid "%d feature"
 msgid_plural "%d features"
 msgstr[0] "%d özelliği"
-msgstr[1] "%d özelliği"
 
 msgid "Print all elements"
-msgstr "Bütün ögeleri yazdır"
+msgstr "Tüm ögeleri yazdır"
 
 msgid "Print list of blacklisted files"
 msgstr "Kara listeye alınmış dosyaların listesini yazdır"
@@ -1120,10 +1128,10 @@ msgid ""
 "                                       Useful in connection with external "
 "automatic plugin installation mechanisms"
 msgstr ""
-"Belirtilen eklenti ya da sağlanan bütün eklentilerin özelliklerinin makine-"
+"Belirtilen eklenti ya da sağlanan tüm eklentilerin özelliklerinin makine-"
 "çözümlenebilir bir listesini yazdır.\n"
-"                                       Harici otomatik eklenti kurulum "
-"tekniği ile bağlantıda faydalı"
+"                                       Dış kendiliğinden eklenti kurulum "
+"tekniği ile bağlantıda yararlıdır"
 
 msgid "List the plugin contents"
 msgstr "Eklenti içeriklerini listele"
@@ -1132,18 +1140,18 @@ msgid ""
 "A slashes ('/') separated list of types of elements (also known as klass) to "
 "list. (unordered)"
 msgstr ""
-"Bir eğik çizgi ('/') öğelernin türlerini listelemek için (klass olarak da "
+"Bir eğik çizgi ('/') ögelerinin türlerini listelemek için (klass olarak da "
 "bilinen) listelerine ayrılmış. (sıralı değil)"
 
 msgid "Check if the specified element or plugin exists"
-msgstr "Belirtilen öge ya da eklentinin var olup olmadığını kontrol et"
+msgstr "Belirtilen öge ya da eklentinin var olup olmadığını denetle"
 
 msgid ""
 "When checking if an element or plugin exists, also check that its version is "
 "at least the version specified"
 msgstr ""
-"Bir öge ya da eklentinin var olup olmadığını kontrol ettiğinizde ayrıca "
-"onların belirtilen en son versiyonda olup olmadıklarını da kontrol edin"
+"Bir öge ya da eklentinin var olup olmadığı denetlenirken, belirtilen en son "
+"sürümde olup olmadıklarını da denetle"
 
 msgid "Print supported URI schemes, with the elements that implement them"
 msgstr "Desteklenen URI şemalarını onlara uygulanan ögelerle yazdır"
@@ -1173,7 +1181,7 @@ msgid "Setting pipeline to PLAYING ...\n"
 msgstr "Boru hattı PLAYING olarak ayarlanıyor ...\n"
 
 msgid "ERROR: pipeline doesn't want to play.\n"
-msgstr "HATA: boruhattı çalmak istemiyor.\n"
+msgstr "HATA: boru hattı çalmak istemiyor.\n"
 
 #, c-format
 msgid "Got message #%u from element \"%s\" (%s): "
@@ -1200,26 +1208,26 @@ msgstr "EOS alındı - boru hattı durduruluyor...\n"
 
 #, c-format
 msgid "FOUND TAG      : found by element \"%s\".\n"
-msgstr "ETİKET BULUNDU      : \"%s\" öğesi tarafından bulundu.\n"
+msgstr "ETİKET BULUNDU      : \"%s\" ögesince bulundu.\n"
 
 #, c-format
 msgid "FOUND TAG      : found by pad \"%s:%s\".\n"
-msgstr "ETİKET BULUNDU      : \"%s:%s\" dolgusu tarafından bulundu.\n"
+msgstr "ETİKET BULUNDU      : \"%s:%s\" dolgusunca bulundu.\n"
 
 #, c-format
 msgid "FOUND TAG      : found by object \"%s\".\n"
-msgstr "ETİKET BULUNDU      : \"%s\" nesnesi tarafından bulundu.\n"
+msgstr "ETİKET BULUNDU      : \"%s\" nesnesince bulundu.\n"
 
 msgid "FOUND TAG\n"
 msgstr "ETİKET BULUNDU\n"
 
 #, c-format
 msgid "FOUND TOC      : found by element \"%s\".\n"
-msgstr "İÇİNDEKİLER BULUNDU      : \"%s\" ögesi tarafından bulundu.\n"
+msgstr "İÇİNDEKİLER BULUNDU      : \"%s\" ögesince bulundu.\n"
 
 #, c-format
 msgid "FOUND TOC      : found by object \"%s\".\n"
-msgstr "İÇİNDEKİLER BULUNDU      : \"%s\" nesnesi tarafından bulundu.\n"
+msgstr "İÇİNDEKİLER BULUNDU      : \"%s\" nesnesince bulundu.\n"
 
 msgid "FOUND TOC\n"
 msgstr "İÇİNDEKİLER BULUNDU\n"
@@ -1325,6 +1333,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "ÖZELLİK-ADI"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "ÖZELLİK-ADI"
+
 msgid "Do not install a fault handler"
 msgstr "Hatalı işleticiyi kurma"
 
@@ -1353,17 +1368,17 @@ msgstr ""
 
 #, c-format
 msgid "ERROR: pipeline could not be constructed: %s.\n"
-msgstr "HATA: boruhattı oluşturulamadı: %s.\n"
+msgstr "HATA: boru hattı oluşturulamadı: %s.\n"
 
 msgid "ERROR: pipeline could not be constructed.\n"
-msgstr "HATA: boruhattı oluşturulamadı.\n"
+msgstr "HATA: boru hattı oluşturulamadı.\n"
 
 #, c-format
 msgid "WARNING: erroneous pipeline: %s\n"
-msgstr "UYARI: hatalı boruhattı: %s\n"
+msgstr "UYARI: hatalı boru hattı: %s\n"
 
 msgid "ERROR: the 'pipeline' element wasn't found.\n"
-msgstr "HATA: 'pipeline' öğesi bulunamadı.\n"
+msgstr "HATA: 'pipeline' ögesi bulunamadı.\n"
 
 msgid "Setting pipeline to PAUSED ...\n"
 msgstr "DURDURULDU durumu için ardışık düzen ayarlamaları ...\n"
@@ -1386,147 +1401,5 @@ msgstr "Boru hattı NULL olarak ayarlanıyor ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Boru hattı boşaltılıyor ...\n"
 
-#~ msgid "ERROR: Pipeline doesn't want to pause.\n"
-#~ msgstr "HATA: Ardışık düzen durdurmayı istemez.\n"
-
-#~ msgid "EOS on shutdown enabled -- waiting for EOS after Error\n"
-#~ msgstr "Kapanmada EOS etkin -- Hatadan sonra EOS için bekleniyor\n"
-
-#~ msgid "Setting pipeline to READY ...\n"
-#~ msgstr "Boru hattı READY olarak ayarlanıyor ...\n"
-
-#~ msgid "Error creating pipe: %s\n"
-#~ msgstr "Pipe oluşturma hatası: %s\n"
-
-#~ msgid "Error forking: %s\n"
-#~ msgstr "Çatallama hatası: %s\n"
-
-#~ msgid "Error reading from console: %s\n"
-#~ msgstr "Uçbirimden okuma hatası: %s\n"
-
-#~ msgid "Error writing to console: %s\n"
-#~ msgstr "Uçbirime yazma hatası: %s\n"
-
-#~ msgid "bin"
-#~ msgstr "bin"
-
-#~ msgid "Internal data stream error."
-#~ msgstr "İç veri akışı hatası."
-
-#~ msgid "Do not output status information of TYPE"
-#~ msgstr "TÜRÜN durum bilgisini gösterme"
-
-#~ msgid "TYPE1,TYPE2,..."
-#~ msgstr "TÜR1,TÜR2,..."
-
-#~ msgid "Disable accelerated CPU instructions"
-#~ msgstr "Hızlandırılmış CPU işlemlerini kapat"
-
-#~ msgid "path list for loading plugins (separated by '"
-#~ msgstr "eklenti yüklemek için yol listesi (' ile ayırılmış"
-
-#~ msgid "')"
-#~ msgstr "')"
-
-#~ msgid "Scheduler to use ('"
-#~ msgstr "Kullanılacak zamanlandırıcı ('"
-
-#~ msgid "' is the default)"
-#~ msgstr "' ön tanımlı olanı)"
-
-#~ msgid "SCHEDULER"
-#~ msgstr "ZAMANLANDIRICI"
-
-#~ msgid "Registry to use"
-#~ msgstr "Kullanılacak kayıt"
-
-#~ msgid "REGISTRY"
-#~ msgstr "KAYIT"
-
-#~ msgid "Internal GStreamer error: state change failed.  File a bug."
-#~ msgstr ""
-#~ "Dahili GStreamer hatası: durum değiştirilemedi.  Hata bildiriminde "
-#~ "bulunun."
-
-#~ msgid "Internal GStreamer error: scheduler problem.  File a bug."
-#~ msgstr ""
-#~ "Dahili GStreamer hatası: zamanlandırıcı sorunu.  Hata bildiriminde "
-#~ "bulunun."
-
-#~ msgid "original location of file as a URI"
-#~ msgstr "dosyanın URI olarak özgün konumu"
-
-#~ msgid "There is no element present to handle the stream's mime type %s."
-#~ msgstr "Akımın %s mime türünü işleyebilecek hiç bir öğe yok."
-
-#~ msgid "maximum"
-#~ msgstr "azami"
-
-#~ msgid ""
-#~ "could not convert \"%s\" so that it fits property \"%s\" in element \"%s\""
-#~ msgstr ""
-#~ "\"%1$s\", \"%3$s\" öğesindeki \"%2$s\" özelliğinine uyacak şekilde "
-#~ "dönüştürülemedi"
-
-#~ msgid "link without source element"
-#~ msgstr "kaynak öğesi olmayan bağ"
-
-#~ msgid "link without sink element"
-#~ msgstr "'sink' öğesi olmayan bağ"
-
-#~ msgid "no element to link URI \"%s\" to"
-#~ msgstr "\"%s\" URI'sini belirtilene bağlayacak öğe yok:"
-
-#~ msgid "Show plugin details"
-#~ msgstr "Eklenti detaylarını göster"
-
-#~ msgid "Show scheduler details"
-#~ msgstr "Zamanlandırıcı detaylarını göster"
-
-#~ msgid " iterations (sum %"
-#~ msgstr " tekrarlar (toplam %"
-
-#~ msgid " ns, average %"
-#~ msgstr " ns, ortalama %"
-
-#~ msgid " ns, min %"
-#~ msgstr " ns, dak %"
-
-#~ msgid " ns, max %"
-#~ msgstr " ns, en fazla %"
-
-#~ msgid " ns).\n"
-#~ msgstr " ns) \n"
-
-#~ msgid "Usage: gst-xmllaunch <file.xml> [ element.property=value ... ]\n"
-#~ msgstr "Kullanım: gst-xmllaunch <dosya.xml> [ öğe.özellik=değer ... ]\n"
-
-#~ msgid "ERROR: parse of xml file '%s' failed.\n"
-#~ msgstr "HATA: xml dosyası '%s' ayrıştırması başarısız.\n"
-
-#~ msgid "ERROR: no toplevel pipeline element in file '%s'.\n"
-#~ msgstr "HATA: '%s' dosyasında üst seviye öğesi bulunamadı.\n"
-
-#~ msgid "WARNING: only one toplevel element is supported at this time."
-#~ msgstr "UYARI: Şu anda sadece bir tane üst seviye öğesi destekleniyor."
-
-#~ msgid "ERROR: could not parse command line argument %d: %s.\n"
-#~ msgstr "HATA: komut satırı argümanı %d ayrıştırılamadı: %s.\n"
-
-#~ msgid "WARNING: element named '%s' not found.\n"
-#~ msgstr "UYARI: '%s' isimli öğe bulunamadı.\n"
-
-#~ msgid "Save xml representation of pipeline to FILE and exit"
-#~ msgstr "Boruhattının xml belirtimini DOSYA'ya kaydet ve çık"
-
-#~ msgid "FILE"
-#~ msgstr "DOSYA"
-
-#~ msgid "Print alloc trace (if enabled at compile time)"
-#~ msgstr "'alloc' takibini yazdır (derleme sırasında etkinleştirilmişse)"
-
-#~ msgid "Number of times to iterate pipeline"
-#~ msgstr "Boruhattının kaç defa tekrarlanacağı"
-
-#~ msgid "         Trying to run anyway.\n"
-#~ msgstr "         Gene de çalıştırma deneniyor.\n"
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Ayrıntılı eklenti yükleme tanılamalarını etkinleştir"
diff --git a/po/uk.po b/po/uk.po
index a01266c..b6b8b09 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -3,13 +3,13 @@
 # This file is distributed under the same license as the gstreamer package.
 #
 # Maxim V. Dziumanenko <dziumanenko@gmail.com>, 2004-2007.
-# Yuri Chornoivan <yurchor@ukr.net>, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2021, 2023.
+# Yuri Chornoivan <yurchor@ukr.net>, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2021, 2023, 2024.
 msgid ""
 msgstr ""
-"Project-Id-Version: gstreamer 1.21.90\n"
+"Project-Id-Version: gstreamer 1.24.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
-"PO-Revision-Date: 2023-01-15 17:39+0200\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
+"PO-Revision-Date: 2024-07-21 19:42+0300\n"
 "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
 "Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n"
 "Language: uk\n"
@@ -19,7 +19,7 @@ msgstr ""
 "X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
 "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-"X-Generator: Lokalize 20.12.0\n"
+"X-Generator: Lokalize 23.04.3\n"
 
 msgid "Print the GStreamer version"
 msgstr "Показати дані щодо версії GStreamer"
@@ -62,9 +62,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Вимкнути діагностику"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Вимкнути докладну діагностику завантаження модулів"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Список розділених крапкою з комою шляхів, які містять модулі"
 
@@ -830,6 +827,12 @@ msgstr "конфіденційні-дані"
 msgid "Private data"
 msgstr "Конфіденційні дані"
 
+msgid "container-specific-track-id"
+msgstr "специфічний-для-контейнера-ід-доріжки"
+
+msgid "Container-specific Track ID"
+msgstr "Специфічний для контейнера ідентифікатор доріжки"
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1065,6 +1068,10 @@ msgstr "Потік не містить даних."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%sРеалізовані інтерфейси%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%sРеалізовані інтерфейси%s:\n"
+
 msgid "readable"
 msgstr "читання"
 
@@ -1080,6 +1087,9 @@ msgstr "контроль"
 msgid "conditionally available"
 msgstr "умовно доступний"
 
+msgid "can be set only at object construction time"
+msgstr "можна встановлювати лише під час побудови об'єкта"
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "можна змінювати у станах NULL, READY, PAUSED та PLAYING"
 
@@ -1345,6 +1355,12 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "НАЗВА-ВЛАСТИВОСТІ"
 
+msgid "Set the name of the program"
+msgstr "Встановити назву програми"
+
+msgid "PROGRAM-NAME"
+msgstr "НАЗВА-ПРОГРАМИ"
+
 msgid "Do not install a fault handler"
 msgstr "Не встановлювати обробник збоїв"
 
@@ -1405,6 +1421,9 @@ msgstr "Канал переводиться у стан NULL ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Спорожнення каналу...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Вимкнути докладну діагностику завантаження модулів"
+
 #~ msgid "Error creating pipe: %s\n"
 #~ msgstr "Помилка під час створення конвеєра: %s\n"
 
diff --git a/po/vi.po b/po/vi.po
index 654ee1c..67d38d4 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -9,7 +9,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.12.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2017-05-05 06:45+0700\n"
 "Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n"
 "Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
@@ -62,9 +62,6 @@ msgstr ""
 msgid "Disable debugging"
 msgstr "Tắt gỡ lỗi"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "Bật chẩn đoán chi tiết việc nạp phần bổ sung"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "Các đường dẫn định giới bằng dấu hai chấm mà chứa phần bổ sung"
 
@@ -834,6 +831,12 @@ msgstr "dữ-liệu-riêng"
 msgid "Private data"
 msgstr "Dữ liệu riêng"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1071,6 +1074,10 @@ msgstr "Luồng không chứa dữ liệu."
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "Giao diện đã thực hiện:\n"
 
+#, c-format
+msgid "%sElement Flags%s:\n"
+msgstr ""
+
 msgid "readable"
 msgstr "được đọc"
 
@@ -1087,6 +1094,9 @@ msgstr "điều khiển được"
 msgid "conditionally available"
 msgstr "điều khiển được"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "có thể thay đổi được trong trạng thái NULL, READY, PAUSED hay PLAYING"
 
@@ -1338,6 +1348,13 @@ msgstr ""
 msgid "PROPERTY-NAME"
 msgstr "TÊN-THUỘC-TÍNH"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "TÊN-THUỘC-TÍNH"
+
 msgid "Do not install a fault handler"
 msgstr "Không cài đặt bộ quản lý lỗi"
 
@@ -1394,6 +1411,9 @@ msgstr "Đang đặt đường ống thành VÔ_GIÁ_TRỊ …\n"
 msgid "Freeing pipeline ...\n"
 msgstr "Đang giải phóng đường ống …\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "Bật chẩn đoán chi tiết việc nạp phần bổ sung"
+
 #~ msgid "ERROR: Pipeline doesn't want to pause.\n"
 #~ msgstr "LỖI: đường ống không tạm dừng được.\n"
 
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 45db2bb..e8c916b 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.21.90\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-23 16:27+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2023-01-21 13:39+0800\n"
 "Last-Translator: Tianze Wang <zwpwjwtz@126.com>\n"
 "Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
@@ -56,9 +56,6 @@ msgstr "改变调试日志的颜色模式。可能的模式有:off、on、disa
 msgid "Disable debugging"
 msgstr "禁止调试"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "开启详细的插件载入分析"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "冒号分隔的包含插件的路径"
 
@@ -799,6 +796,12 @@ msgstr "私有数据"
 msgid "Private data"
 msgstr "专有用途的数据"
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ", "
@@ -1031,6 +1034,10 @@ msgstr "流中不含数据"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "%s实现的接口%s:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "%s实现的接口%s:\n"
+
 msgid "readable"
 msgstr "可读"
 
@@ -1046,6 +1053,9 @@ msgstr "可控制"
 msgid "conditionally available"
 msgstr "部分情况下可用"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "可以在NULL、READY、PAUSED或PLAYING状态下改变"
 
@@ -1290,6 +1300,13 @@ msgstr "如果启用了详细输出模式,不输出指定属性的状态信息
 msgid "PROPERTY-NAME"
 msgstr "属性名"
 
+msgid "Set the name of the program"
+msgstr ""
+
+#, fuzzy
+msgid "PROGRAM-NAME"
+msgstr "属性名"
+
 msgid "Do not install a fault handler"
 msgstr "不安装错误的处理程序"
 
@@ -1350,6 +1367,9 @@ msgstr "设置 NULL 管道 ...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "释放管道资源 ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "开启详细的插件载入分析"
+
 #~ msgid "Error creating pipe: %s\n"
 #~ msgstr "创建管道时出错:“%s\n"
 
diff --git a/po/zh_TW.po b/po/zh_TW.po
index debae02..142aac6 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -27,7 +27,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gstreamer 1.19.2\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-11 15:40+0000\n"
+"POT-Creation-Date: 2024-11-03 17:36+0000\n"
 "PO-Revision-Date: 2021-09-26 21:45+0800\n"
 "Last-Translator: Wen Liao <wen.cf83@gmail.com>\n"
 "Language-Team: Chinese (traditional) <zh-l10n@lists.linux.org.tw>\n"
@@ -76,9 +76,6 @@ msgstr "更改偵錯日誌配色模式,支援配色模式為:off, on, disabl
 msgid "Disable debugging"
 msgstr "關閉偵錯功能"
 
-msgid "Enable verbose plugin loading diagnostics"
-msgstr "載入外掛時顯示詳細訊息"
-
 msgid "Colon-separated paths containing plugins"
 msgstr "以分號分隔的路徑中有包含外掛程式"
 
@@ -824,6 +821,12 @@ msgstr ""
 msgid "Private data"
 msgstr ""
 
+msgid "container-specific-track-id"
+msgstr ""
+
+msgid "Container-specific Track ID"
+msgstr ""
+
 #. separator between two strings
 msgid ", "
 msgstr ""
@@ -1059,6 +1062,10 @@ msgstr "資料串流中沒有資料"
 msgid "%sImplemented Interfaces%s:\n"
 msgstr "實作介面:\n"
 
+#, fuzzy, c-format
+msgid "%sElement Flags%s:\n"
+msgstr "實作介面:\n"
+
 msgid "readable"
 msgstr "可讀"
 
@@ -1075,6 +1082,9 @@ msgstr "可控制"
 msgid "conditionally available"
 msgstr "可控制"
 
+msgid "can be set only at object construction time"
+msgstr ""
+
 msgid "changeable in NULL, READY, PAUSED or PLAYING state"
 msgstr "可以切換到NULL, READY, PAUSED 或PLAYING狀態"
 
@@ -1320,6 +1330,12 @@ msgstr "當開啟verbose 輸出時請勿印出指定的屬性中的狀態資訊
 msgid "PROPERTY-NAME"
 msgstr ""
 
+msgid "Set the name of the program"
+msgstr ""
+
+msgid "PROGRAM-NAME"
+msgstr ""
+
 msgid "Do not install a fault handler"
 msgstr "請勿安裝錯誤處理程式"
 
@@ -1380,6 +1396,9 @@ msgstr "將pipeline狀態設為NULL...\n"
 msgid "Freeing pipeline ...\n"
 msgstr "釋放pipeline ...\n"
 
+#~ msgid "Enable verbose plugin loading diagnostics"
+#~ msgstr "載入外掛時顯示詳細訊息"
+
 #~ msgid "Internal data stream error."
 #~ msgstr "內部資料串流錯誤"
 
diff --git a/scripts/gen-changelog.py b/scripts/gen-changelog.py
index 3924e6e..44739f1 100755
--- a/scripts/gen-changelog.py
+++ b/scripts/gen-changelog.py
@@ -29,7 +29,6 @@ changelog_starts = {
     'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14',
     'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc',
     'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b',
-    'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330',
     'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2',
     'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b',
 }
diff --git a/scripts/git-version.sh b/scripts/git-version.sh
index d96223a..fe1313b 100755
--- a/scripts/git-version.sh
+++ b/scripts/git-version.sh
@@ -12,7 +12,6 @@ for m in \
   gst-python gstreamer-sharp \
   gnonlin \
   gst-rtsp-server \
-  gst-omx \
   gst-devtools \
   ; do
   if test -d $m; then
diff --git a/tests/check/elements/fakesink.c b/tests/check/elements/fakesink.c
index 352031a..68f4363 100644
--- a/tests/check/elements/fakesink.c
+++ b/tests/check/elements/fakesink.c
@@ -890,6 +890,175 @@ GST_START_TEST (test_position)
 
 GST_END_TEST;
 
+/* test position reporting still works after a FLUSH_STOP(reset_time=FALSE) */
+GST_START_TEST (test_position_non_resetting_flush)
+{
+  GstElement *pipeline, *sink;
+  GstPad *sinkpad;
+  GstStateChangeReturn ret;
+  gboolean qret;
+  gint64 qcur;
+  GstBuffer *buffer;
+  GstFlowReturn fret;
+  ChainData *data;
+  GstEvent *event;
+  gboolean eret;
+
+  /* create sink */
+  pipeline = gst_pipeline_new ("pipeline");
+  fail_if (pipeline == NULL);
+
+  sink = gst_element_factory_make ("fakesink", "sink");
+  fail_if (sink == NULL);
+  g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
+  g_object_set (G_OBJECT (sink), "num-buffers", 2, NULL);
+
+  gst_bin_add (GST_BIN (pipeline), sink);
+
+  sinkpad = gst_element_get_static_pad (sink, "sink");
+  fail_if (sinkpad == NULL);
+
+  /* make pipeline and element ready to accept data */
+  ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  fail_unless (ret == GST_STATE_CHANGE_ASYNC);
+
+  gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
+
+  /* send segment, this should work */
+  {
+    GstSegment segment;
+
+    GST_DEBUG ("sending segment");
+    gst_segment_init (&segment, GST_FORMAT_TIME);
+    segment.start = 1 * GST_SECOND;
+    segment.stop = 3 * GST_SECOND;
+    segment.time = 1 * GST_SECOND;
+    event = gst_event_new_segment (&segment);
+
+    eret = gst_pad_send_event (sinkpad, event);
+    fail_if (eret == FALSE);
+  }
+
+  /* do position query, this should succeed with the time value from the segment. */
+  qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
+  fail_unless (qret == TRUE);
+  fail_unless (qcur == 1 * GST_SECOND);
+
+  /* send buffer that we will flush out */
+  buffer = gst_buffer_new ();
+  GST_BUFFER_PTS (buffer) = 2 * GST_SECOND;
+  GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
+
+  GST_DEBUG ("sending buffer");
+
+  /* this buffer causes the sink to preroll */
+  data = chain_async (sinkpad, buffer);
+  fail_if (data == NULL);
+
+  /* wait for preroll */
+  ret = gst_element_get_state (pipeline, NULL, NULL, -1);
+
+  /* do position query, this should succeed with the time value from the
+   * segment. */
+  qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
+  fail_unless (qret == TRUE);
+  fail_unless (qcur == 1 * GST_SECOND);
+
+  /* start flushing */
+  {
+    GST_DEBUG ("sending flush_start");
+    event = gst_event_new_flush_start ();
+
+    eret = gst_pad_send_event (sinkpad, event);
+    fail_if (eret == FALSE);
+  }
+
+  /* preroll buffer is flushed out */
+  fret = chain_async_return (data);
+  fail_unless (fret == GST_FLOW_FLUSHING);
+
+  /* do position query, this should succeed with the time value from the
+   * segment before the flush. */
+  qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
+  fail_unless (qret == TRUE);
+  fail_unless (qcur == 1 * GST_SECOND);
+
+  /* send a FLUSH_STOP with reset_time=FALSE */
+  {
+    GST_DEBUG ("sending flush_stop");
+    event = gst_event_new_flush_stop (FALSE);
+
+    eret = gst_pad_send_event (sinkpad, event);
+    fail_if (eret == FALSE);
+  }
+
+  /* do position query again, this should again succeed with the time
+   * value from the segment before the flush. */
+  qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
+  fail_unless (qret == TRUE);
+  fail_unless (qcur == 1 * GST_SECOND);
+
+  /* send a different segment, this should work */
+  {
+    GstSegment segment;
+
+    GST_DEBUG ("sending segment");
+    gst_segment_init (&segment, GST_FORMAT_TIME);
+    segment.start = 2 * GST_SECOND;
+    segment.stop = 4 * GST_SECOND;
+    segment.time = 10 * GST_SECOND;
+    event = gst_event_new_segment (&segment);
+
+    eret = gst_pad_send_event (sinkpad, event);
+    fail_if (eret == FALSE);
+  }
+
+  /* do position query again, the position should reflect the time
+   * value from the new segment. */
+  qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
+  fail_unless (qret == TRUE);
+  fail_unless (qcur == 10 * GST_SECOND);
+
+  /* send buffer that we will flush out */
+  buffer = gst_buffer_new ();
+  GST_BUFFER_PTS (buffer) = 2 * GST_SECOND;
+  GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
+
+  GST_DEBUG ("sending buffer");
+
+  /* this buffer causes the sink to preroll */
+  data = chain_async (sinkpad, buffer);
+  fail_if (data == NULL);
+
+  /* wait for preroll */
+  ret = gst_element_get_state (pipeline, NULL, NULL, -1);
+
+  /* do position query, this should succeed with the time value from the
+   * segment. */
+  qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
+  fail_unless (qret == TRUE);
+  fail_unless (qcur == 10 * GST_SECOND);
+
+  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
+
+  /* preroll buffer is rendered */
+  fret = chain_async_return (data);
+  fail_unless (fret == GST_FLOW_OK);
+
+  ret = gst_element_set_state (pipeline, GST_STATE_NULL);
+  fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
+
+  /* fails because we are in the wrong state */
+  qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
+  fail_unless (qret == FALSE);
+
+  gst_object_unref (sinkpad);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
 /* like fakesrc, but also pushes an OOB event after each buffer */
 typedef GstPushSrc OOBSource;
 typedef GstPushSrcClass OOBSourceClass;
@@ -1190,6 +1359,7 @@ fakesink_suite (void)
   tcase_add_test (tc_chain, test_eos);
   tcase_add_test (tc_chain, test_eos2);
   tcase_add_test (tc_chain, test_position);
+  tcase_add_test (tc_chain, test_position_non_resetting_flush);
   tcase_add_test (tc_chain, test_notify_race);
   tcase_add_test (tc_chain, test_last_message_notify);
   tcase_skip_broken_test (tc_chain, test_last_message_deep_notify);
diff --git a/tests/check/elements/filesink.c b/tests/check/elements/filesink.c
index cccb703..53bc3a9 100644
--- a/tests/check/elements/filesink.c
+++ b/tests/check/elements/filesink.c
@@ -24,6 +24,7 @@
 #endif
 
 #include <stdio.h>
+#include <string.h>
 
 #include <glib.h>
 #include <glib/gstdio.h>
@@ -484,6 +485,86 @@ GST_START_TEST (test_uri_interface)
 
 GST_END_TEST;
 
+static void
+test_buffered_write (guint num_buf, guint num_mem_per_buf)
+{
+  GstElement *filesink;
+  guint i, j;
+  gchar *tmp_fn;
+  GstSegment segment;
+  const gsize size_per_mem = 4;
+  gsize total_size = size_per_mem * num_buf * num_mem_per_buf;
+  GStatBuf stat_buf;
+
+  tmp_fn = create_temporary_file ();
+  if (!tmp_fn)
+    return;
+
+  filesink = setup_filesink ();
+  g_object_set (filesink, "location", tmp_fn, NULL);
+
+  fail_unless_equals_int (gst_element_set_state (filesink, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_ASYNC);
+
+  fail_unless (gst_pad_push_event (mysrcpad,
+          gst_event_new_stream_start ("test")));
+
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  for (i = 0; i < num_buf; i++) {
+    GstBuffer *buf = gst_buffer_new ();
+    for (j = 0; j < num_mem_per_buf; j++) {
+      GstMemory *mem = gst_allocator_alloc (NULL, size_per_mem, NULL);
+      GstMapInfo info;
+      fail_unless (mem != NULL);
+
+      fail_unless (gst_memory_map (mem, &info, GST_MAP_WRITE));
+      memset (info.data, 0, info.size);
+      gst_memory_unmap (mem, &info);
+
+      gst_buffer_append_memory (buf, mem);
+    }
+
+    fail_unless_equals_int (gst_pad_push (mysrcpad, buf), GST_FLOW_OK);
+  }
+
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+
+  fail_unless_equals_int (gst_element_set_state (filesink, GST_STATE_NULL),
+      GST_STATE_CHANGE_SUCCESS);
+
+  cleanup_filesink (filesink);
+
+  if (g_stat (tmp_fn, &stat_buf) == 0)
+    fail_unless_equals_int64 (stat_buf.st_size, total_size);
+
+  g_remove (tmp_fn);
+  g_free (tmp_fn);
+}
+
+GST_START_TEST (test_buffered_write_17_1)
+{
+  test_buffered_write (17, 1);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_buffered_write_9_2)
+{
+  test_buffered_write (9, 2);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_buffered_write_6_3)
+{
+  test_buffered_write (6, 3);
+}
+
+GST_END_TEST;
+
 static Suite *
 filesink_suite (void)
 {
@@ -496,6 +577,9 @@ filesink_suite (void)
   tcase_add_test (tc_chain, test_uri_interface);
   tcase_add_test (tc_chain, test_seeking);
   tcase_add_test (tc_chain, test_flush);
+  tcase_add_test (tc_chain, test_buffered_write_17_1);
+  tcase_add_test (tc_chain, test_buffered_write_9_2);
+  tcase_add_test (tc_chain, test_buffered_write_6_3);
 
   return s;
 }
diff --git a/tests/check/elements/multiqueue.c b/tests/check/elements/multiqueue.c
index 817afa4..90e3af1 100644
--- a/tests/check/elements/multiqueue.c
+++ b/tests/check/elements/multiqueue.c
@@ -1661,6 +1661,80 @@ GST_START_TEST (test_stream_status_messages)
 
 GST_END_TEST;
 
+static void
+queue_overrun_cb (GstElement * mq, guint * overrun_count)
+{
+  *overrun_count += 1;
+  g_object_set (mq, "max-size-time", (guint64) 0, NULL);
+}
+
+GST_START_TEST (test_time_level_before_output)
+{
+  GstElement *mq;
+  GstPad *sinkpad;
+  GstPad *srcpad;
+  GstBuffer *buffer;
+  GstSegment segment;
+  GstCaps *caps;
+  guint overrun_count = 0;
+
+  mq = gst_element_factory_make ("multiqueue", NULL);
+  g_object_set (mq, "max-size-time", 5 * GST_SECOND, NULL);
+  g_signal_connect (mq, "overrun",
+      G_CALLBACK (queue_overrun_cb), &overrun_count);
+
+  sinkpad = gst_element_request_pad_simple (mq, "sink_%u");
+  srcpad = gst_element_get_static_pad (mq, "src_0");
+
+  gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+      NULL, NULL, NULL);
+
+  fail_unless (gst_element_set_state (mq,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
+  caps = gst_caps_new_empty_simple ("foo/x-bar");
+  gst_pad_send_event (sinkpad, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  gst_pad_send_event (sinkpad, gst_event_new_segment (&segment));
+
+  buffer = gst_buffer_new_and_alloc (4);
+  GST_BUFFER_TIMESTAMP (buffer) = 25 * GST_SECOND;
+  GST_BUFFER_DURATION (buffer) = GST_SECOND;
+  gst_pad_chain (sinkpad, buffer);
+
+  /* Pushed 1 second duration buffer, should not cause overrun */
+  fail_unless_equals_int (overrun_count, 0);
+
+  /* 10 seconds duration will make queue full but multiqueue will notify
+   * of overrun on the next push */
+  buffer = gst_buffer_new_and_alloc (4);
+  GST_BUFFER_TIMESTAMP (buffer) = 26 * GST_SECOND;
+  GST_BUFFER_DURATION (buffer) = 10 * GST_SECOND;
+  gst_pad_chain (sinkpad, buffer);
+  fail_unless_equals_int (overrun_count, 0);
+
+  /* Already filled, overrun is expected */
+  buffer = gst_buffer_new_and_alloc (4);
+  GST_BUFFER_TIMESTAMP (buffer) = 36 * GST_SECOND;
+  gst_pad_chain (sinkpad, buffer);
+
+  fail_unless_equals_int (overrun_count, 1);
+
+  fail_unless (gst_element_set_state (mq,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+
+  gst_element_release_request_pad (mq, sinkpad);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+  gst_object_unref (mq);
+}
+
+GST_END_TEST;
+
 static Suite *
 multiqueue_suite (void)
 {
@@ -1692,6 +1766,7 @@ multiqueue_suite (void)
   tcase_add_test (tc_chain, test_initial_events_nodelay);
 
   tcase_add_test (tc_chain, test_stream_status_messages);
+  tcase_add_test (tc_chain, test_time_level_before_output);
 
   return s;
 }
diff --git a/tests/check/elements/queue.c b/tests/check/elements/queue.c
index 9663a68..71de2d5 100644
--- a/tests/check/elements/queue.c
+++ b/tests/check/elements/queue.c
@@ -532,20 +532,19 @@ GST_START_TEST (test_time_level)
   /* pushing gives away my reference */
   gst_pad_push (mysrcpad, buffer);
 
-  /* level should be 1 seconds because buffer has no duration and starts at 1
-   * SECOND (sparse stream). */
+  /* level should be zero because buffer has no duration */
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_if (time != GST_SECOND);
+  fail_if (time != 0);
 
-  /* second push should set the level to 2 second */
+  /* second push should set the level to 1 second */
   buffer = gst_buffer_new_and_alloc (4);
   GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND;
   gst_pad_push (mysrcpad, buffer);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_if (time != 2 * GST_SECOND);
+  fail_if (time != GST_SECOND);
 
-  /* third push should set the level to 4 seconds, the 1 second diff with the
+  /* third push should set the level to 3 seconds, the 1 second diff with the
    * previous buffer (without duration) and the 1 second duration of this
    * buffer. */
   buffer = gst_buffer_new_and_alloc (4);
@@ -555,9 +554,9 @@ GST_START_TEST (test_time_level)
   gst_pad_push (mysrcpad, buffer);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_if (time != 4 * GST_SECOND);
+  fail_if (time != 3 * GST_SECOND);
 
-  /* fourth push should set the level to 6 seconds, the 2 second diff with the
+  /* fourth push should set the level to 5 seconds, the 2 second diff with the
    * previous buffer, same duration. */
   buffer = gst_buffer_new_and_alloc (4);
   GST_BUFFER_TIMESTAMP (buffer) = 5 * GST_SECOND;
@@ -566,7 +565,7 @@ GST_START_TEST (test_time_level)
   gst_pad_push (mysrcpad, buffer);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_if (time != 6 * GST_SECOND);
+  fail_if (time != 5 * GST_SECOND);
 
   /* fifth push should not adjust the level, the timestamp and duration are the
    * same, meaning the previous buffer did not really have a duration. */
@@ -576,7 +575,7 @@ GST_START_TEST (test_time_level)
   gst_pad_push (mysrcpad, buffer);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_if (time != 6 * GST_SECOND);
+  fail_if (time != 5 * GST_SECOND);
 
   /* sixth push should adjust the level with 1 second, we now know the
    * previous buffer actually had a duration of 2 SECONDS */
@@ -585,7 +584,7 @@ GST_START_TEST (test_time_level)
   gst_pad_push (mysrcpad, buffer);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_if (time != 7 * GST_SECOND);
+  fail_if (time != 6 * GST_SECOND);
 
   /* eighth push should cause overrun */
   fail_unless (overrun_count == 0);
@@ -635,7 +634,7 @@ GST_START_TEST (test_time_level_task_not_started)
   gst_pad_push_event (mysrcpad, event);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_if (time != 0 * GST_SECOND);
+  fail_if (time != 0);
 
   segment.base = 4 * GST_SECOND;
   event = gst_event_new_segment (&segment);
@@ -643,7 +642,7 @@ GST_START_TEST (test_time_level_task_not_started)
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
   GST_DEBUG ("time now %" GST_TIME_FORMAT, GST_TIME_ARGS (time));
-  fail_if (time != 4 * GST_SECOND);
+  fail_if (time != 0);
 
   unblock_src ();
 
@@ -1018,10 +1017,9 @@ GST_START_TEST (test_time_level_buffer_list)
   /* pushing gives away my reference */
   gst_pad_push (mysrcpad, buffer);
 
-  /* level should be 1 seconds because buffer has no duration and starts at 1
-   * SECOND (sparse stream). */
+  /* level should be zero because buffer has no duration */
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_unless_equals_uint64 (time, 1000 * GST_MSECOND);
+  fail_unless_equals_uint64 (time, 0);
   g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL);
   fail_unless_equals_int (buffers, 1);
 
@@ -1036,11 +1034,11 @@ GST_START_TEST (test_time_level_buffer_list)
   gst_pad_push_list (mysrcpad, buffer_list);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_unless_equals_uint64 (time, 2000 * GST_MSECOND);
+  fail_unless_equals_uint64 (time, 1000 * GST_MSECOND);
   g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL);
   fail_unless_equals_int (buffers, 3);
 
-  /* third push should set the level to 4 seconds, the 1 second diff with the
+  /* third push should set the level to 3 seconds, the 1 second diff with the
    * previous buffer (without duration) and the 1 second duration of this
    * buffer. */
   buffer_list = gst_buffer_list_new ();
@@ -1057,11 +1055,11 @@ GST_START_TEST (test_time_level_buffer_list)
   gst_pad_push_list (mysrcpad, buffer_list);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_unless_equals_uint64 (time, 4000 * GST_MSECOND);
+  fail_unless_equals_uint64 (time, 3000 * GST_MSECOND);
   g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL);
   fail_unless_equals_int (buffers, 5);
 
-  /* fourth push should set the level to 6 seconds, the 2 second diff with the
+  /* fourth push should set the level to 5 seconds, the 2 second diff with the
    * previous buffer, same duration. */
   buffer_list = gst_buffer_list_new ();
   buffer = gst_buffer_new_and_alloc (4);
@@ -1072,7 +1070,7 @@ GST_START_TEST (test_time_level_buffer_list)
   gst_pad_push_list (mysrcpad, buffer_list);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_unless_equals_uint64 (time, 6000 * GST_MSECOND);
+  fail_unless_equals_uint64 (time, 5000 * GST_MSECOND);
   g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL);
   fail_unless_equals_int (buffers, 6);
 
@@ -1098,7 +1096,7 @@ GST_START_TEST (test_time_level_buffer_list)
   gst_pad_push_list (mysrcpad, buffer_list);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_unless_equals_uint64 (time, 6000 * GST_MSECOND);
+  fail_unless_equals_uint64 (time, 5000 * GST_MSECOND);
   g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL);
   fail_unless_equals_int (buffers, 10);
 
@@ -1109,7 +1107,7 @@ GST_START_TEST (test_time_level_buffer_list)
   gst_pad_push (mysrcpad, buffer);
 
   g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
-  fail_unless_equals_uint64 (time, 7000 * GST_MSECOND);
+  fail_unless_equals_uint64 (time, 6000 * GST_MSECOND);
   g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL);
   fail_unless_equals_int (buffers, 11);
 
@@ -1181,6 +1179,208 @@ GST_START_TEST (test_initial_events_nodelay)
 
 GST_END_TEST;
 
+typedef struct
+{
+  GstBuffer *buffer;
+  GMutex lock;
+  GCond cond;
+  gboolean blocked;
+} FlushOnErrorData;
+
+static GstPadProbeReturn
+flush_on_error_block_probe (GstPad * pad, GstPadProbeInfo * info,
+    FlushOnErrorData * data)
+{
+  g_mutex_lock (&data->lock);
+  data->blocked = TRUE;
+  g_cond_signal (&data->cond);
+  g_mutex_unlock (&data->lock);
+
+  return GST_PAD_PROBE_OK;
+}
+
+static GstPadProbeReturn
+flush_on_error_probe (GstPad * pad, GstPadProbeInfo * info,
+    FlushOnErrorData * data)
+{
+  if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info)))
+    return GST_PAD_PROBE_DROP;
+
+  g_mutex_lock (&data->lock);
+  data->buffer = GST_PAD_PROBE_INFO_BUFFER (info);
+  g_cond_signal (&data->cond);
+  g_mutex_unlock (&data->lock);
+
+  GST_PAD_PROBE_INFO_FLOW_RETURN (info) = GST_FLOW_ERROR;
+
+  return GST_PAD_PROBE_HANDLED;
+}
+
+static gpointer
+alloc_thread (GstBufferPool * pool)
+{
+  GstFlowReturn ret;
+  GstBuffer *buf;
+
+  /* This call will be blocked */
+  ret = gst_buffer_pool_acquire_buffer (pool, &buf, NULL);
+  fail_unless (ret == GST_FLOW_OK);
+
+  gst_buffer_unref (buf);
+
+  return NULL;
+}
+
+GST_START_TEST (test_flush_on_error)
+{
+  GstElement *elem;
+  GstPad *sinkpad;
+  GstPad *srcpad;
+  GstSegment segment;
+  GstCaps *caps;
+  gboolean ret;
+  gulong block_id;
+  FlushOnErrorData data;
+  GstBufferPool *pool;
+  GstStructure *config;
+  GstBuffer *buf;
+  GstFlowReturn flow_ret;
+  GThread *thread;
+
+  data.buffer = NULL;
+  data.blocked = FALSE;
+  g_mutex_init (&data.lock);
+  g_cond_init (&data.cond);
+
+  /* Setup bufferpool with max-buffers 2 */
+  caps = gst_caps_new_empty_simple ("foo/x-bar");
+  pool = gst_buffer_pool_new ();
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, caps, 4, 0, 2);
+  gst_buffer_pool_set_config (pool, config);
+  gst_buffer_pool_set_active (pool, TRUE);
+
+  elem = gst_element_factory_make ("queue", NULL);
+  gst_object_ref_sink (elem);
+  sinkpad = gst_element_get_static_pad (elem, "sink");
+  srcpad = gst_element_get_static_pad (elem, "src");
+
+  block_id = gst_pad_add_probe (srcpad,
+      GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,
+      (GstPadProbeCallback) flush_on_error_block_probe, &data, NULL);
+  gst_pad_add_probe (srcpad,
+      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_BUFFER,
+      (GstPadProbeCallback) flush_on_error_probe, &data, NULL);
+
+  fail_unless (gst_element_set_state (elem,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  ret = gst_pad_send_event (sinkpad,
+      gst_event_new_stream_start ("test-stream-start"));
+  fail_unless (ret);
+
+  ret = gst_pad_send_event (sinkpad, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  fail_unless (ret);
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  ret = gst_pad_send_event (sinkpad, gst_event_new_segment (&segment));
+  fail_unless (ret);
+
+  flow_ret = gst_buffer_pool_acquire_buffer (pool, &buf, NULL);
+  fail_unless (flow_ret == GST_FLOW_OK);
+  GST_BUFFER_PTS (buf) = 0;
+  flow_ret = gst_pad_chain (sinkpad, buf);
+  fail_unless (flow_ret == GST_FLOW_OK);
+
+  flow_ret = gst_buffer_pool_acquire_buffer (pool, &buf, NULL);
+  fail_unless (flow_ret == GST_FLOW_OK);
+  GST_BUFFER_PTS (buf) = GST_SECOND;
+  flow_ret = gst_pad_chain (sinkpad, buf);
+  fail_unless (flow_ret == GST_FLOW_OK);
+
+  /* Acquire buffer from other thread. The acquire_buffer() will be blocked
+   * due to max-buffers 2 */
+  thread = g_thread_new (NULL, (GThreadFunc) alloc_thread, pool);
+
+  g_mutex_lock (&data.lock);
+  while (!data.blocked)
+    g_cond_wait (&data.cond, &data.lock);
+  g_mutex_unlock (&data.lock);
+
+  gst_pad_remove_probe (srcpad, block_id);
+
+  /* Then now acquire thread can be unblocked since queue will flush
+   * internal queue on flow error */
+  g_thread_join (thread);
+
+  gst_element_set_state (elem, GST_STATE_NULL);
+  gst_clear_buffer (&data.buffer);
+  gst_buffer_pool_set_active (pool, FALSE);
+  gst_object_unref (pool);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+  gst_object_unref (elem);
+  g_mutex_clear (&data.lock);
+  g_cond_clear (&data.cond);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_time_level_before_output)
+{
+  GstBuffer *buffer1;
+  GstBuffer *buffer2;
+  GstSegment segment;
+  GstClockTime time;
+
+  g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun), NULL);
+  g_object_set (queue, "max-size-time", 5 * GST_SECOND, "leaky", 2, NULL);
+
+  block_src ();
+
+  UNDERRUN_LOCK ();
+  fail_unless (gst_element_set_state (queue,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+  UNDERRUN_WAIT ();
+  UNDERRUN_UNLOCK ();
+
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
+  gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment));
+
+  fail_unless_equals_int (overrun_count, 0);
+  fail_unless_equals_int (underrun_count, 1);
+
+  buffer1 = gst_buffer_new_and_alloc (4);
+  GST_BUFFER_TIMESTAMP (buffer1) = 25 * GST_SECOND;
+  GST_BUFFER_DURATION (buffer1) = GST_SECOND;
+  gst_pad_push (mysrcpad, buffer1);
+
+  /* Pushed 1 second duration buffer, should report 1 seconds */
+  g_object_get (queue, "current-level-time", &time, NULL);
+  fail_unless_equals_int64 (time, GST_SECOND);
+  fail_unless_equals_int (overrun_count, 0);
+  fail_unless_equals_int (underrun_count, 1);
+
+  buffer2 = gst_buffer_new_and_alloc (4);
+  gst_pad_push (mysrcpad, buffer2);
+
+  /* Pushed with unknown duration, should not cause overrun and
+   * timelevel should not be changed */
+  g_object_get (queue, "current-level-time", &time, NULL);
+  fail_unless_equals_int64 (time, GST_SECOND);
+  fail_unless_equals_int (overrun_count, 0);
+  fail_unless_equals_int (underrun_count, 1);
+
+  fail_unless (gst_element_set_state (queue,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+}
+
+GST_END_TEST;
+
 static Suite *
 queue_suite (void)
 {
@@ -1204,6 +1404,8 @@ queue_suite (void)
   tcase_add_test (tc_chain, test_sticky_not_linked);
   tcase_add_test (tc_chain, test_time_level_buffer_list);
   tcase_add_test (tc_chain, test_initial_events_nodelay);
+  tcase_add_test (tc_chain, test_flush_on_error);
+  tcase_add_test (tc_chain, test_time_level_before_output);
 
   return s;
 }
diff --git a/tests/check/elements/queue2.c b/tests/check/elements/queue2.c
index c27e973..ac0526d 100644
--- a/tests/check/elements/queue2.c
+++ b/tests/check/elements/queue2.c
@@ -715,6 +715,213 @@ GST_START_TEST (test_ready_paused_buffering_message)
 
 GST_END_TEST;
 
+typedef struct
+{
+  GstBuffer *buffer;
+  GMutex lock;
+  GCond cond;
+  gboolean blocked;
+} FlushOnErrorData;
+
+static GstPadProbeReturn
+flush_on_error_block_probe (GstPad * pad, GstPadProbeInfo * info,
+    FlushOnErrorData * data)
+{
+  g_mutex_lock (&data->lock);
+  data->blocked = TRUE;
+  g_cond_signal (&data->cond);
+  g_mutex_unlock (&data->lock);
+
+  return GST_PAD_PROBE_OK;
+}
+
+static GstPadProbeReturn
+flush_on_error_probe (GstPad * pad, GstPadProbeInfo * info,
+    FlushOnErrorData * data)
+{
+  if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info)))
+    return GST_PAD_PROBE_DROP;
+
+  g_mutex_lock (&data->lock);
+  data->buffer = GST_PAD_PROBE_INFO_BUFFER (info);
+  g_cond_signal (&data->cond);
+  g_mutex_unlock (&data->lock);
+
+  GST_PAD_PROBE_INFO_FLOW_RETURN (info) = GST_FLOW_ERROR;
+
+  return GST_PAD_PROBE_HANDLED;
+}
+
+static gpointer
+alloc_thread (GstBufferPool * pool)
+{
+  GstFlowReturn ret;
+  GstBuffer *buf;
+
+  /* This call will be blocked */
+  ret = gst_buffer_pool_acquire_buffer (pool, &buf, NULL);
+  fail_unless (ret == GST_FLOW_OK);
+
+  gst_buffer_unref (buf);
+
+  return NULL;
+}
+
+GST_START_TEST (test_flush_on_error)
+{
+  GstElement *elem;
+  GstPad *sinkpad;
+  GstPad *srcpad;
+  GstSegment segment;
+  GstCaps *caps;
+  gboolean ret;
+  gulong block_id;
+  FlushOnErrorData data;
+  GstBufferPool *pool;
+  GstStructure *config;
+  GstBuffer *buf;
+  GstFlowReturn flow_ret;
+  GThread *thread;
+
+  data.buffer = NULL;
+  data.blocked = FALSE;
+  g_mutex_init (&data.lock);
+  g_cond_init (&data.cond);
+
+  /* Setup bufferpool with max-buffers 2 */
+  caps = gst_caps_new_empty_simple ("foo/x-bar");
+  pool = gst_buffer_pool_new ();
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, caps, 4, 0, 2);
+  gst_buffer_pool_set_config (pool, config);
+  gst_buffer_pool_set_active (pool, TRUE);
+
+  elem = gst_element_factory_make ("queue2", NULL);
+  gst_object_ref_sink (elem);
+  sinkpad = gst_element_get_static_pad (elem, "sink");
+  srcpad = gst_element_get_static_pad (elem, "src");
+
+  block_id = gst_pad_add_probe (srcpad,
+      GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,
+      (GstPadProbeCallback) flush_on_error_block_probe, &data, NULL);
+  gst_pad_add_probe (srcpad,
+      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_BUFFER,
+      (GstPadProbeCallback) flush_on_error_probe, &data, NULL);
+
+  fail_unless (gst_element_set_state (elem,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  ret = gst_pad_send_event (sinkpad,
+      gst_event_new_stream_start ("test-stream-start"));
+  fail_unless (ret);
+
+  ret = gst_pad_send_event (sinkpad, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+  fail_unless (ret);
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  ret = gst_pad_send_event (sinkpad, gst_event_new_segment (&segment));
+  fail_unless (ret);
+
+  flow_ret = gst_buffer_pool_acquire_buffer (pool, &buf, NULL);
+  fail_unless (flow_ret == GST_FLOW_OK);
+  GST_BUFFER_PTS (buf) = 0;
+  flow_ret = gst_pad_chain (sinkpad, buf);
+  fail_unless (flow_ret == GST_FLOW_OK);
+
+  flow_ret = gst_buffer_pool_acquire_buffer (pool, &buf, NULL);
+  fail_unless (flow_ret == GST_FLOW_OK);
+  GST_BUFFER_PTS (buf) = GST_SECOND;
+  flow_ret = gst_pad_chain (sinkpad, buf);
+  fail_unless (flow_ret == GST_FLOW_OK);
+
+  /* Acquire buffer from other thread. The acquire_buffer() will be blocked
+   * due to max-buffers 2 */
+  thread = g_thread_new (NULL, (GThreadFunc) alloc_thread, pool);
+
+  g_mutex_lock (&data.lock);
+  while (!data.blocked)
+    g_cond_wait (&data.cond, &data.lock);
+  g_mutex_unlock (&data.lock);
+
+  gst_pad_remove_probe (srcpad, block_id);
+
+  /* Then now acquire thread can be unblocked since queue will flush
+   * internal queue on flow error */
+  g_thread_join (thread);
+
+  gst_element_set_state (elem, GST_STATE_NULL);
+  gst_clear_buffer (&data.buffer);
+  gst_buffer_pool_set_active (pool, FALSE);
+  gst_object_unref (pool);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+  gst_object_unref (elem);
+  g_mutex_clear (&data.lock);
+  g_cond_clear (&data.cond);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_time_level_before_output)
+{
+  GstElement *queue2;
+  GstPad *sinkpad;
+  GstPad *srcpad;
+  GstBuffer *buffer1;
+  GstBuffer *buffer2;
+  GstSegment segment;
+  GstClockTime time;
+  GstCaps *caps;
+
+  queue2 = gst_element_factory_make ("queue2", NULL);
+  g_object_set (queue2, "max-size-time", 5 * GST_SECOND, NULL);
+
+  sinkpad = gst_element_get_static_pad (queue2, "sink");
+  srcpad = gst_element_get_static_pad (queue2, "src");
+
+  gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+      NULL, NULL, NULL);
+
+  fail_unless (gst_element_set_state (queue2,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
+  caps = gst_caps_new_empty_simple ("foo/x-bar");
+  gst_pad_send_event (sinkpad, gst_event_new_caps (caps));
+  gst_caps_unref (caps);
+
+  gst_segment_init (&segment, GST_FORMAT_BYTES);
+  gst_pad_send_event (sinkpad, gst_event_new_segment (&segment));
+
+  buffer1 = gst_buffer_new_and_alloc (4);
+  GST_BUFFER_TIMESTAMP (buffer1) = 25 * GST_SECOND;
+  GST_BUFFER_DURATION (buffer1) = GST_SECOND;
+  gst_pad_chain (sinkpad, buffer1);
+
+  /* Pushed 1 second duration buffer, should report 1 seconds */
+  g_object_get (queue2, "current-level-time", &time, NULL);
+  fail_unless_equals_int64 (time, GST_SECOND);
+
+  buffer2 = gst_buffer_new_and_alloc (4);
+  gst_pad_chain (sinkpad, buffer2);
+
+  /* Pushed with unknown duration, timelevel should not be changed */
+  g_object_get (queue2, "current-level-time", &time, NULL);
+  fail_unless_equals_int64 (time, GST_SECOND);
+
+  fail_unless (gst_element_set_state (queue2,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+  gst_object_unref (queue2);
+}
+
+GST_END_TEST;
+
 static Suite *
 queue2_suite (void)
 {
@@ -733,6 +940,8 @@ queue2_suite (void)
   tcase_add_test (tc_chain, test_small_ring_buffer);
   tcase_add_test (tc_chain, test_bitrate_query);
   tcase_add_test (tc_chain, test_ready_paused_buffering_message);
+  tcase_add_test (tc_chain, test_flush_on_error);
+  tcase_add_test (tc_chain, test_time_level_before_output);
 
   return s;
 }
diff --git a/tests/check/elements/tee.c b/tests/check/elements/tee.c
index a19e73e..aa21906 100644
--- a/tests/check/elements/tee.c
+++ b/tests/check/elements/tee.c
@@ -339,7 +339,8 @@ GST_START_TEST (test_internal_links)
   GstIteratorResult res;
   GValue val1 = { 0, }
   , val2 = {
-  0,};
+    0,
+  };
 
   tee = gst_check_setup_element ("tee");
 
diff --git a/tests/check/gst/gstbin.c b/tests/check/gst/gstbin.c
index 88ff44d..8341d6e 100644
--- a/tests/check/gst/gstbin.c
+++ b/tests/check/gst/gstbin.c
@@ -1919,7 +1919,7 @@ G_STMT_START { \
   gst_bin_set_suppressed_flags (bin, suppressed_flags); \
   gst_bin_add (bin, element); \
   fail_unless ((natural_flags | GST_OBJECT_FLAGS (bin)) \
-      == expected_flags); \
+      == (expected_flags | GST_OBJECT_FLAG_CONSTRUCTED)); \
   gst_object_unref (bin); \
 } G_STMT_END
 
diff --git a/tests/check/gst/gstbuffer.c b/tests/check/gst/gstbuffer.c
index 647dcb6..dbb8478 100644
--- a/tests/check/gst/gstbuffer.c
+++ b/tests/check/gst/gstbuffer.c
@@ -258,7 +258,7 @@ GST_START_TEST (test_metadata_writable)
   ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 2);
   fail_unless (gst_buffer_is_writable (buffer) == FALSE);
 
-  /* Check that make_metadata_writable produces a new sub-buffer with 
+  /* Check that make_metadata_writable produces a new sub-buffer with
    * writable metadata. */
   sub1 = gst_buffer_make_writable (buffer);
   fail_if (sub1 == buffer);
@@ -967,6 +967,37 @@ GST_START_TEST (test_auto_unmap)
 
 GST_END_TEST;
 
+GST_START_TEST (test_reference_timestamp_meta_serialization)
+{
+  GstCaps *reference =
+      gst_caps_new_simple ("timestamp/x-unix", NULL, NULL, NULL);
+
+  /* Serialize */
+  GstBuffer *buffer = gst_buffer_new ();
+  GstReferenceTimestampMeta *meta =
+      gst_buffer_add_reference_timestamp_meta (buffer, reference, 1, 2);
+  GByteArray *data = g_byte_array_new ();
+  fail_unless (gst_meta_serialize_simple ((GstMeta *) meta, data));
+  gst_buffer_unref (buffer);
+
+  /* Deserialize */
+  buffer = gst_buffer_new ();
+  guint32 consumed;
+  meta = (GstReferenceTimestampMeta *) gst_meta_deserialize (buffer, data->data,
+      data->len, &consumed);
+  fail_unless (meta);
+  fail_unless (consumed == data->len);
+  fail_unless (gst_caps_is_equal (meta->reference, reference));
+  fail_unless_equals_uint64 (meta->timestamp, 1);
+  fail_unless_equals_uint64 (meta->duration, 2);
+  gst_buffer_unref (buffer);
+
+  gst_caps_unref (reference);
+  g_byte_array_unref (data);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_buffer_suite (void)
 {
@@ -994,6 +1025,7 @@ gst_buffer_suite (void)
   tcase_add_test (tc_chain, test_wrapped_bytes);
   tcase_add_test (tc_chain, test_new_memdup);
   tcase_add_test (tc_chain, test_auto_unmap);
+  tcase_add_test (tc_chain, test_reference_timestamp_meta_serialization);
 
   return s;
 }
diff --git a/tests/check/gst/gstbufferpool.c b/tests/check/gst/gstbufferpool.c
index 9f25c0d..737dc24 100644
--- a/tests/check/gst/gstbufferpool.c
+++ b/tests/check/gst/gstbufferpool.c
@@ -336,6 +336,114 @@ GST_START_TEST (test_no_deadlock_for_buffer_discard)
 
 GST_END_TEST;
 
+GST_START_TEST (test_parent_meta)
+{
+  GstBufferPool *pool;
+  GstBuffer *buf1, *buf2, *buf3;
+  GstMemory *mem;
+  gint buf1_dcount = 0;
+  gint buf2_dcount = 0;
+
+  pool = create_pool (1, 0, 0);
+  fail_unless (pool);
+  gst_buffer_pool_set_active (pool, TRUE);
+
+  fail_unless (gst_buffer_pool_acquire_buffer (pool, &buf1,
+          NULL) == GST_FLOW_OK);
+  buffer_track_destroy (buf1, &buf1_dcount);
+
+  /* Create a 2nd buffer reffing the same memory. Set parent meta to make sure
+   * buf1 does not return to pool until buf2 is destroyed. */
+  mem = gst_buffer_get_memory (buf1, 0);
+  buf2 = gst_buffer_new ();
+  gst_buffer_append_memory (buf2, mem);
+  gst_buffer_add_parent_buffer_meta (buf2, buf1);
+  buffer_track_destroy (buf2, &buf2_dcount);
+
+  /* buf1 is still reffed by the meta */
+  gst_buffer_unref (buf1);
+  fail_unless_equals_int (buf1_dcount, 0);
+  fail_unless_equals_int (buf2_dcount, 0);
+
+  /* buf2 gets destroyed and buf1 returns to pool */
+  gst_buffer_unref (buf2);
+  fail_unless_equals_int (buf1_dcount, 0);
+  fail_unless_equals_int (buf2_dcount, 1);
+
+  /* buf1 should be recycled with the same memory */
+  fail_unless (gst_buffer_pool_acquire_buffer (pool, &buf3,
+          NULL) == GST_FLOW_OK);
+  fail_unless_equals_pointer (buf1, buf3);
+  fail_unless_equals_pointer (mem, gst_buffer_peek_memory (buf3, 0));
+
+  gst_buffer_unref (buf3);
+  fail_unless_equals_int (buf1_dcount, 0);
+  fail_unless_equals_int (buf2_dcount, 1);
+
+  gst_buffer_pool_set_active (pool, FALSE);
+  gst_object_unref (pool);
+  fail_unless_equals_int (buf1_dcount, 1);
+  fail_unless_equals_int (buf2_dcount, 1);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_make_writable_parent_meta)
+{
+  GstBufferPool *pool;
+  GstBuffer *buf1, *buf2, *buf3;
+  GstMemory *mem1, *mem2;
+  gint buf1_dcount = 0;
+  gint buf2_dcount = 0;
+
+  pool = create_pool (1, 0, 0);
+  fail_unless (pool);
+  gst_buffer_pool_set_active (pool, TRUE);
+
+  fail_unless (gst_buffer_pool_acquire_buffer (pool, &buf1,
+          NULL) == GST_FLOW_OK);
+  buffer_track_destroy (buf1, &buf1_dcount);
+
+  /* Make buf1 not writable and copy it */
+  gst_buffer_ref (buf1);
+  buf2 = gst_buffer_make_writable (buf1);
+  buffer_track_destroy (buf2, &buf2_dcount);
+  fail_unless (buf1 != buf2);
+  fail_unless (gst_buffer_is_writable (buf2));
+
+  /* buf1 and buf2 should be sharing the same memory */
+  mem1 = gst_buffer_peek_memory (buf1, 0);
+  mem2 = gst_buffer_peek_memory (buf2, 0);
+  fail_unless_equals_pointer (mem1, mem2);
+
+  /* buf1 is still reffed by the meta */
+  gst_buffer_unref (buf1);
+  fail_unless_equals_int (buf1_dcount, 0);
+  fail_unless_equals_int (buf2_dcount, 0);
+
+  /* buf2 gets destroyed and buf1 returns to pool */
+  gst_buffer_unref (buf2);
+  fail_unless_equals_int (buf1_dcount, 0);
+  fail_unless_equals_int (buf2_dcount, 1);
+
+  /* buf1 should be recycled with the same memory */
+  fail_unless (gst_buffer_pool_acquire_buffer (pool, &buf3,
+          NULL) == GST_FLOW_OK);
+  fail_unless_equals_pointer (buf1, buf3);
+  fail_unless_equals_pointer (mem1, gst_buffer_peek_memory (buf3, 0));
+
+  gst_buffer_unref (buf3);
+  fail_unless_equals_int (buf1_dcount, 0);
+  fail_unless_equals_int (buf2_dcount, 1);
+
+  gst_buffer_pool_set_active (pool, FALSE);
+  gst_object_unref (pool);
+  fail_unless_equals_int (buf1_dcount, 1);
+  fail_unless_equals_int (buf2_dcount, 1);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_buffer_pool_suite (void)
 {
@@ -355,6 +463,8 @@ gst_buffer_pool_suite (void)
   tcase_add_test (tc_chain, test_pool_config_validate);
   tcase_add_test (tc_chain, test_flushing_pool_returns_flushing);
   tcase_add_test (tc_chain, test_no_deadlock_for_buffer_discard);
+  tcase_add_test (tc_chain, test_parent_meta);
+  tcase_add_test (tc_chain, test_make_writable_parent_meta);
 
   return s;
 }
diff --git a/tests/check/gst/gstdevice.c b/tests/check/gst/gstdevice.c
index 0c4d91f..baddb33 100644
--- a/tests/check/gst/gstdevice.c
+++ b/tests/check/gst/gstdevice.c
@@ -178,7 +178,6 @@ GST_DEVICE_PROVIDER_REGISTER_DECLARE (testdeviceprovider);
 
 GST_DEVICE_PROVIDER_REGISTER_DEFINE (testdeviceprovider, "testdeviceprovider",
     1, gst_test_device_provider_get_type ())
-
      static void register_test_device_provider (void)
 {
   gst_device_provider_register (NULL, "testdeviceprovider", 1,
diff --git a/tests/check/gst/gstelementfactory.c b/tests/check/gst/gstelementfactory.c
index 7d72247..9d9960b 100644
--- a/tests/check/gst/gstelementfactory.c
+++ b/tests/check/gst/gstelementfactory.c
@@ -19,6 +19,7 @@
  * Boston, MA 02110-1301, USA.
  */
 #include "../../gst/gst_private.h"
+#include "../../gst/glib-compat-private.h"
 
 #include <gst/check/gstcheck.h>
 
@@ -38,7 +39,7 @@ setup_pad_template (GstElementFactory * factory, GstStaticPadTemplate * tmpl)
 {
   GstStaticPadTemplate *template;
 
-  template = g_slice_dup (GstStaticPadTemplate, tmpl);
+  template = g_memdup2 (tmpl, sizeof (GstStaticPadTemplate));
   factory->staticpadtemplates = g_list_append (factory->staticpadtemplates,
       template);
   factory->numpadtemplates++;
diff --git a/tests/check/gst/gstinfo.c b/tests/check/gst/gstinfo.c
index dba7d63..8615e48 100644
--- a/tests/check/gst/gstinfo.c
+++ b/tests/check/gst/gstinfo.c
@@ -516,8 +516,8 @@ GST_END_TEST;
 
 GST_START_TEST (info_set_and_reset_string)
 {
-  GstDebugCategory *states;
-  GstDebugCategory *caps;
+  GstDebugCategory *states = NULL;
+  GstDebugCategory *caps = NULL;
   GstDebugLevel cat;
 
   GST_DEBUG_CATEGORY_GET (states, "GST_STATES");
diff --git a/tests/check/gst/gstiterator.c b/tests/check/gst/gstiterator.c
index 9e989f8..5004360 100644
--- a/tests/check/gst/gstiterator.c
+++ b/tests/check/gst/gstiterator.c
@@ -37,6 +37,41 @@ make_list_of_ints (gint n)
   return g_list_reverse (ret);
 }
 
+static GstIteratorResult
+broken_iterator_next (G_GNUC_UNUSED GstIterator * it,
+    G_GNUC_UNUSED GValue * val)
+{
+  return GST_ITERATOR_ERROR;
+}
+
+static void
+broken_iterator_resync (G_GNUC_UNUSED GstIterator * it)
+{
+}
+
+static void
+broken_iterator_free (G_GNUC_UNUSED GstIterator * it)
+{
+}
+
+static GstIterator *
+make_broken_iterator (GType item_type, GMutex * mutex, guint32 * cookie)
+{
+  return gst_iterator_new (sizeof (GstIterator),
+      item_type,
+      mutex,
+      cookie,
+      NULL,
+      broken_iterator_next, NULL, broken_iterator_resync, broken_iterator_free);
+}
+
+static gint
+passthrough_filter (G_GNUC_UNUSED gconstpointer a,
+    G_GNUC_UNUSED gconstpointer b)
+{
+  return 0;
+}
+
 #define NUM_ELEMENTS 10
 
 GST_START_TEST (test_manual_iteration)
@@ -424,6 +459,28 @@ GST_START_TEST (test_filter_of_filter_locking)
 
 GST_END_TEST;
 
+GST_START_TEST (test_filter_propagates_error)
+{
+  guint32 cookie = 0;
+  GMutex m;
+  g_mutex_init (&m);
+
+  GValue v = G_VALUE_INIT;
+  g_value_init (&v, G_TYPE_POINTER);
+
+  GstIterator *it =
+      gst_iterator_filter (make_broken_iterator (G_TYPE_POINTER, &mutex,
+          &cookie), passthrough_filter, NULL);
+
+  fail_unless_equals_int (gst_iterator_next (it, &v), GST_ITERATOR_ERROR);
+
+  gst_iterator_free (it);
+  g_mutex_clear (&m);
+  g_value_unset (&v);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_iterator_suite (void)
 {
@@ -441,6 +498,7 @@ gst_iterator_suite (void)
   tcase_add_test (tc_chain, test_filter_locking);
   tcase_add_test (tc_chain, test_filter_of_filter);
   tcase_add_test (tc_chain, test_filter_of_filter_locking);
+  tcase_add_test (tc_chain, test_filter_propagates_error);
   return s;
 }
 
diff --git a/tests/check/gst/gstmemory.c b/tests/check/gst/gstmemory.c
index 1cde398..def8bcb 100644
--- a/tests/check/gst/gstmemory.c
+++ b/tests/check/gst/gstmemory.c
@@ -588,7 +588,7 @@ static GstMemory *
 _my_opaque_alloc (GstAllocator * allocator, gsize size,
     GstAllocationParams * params)
 {
-  MyOpaqueMemory *mem = g_slice_new (MyOpaqueMemory);
+  MyOpaqueMemory *mem = g_new (MyOpaqueMemory, 1);
   gsize maxsize = size + params->prefix + params->padding;
 
   gst_memory_init (GST_MEMORY_CAST (mem), params->flags, allocator, NULL,
@@ -605,7 +605,7 @@ _my_opaque_free (GstAllocator * allocator, GstMemory * mem)
   MyOpaqueMemory *mmem = (MyOpaqueMemory *) mem;
 
   g_free (mmem->data);
-  g_slice_free (MyOpaqueMemory, mmem);
+  g_free (mmem);
 }
 
 static gpointer
diff --git a/tests/check/gst/gstmeta.c b/tests/check/gst/gstmeta.c
index b5d0392..7228c99 100644
--- a/tests/check/gst/gstmeta.c
+++ b/tests/check/gst/gstmeta.c
@@ -808,6 +808,53 @@ GST_START_TEST (test_meta_custom_transform)
 
 GST_END_TEST;
 
+GST_START_TEST (test_meta_custom_serialize)
+{
+  const GstMetaInfo *info;
+  GstCustomMeta *meta;
+  GstBuffer *buffer;
+
+  info = gst_meta_register_custom_simple ("test-custom-serialize");
+  fail_unless (info != NULL);
+
+  /* add some metadata */
+  buffer = gst_buffer_new ();
+  meta = gst_buffer_add_custom_meta (buffer, "test-custom-serialize");
+  gst_structure_set (meta->structure, "test-field", G_TYPE_INT, 42, NULL);
+
+  /* Serialize */
+  GByteArray *data = g_byte_array_new ();
+  fail_unless (gst_meta_serialize_simple ((GstMeta *) meta, data));
+  gst_buffer_unref (buffer);
+
+  /* Create a new buffer */
+  buffer = gst_buffer_new ();
+  guint32 consumed;
+  meta = (GstCustomMeta *) gst_meta_deserialize (buffer, data->data, data->len,
+      &consumed);
+  fail_unless (meta);
+  fail_unless (consumed == data->len);
+
+  /* Check meta's content */
+  fail_unless (gst_custom_meta_has_name (meta, "test-custom-serialize"));
+  gint val;
+  fail_unless (gst_structure_get_int (meta->structure, "test-field", &val));
+  fail_unless_equals_int (val, 42);
+
+  /* Add field that cannot be serialized */
+  GstElement *bin = gst_bin_new ("mybin");
+  gst_structure_set (meta->structure, "test-field-obj", GST_TYPE_BIN, bin,
+      NULL);
+  g_byte_array_set_size (data, 0);
+  fail_if (gst_meta_serialize_simple ((GstMeta *) meta, data));
+  fail_if (data->len != 0);
+  gst_object_unref (bin);
+  gst_buffer_unref (buffer);
+  g_byte_array_unref (data);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_buffermeta_suite (void)
 {
@@ -827,6 +874,7 @@ gst_buffermeta_suite (void)
   tcase_add_test (tc_chain, test_meta_seqnum);
   tcase_add_test (tc_chain, test_meta_custom);
   tcase_add_test (tc_chain, test_meta_custom_transform);
+  tcase_add_test (tc_chain, test_meta_custom_serialize);
 
   return s;
 }
diff --git a/tests/check/gst/gstobject.c b/tests/check/gst/gstobject.c
index 3d9660a..9daee3a 100644
--- a/tests/check/gst/gstobject.c
+++ b/tests/check/gst/gstobject.c
@@ -284,12 +284,18 @@ GST_START_TEST (test_fake_object_name_threaded_right)
 
   /* start looping and set/get name repeatedly */
   for (i = 0; i < 1000; ++i) {
+#ifndef g_autoptr
     GST_OBJECT_LOCK (object);
+#else
+    GST_OBJECT_AUTO_LOCK (object, locker);
+#endif
     g_free (GST_OBJECT_NAME (object));
     GST_OBJECT_NAME (object) = g_strdup ("main");
     THREAD_SWITCH ();
     name = g_strdup (GST_OBJECT_NAME (object));
+#ifndef g_autoptr
     GST_OBJECT_UNLOCK (object);
+#endif
 
     fail_unless (strcmp (name, "main") == 0,
         "Name got changed while lock held during run %d", i);
diff --git a/tests/check/gst/gstplugin.c b/tests/check/gst/gstplugin.c
index 4550bca..dac7a8c 100644
--- a/tests/check/gst/gstplugin.c
+++ b/tests/check/gst/gstplugin.c
@@ -267,17 +267,9 @@ GST_START_TEST (test_version_checks)
           GST_VERSION_MAJOR, GST_VERSION_MINOR + 1, GST_VERSION_MICRO) == TRUE,
       "Unexpected version check result");
 
-  /* If the nano is set, then we expect that X.Y.Z-1.x >= X.Y.Z, so that a
-   * devel plugin is valid against an upcoming release */
-  if (GST_VERSION_NANO > 0) {
-    fail_unless (gst_default_registry_check_feature_version ("identity",
-            GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO + 1) ==
-        TRUE, "Unexpected version check result");
-  } else {
-    fail_if (gst_default_registry_check_feature_version ("identity",
-            GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO + 1) ==
-        TRUE, "Unexpected version check result");
-  }
+  fail_if (gst_default_registry_check_feature_version ("identity",
+          GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO + 1) ==
+      TRUE, "Unexpected version check result");
 
   if (GST_VERSION_MAJOR > 0) {
     fail_if (gst_default_registry_check_feature_version ("identity",
@@ -304,6 +296,70 @@ GST_START_TEST (test_version_checks)
 
 GST_END_TEST;
 
+static gboolean
+register_check_status_messages (GstPlugin * plugin)
+{
+  gst_plugin_add_status_info (plugin, "Hello World!");
+  gst_plugin_add_status_warning (plugin, "This not so good");
+  gst_plugin_add_status_warning (plugin, "Not good either!");
+  gst_plugin_add_status_error (plugin, "Oh no!");
+  return TRUE;
+}
+
+GST_START_TEST (test_status_messages)
+{
+  GstPlugin *plugin;
+
+  fail_unless (gst_plugin_register_static (GST_VERSION_MAJOR,
+          GST_VERSION_MINOR, "status-messages", "status-messages",
+          register_check_status_messages, VERSION, GST_LICENSE, PACKAGE,
+          GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN));
+
+  fail_unless (gst_plugin_register_static (GST_VERSION_MAJOR,
+          GST_VERSION_MINOR, "no-status-messages", "no-status-messages",
+          register_check_elements, VERSION, GST_LICENSE, PACKAGE,
+          GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN));
+
+  plugin = gst_registry_find_plugin (gst_registry_get (), "status-messages");
+  fail_unless (plugin != NULL);
+
+  {
+    gchar **info_msgs = gst_plugin_get_status_infos (plugin);
+
+    fail_unless_equals_int (g_strv_length (info_msgs), 1);
+    fail_unless_equals_string (info_msgs[0], "Hello World!");
+    g_strfreev (info_msgs);
+  }
+
+  {
+    gchar **warn_msgs = gst_plugin_get_status_warnings (plugin);
+
+    fail_unless_equals_int (g_strv_length (warn_msgs), 2);
+    fail_unless_equals_string (warn_msgs[0], "This not so good");
+    fail_unless_equals_string (warn_msgs[1], "Not good either!");
+    g_strfreev (warn_msgs);
+  }
+
+  {
+    gchar **err_msgs = gst_plugin_get_status_errors (plugin);
+
+    fail_unless_equals_int (g_strv_length (err_msgs), 1);
+    fail_unless_equals_string (err_msgs[0], "Oh no!");
+    g_strfreev (err_msgs);
+  }
+
+  gst_object_unref (plugin);
+
+  plugin = gst_registry_find_plugin (gst_registry_get (), "no-status-messages");
+  fail_unless (plugin != NULL);
+  fail_unless (gst_plugin_get_status_infos (plugin) == NULL);
+  fail_unless (gst_plugin_get_status_warnings (plugin) == NULL);
+  fail_unless (gst_plugin_get_status_errors (plugin) == NULL);
+  gst_object_unref (plugin);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_plugin_suite (void)
 {
@@ -325,6 +381,7 @@ gst_plugin_suite (void)
   tcase_add_test (tc_chain, test_find_feature);
   tcase_add_test (tc_chain, test_find_element);
   tcase_add_test (tc_chain, test_version_checks);
+  tcase_add_test (tc_chain, test_status_messages);
   //tcase_add_test (tc_chain, test_typefind);
 
   return s;
diff --git a/tests/check/gst/gstpromise.c b/tests/check/gst/gstpromise.c
index 25e6f11..24ddec8 100644
--- a/tests/check/gst/gstpromise.c
+++ b/tests/check/gst/gstpromise.c
@@ -315,7 +315,7 @@ GST_START_TEST (test_reply_reply)
   gst_promise_reply (r, s);
   fail_unless (data.result == GST_PROMISE_RESULT_REPLIED);
   fail_unless (data.change_count == 1);
-  ASSERT_CRITICAL (gst_promise_reply (r, NULL));
+  ASSERT_WARNING (gst_promise_reply (r, NULL));
   fail_unless (gst_promise_wait (r) == GST_PROMISE_RESULT_REPLIED);
   ret = gst_promise_get_reply (r);
   fail_unless (gst_structure_is_equal (ret, s));
@@ -372,7 +372,7 @@ GST_START_TEST (test_interrupt_interrupt)
   gst_promise_interrupt (r);
   fail_unless (data.result == GST_PROMISE_RESULT_INTERRUPTED);
   fail_unless (data.change_count == 1);
-  ASSERT_CRITICAL (gst_promise_interrupt (r));
+  ASSERT_WARNING (gst_promise_interrupt (r));
   fail_unless (data.result == GST_PROMISE_RESULT_INTERRUPTED);
   fail_unless (data.change_count == 1);
 
@@ -408,7 +408,7 @@ GST_START_TEST (test_expire_interrupt)
   gst_promise_expire (r);
   fail_unless (data.result == GST_PROMISE_RESULT_EXPIRED);
   fail_unless (data.change_count == 1);
-  ASSERT_CRITICAL (gst_promise_interrupt (r));
+  ASSERT_WARNING (gst_promise_interrupt (r));
   fail_unless (data.result == GST_PROMISE_RESULT_EXPIRED);
   fail_unless (data.change_count == 1);
 
@@ -426,7 +426,7 @@ GST_START_TEST (test_expire_reply)
   gst_promise_expire (r);
   fail_unless (data.result == GST_PROMISE_RESULT_EXPIRED);
   fail_unless (data.change_count == 1);
-  ASSERT_CRITICAL (gst_promise_reply (r, NULL));
+  ASSERT_WARNING (gst_promise_reply (r, NULL));
   fail_unless (data.result == GST_PROMISE_RESULT_EXPIRED);
   fail_unless (data.change_count == 1);
 
diff --git a/tests/check/gst/gststructure.c b/tests/check/gst/gststructure.c
index 21ad40a..80bc05a 100644
--- a/tests/check/gst/gststructure.c
+++ b/tests/check/gst/gststructure.c
@@ -424,7 +424,7 @@ GST_START_TEST (test_structure_new)
   GstStructure *s;
   GError *e;
   GQuark domain;
-  gboolean bool;
+  gboolean get_bool;
   gint num, den;
   GstClockTime clocktime;
   guint64 uint64;
@@ -448,8 +448,8 @@ GST_START_TEST (test_structure_new)
   fail_if (gst_structure_has_field (s, "key"));
   fail_unless_equals_int (gst_structure_n_fields (s), 4);
 
-  fail_unless (gst_structure_get_boolean (s, "bool", &bool));
-  fail_unless (bool);
+  fail_unless (gst_structure_get_boolean (s, "bool", &get_bool));
+  fail_unless (get_bool);
 
   fail_unless (gst_structure_get_fraction (s, "fraction", &num, &den));
   fail_unless_equals_int (num, 1);
@@ -792,7 +792,7 @@ GST_START_TEST (test_serialize_nested_structures)
   fail_unless (gst_structure_has_field_typed (s, "main-sub1",
           GST_TYPE_STRUCTURE));
 
-  str2 = gst_structure_serialize (s, GST_SERIALIZE_FLAG_NONE);
+  str2 = gst_structure_serialize_full (s, GST_SERIALIZE_FLAG_NONE);
   fail_unless (str2 != NULL);
 
   fail_unless_equals_string (str1, str2);
@@ -1034,6 +1034,25 @@ GST_START_TEST (test_flags)
 
 GST_END_TEST;
 
+GST_START_TEST (test_strict)
+{
+  GstStructure *s;
+
+  GstElement *bin = gst_bin_new ("mybin");
+  s = gst_structure_new ("test-struct", "obj", GST_TYPE_BIN, bin, NULL);
+  fail_unless (s);
+  fail_if (gst_structure_serialize_full (s, GST_SERIALIZE_FLAG_STRICT));
+  gst_structure_free (s);
+  gst_object_unref (bin);
+
+  s = gst_structure_new ("test-struct", "ptr", G_TYPE_POINTER, NULL, NULL);
+  fail_unless (s);
+  fail_if (gst_structure_serialize_full (s, GST_SERIALIZE_FLAG_STRICT));
+  gst_structure_free (s);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_structure_suite (void)
 {
@@ -1067,6 +1086,7 @@ gst_structure_suite (void)
   tcase_add_test (tc_chain, test_filter_and_map_in_place);
   tcase_add_test (tc_chain, test_flagset);
   tcase_add_test (tc_chain, test_flags);
+  tcase_add_test (tc_chain, test_strict);
   return s;
 }
 
diff --git a/tests/check/gst/gsturi.c b/tests/check/gst/gsturi.c
index 92511b3..47ebd36 100644
--- a/tests/check/gst/gsturi.c
+++ b/tests/check/gst/gsturi.c
@@ -1043,6 +1043,55 @@ GST_START_TEST (test_url_get_set)
       "//example.com/path/to/file/there/segment?key=value&query#fragment");
   g_free (tmp_str);
 
+  /* query string (full) */
+  tmp_str = gst_uri_get_query_string (url);
+  fail_unless_equals_string (tmp_str, "key=value&query");
+  g_free (tmp_str);
+
+  /* query string (single key, no value) */
+  tmp_list = g_list_append (NULL, g_strdup ("query"));
+  tmp_str = gst_uri_get_query_string_ordered (url, tmp_list);
+  fail_unless_equals_string (tmp_str, "query");
+  g_free (tmp_str);
+  tmp_str = gst_uri_to_string_with_keys (url, tmp_list);
+  fail_unless_equals_string (tmp_str,
+      "//example.com/path/to/file/there/segment?query#fragment");
+  g_free (tmp_str);
+  g_list_free_full (tmp_list, g_free);
+
+  /* query string (single key, with value) */
+  tmp_list = g_list_append (NULL, g_strdup ("key"));
+  tmp_str = gst_uri_get_query_string_ordered (url, tmp_list);
+  fail_unless_equals_string (tmp_str, "key=value");
+  g_free (tmp_str);
+  tmp_str = gst_uri_to_string_with_keys (url, tmp_list);
+  fail_unless_equals_string (tmp_str,
+      "//example.com/path/to/file/there/segment?key=value#fragment");
+  g_free (tmp_str);
+  g_list_free_full (tmp_list, g_free);
+
+  /* query string (key not present) */
+  tmp_list = g_list_append (NULL, g_strdup ("absent"));
+  tmp_str = gst_uri_get_query_string_ordered (url, tmp_list);
+  fail_if (tmp_str != NULL);
+  tmp_str = gst_uri_to_string_with_keys (url, tmp_list);
+  fail_unless_equals_string (tmp_str,
+      "//example.com/path/to/file/there/segment#fragment");
+  g_free (tmp_str);
+  g_list_free_full (tmp_list, g_free);
+
+  /* query string (both keys, inverse order) */
+  tmp_list = g_list_append (NULL, g_strdup ("query"));
+  tmp_list = g_list_append (tmp_list, g_strdup ("key"));
+  tmp_str = gst_uri_get_query_string_ordered (url, tmp_list);
+  fail_unless_equals_string (tmp_str, "query&key=value");
+  g_free (tmp_str);
+  tmp_str = gst_uri_to_string_with_keys (url, tmp_list);
+  fail_unless_equals_string (tmp_str,
+      "//example.com/path/to/file/there/segment?query&key=value#fragment");
+  g_free (tmp_str);
+  g_list_free_full (tmp_list, g_free);
+
   fail_unless (gst_uri_set_query_value (url, "key", NULL));
   tmp_str = gst_uri_to_string (url);
   fail_unless_equals_string (tmp_str,
diff --git a/tests/check/gst/gstutils.c b/tests/check/gst/gstutils.c
index 4ac2b67..252c3c0 100644
--- a/tests/check/gst/gstutils.c
+++ b/tests/check/gst/gstutils.c
@@ -410,11 +410,11 @@ GST_START_TEST (test_parse_bin_from_description)
     const gchar *pad_names;
   } bin_tests[] = {
     {
-    "identity", "identity0/sink,identity0/src"}, {
-    "identity ! identity ! identity", "identity1/sink,identity3/src"}, {
-    "identity ! fakesink", "identity4/sink"}, {
-    "fakesrc ! identity", "identity5/src"}, {
-    "fakesrc ! fakesink", ""}
+        "identity", "identity0/sink,identity0/src"}, {
+        "identity ! identity ! identity", "identity1/sink,identity3/src"}, {
+        "identity ! fakesink", "identity4/sink"}, {
+        "fakesrc ! identity", "identity5/src"}, {
+        "fakesrc ! fakesink", ""}
   };
   gint i;
 
@@ -1894,6 +1894,41 @@ static const GstClockTime times4[] = {
   60, 100
 };
 
+static const GstClockTime times5[] = {
+  3097492530135419, 3097492507369715,
+  3097492729101770, 3097492707369715,
+  3097493128807704, 3097493107369715,
+  3097493328386576, 3097493307369715,
+  3097493728105969, 3097493707369715,
+  3097494207585880, 3097494187369715,
+  3097495048016903, 3097495027369715,
+  3097496287625601, 3097496267369715,
+  3097497447848684, 3097497427369715,
+  3097498888090268, 3097498867369715,
+  3097499128283739, 3097499107369715,
+  3097501168351161, 3097501147369715,
+  3097502448473187, 3097502427369715,
+  3097502729226046, 3097502707369715,
+  3097503009343256, 3097502987369715,
+  3097503089910694, 3097503067369715,
+  3097503131675320, 3097503107369715,
+  3097503179587096, 3097503147369715,
+  3097504741040566, 3097504707369715,
+  3097504941855342, 3097504907369715,
+  3097506820823108, 3097506787369715,
+  3097508259718567, 3097508227369715,
+  3097508421611551, 3097508387369715,
+  3097509422069495, 3097509387369715,
+  3097511460842652, 3097511427369715,
+  3097511740612276, 3097511707369715,
+  3097513169836240, 3097513147369715,
+  3097514020101841, 3097513987369715,
+  3097515540180269, 3097515507369715,
+  3097516618966664, 3097516587369715,
+  3097518098778648, 3097518067369715,
+  3097518938513564, 3097518907369715
+};
+
 struct test_entry
 {
   gint n;
@@ -1904,15 +1939,17 @@ struct test_entry
   guint64 expect_denom;
 } times[] = {
   {
-  32, times1, 257154512360784, 120670380469753, 4052622913376634109,
-        4052799313904261962}, {
-  64, times1, 257359198881356, 120875054227405, 2011895759027682422,
-        2012014931360215503}, {
-  32, times2, 291705506022294, 162134297192792, 2319535707505209857,
-        2321009753483354451}, {
-  32, times3, 291922315691409, 162234934150296, 1370930728180888261,
-        4392719527011673456}, {
-  6, times4, 60, 100, 2, 1}
+        32, times1, 257154512360784, 120670380469753, 4052622913376634109,
+      4052799313904261962}, {
+        64, times1, 257359198881356, 120875054227405, 2011895759027682422,
+      2012014931360215503}, {
+        32, times2, 291705506022294, 162134297192792, 2319535707505209857,
+      2321009753483354451}, {
+        32, times3, 291922315691409, 162234934150296, 1370930728180888261,
+      4392719527011673456}, {
+      6, times4, 60, 100, 2, 1},
+  {G_N_ELEMENTS (times5) / 2, times5, 3097518938513564, 3097518903890035,
+      7927902279407500000, 7932215807091104881},
 };
 
 GST_START_TEST (test_regression)
@@ -1953,6 +1990,21 @@ GST_START_TEST (test_regression)
 
 GST_END_TEST;
 
+// 10 Values
+static const int ceil_log2_values[] = {
+  -1, 0, 1, 2, 2, 3, 3, 3, 3, 4
+};
+
+GST_START_TEST (test_ceil_log2)
+{
+  int i;
+  for (i = 1; i < 10; i++) {
+    fail_unless_equals_int (gst_util_ceil_log2 (i), ceil_log2_values[i]);
+  }
+}
+
+GST_END_TEST;
+
 GST_START_TEST (test_mark_as_plugin_api)
 {
   GstPluginAPIFlags api_flags;
@@ -2016,6 +2068,8 @@ gst_utils_suite (void)
 
   tcase_add_test (tc_chain, test_mark_as_plugin_api);
 
+  tcase_add_test (tc_chain, test_ceil_log2);
+
   return s;
 }
 
diff --git a/tests/check/gst/gstvalue.c b/tests/check/gst/gstvalue.c
index 3a4ccfb..b1d2548 100644
--- a/tests/check/gst/gstvalue.c
+++ b/tests/check/gst/gstvalue.c
@@ -773,6 +773,16 @@ GST_START_TEST (test_flagset)
   g_value_unset (&dest);
   g_value_unset (&value);
   g_value_unset (&value2);
+
+  /* Check that we reject flagset looking string that holds 64 bit integers. */
+  g_value_init (&value, GST_TYPE_FLAG_SET);
+  string = g_strdup ("AB24:0x0100000000000002");
+
+  fail_if (gst_value_deserialize (&value, string),
+      "matched something that isn't a flagset %s", string);
+
+  g_free (string);
+  g_value_unset (&value);
 }
 
 GST_END_TEST;
@@ -819,28 +829,28 @@ GST_START_TEST (test_deserialize_string)
     const gchar *to;
   } tests[] = {
     {
-    "\"foo\"", "foo"}, {
-    "\"foo\\%\"", "foo%"}, {
-    "\"0123456789_-+/:.\"", "0123456789_-+/:."}, {
-    "\"Hello\\ World\"", "Hello World"}, {
-    "\"Hello\\ World", "\"Hello\\ World"}, {
-    "\"\\", "\"\\"}, {
-    "\"\\0", "\"\\0"}, {
-    "\"t\\303\\274t\"", "tüt"}, {
-      /* utf8 octal sequence */
-    "", ""},                    /* empty strings */
+        "\"foo\"", "foo"}, {
+        "\"foo\\%\"", "foo%"}, {
+        "\"0123456789_-+/:.\"", "0123456789_-+/:."}, {
+        "\"Hello\\ World\"", "Hello World"}, {
+        "\"Hello\\ World", "\"Hello\\ World"}, {
+        "\"\\", "\"\\"}, {
+        "\"\\0", "\"\\0"}, {
+        "\"t\\303\\274t\"", "tüt"}, {
+          /* utf8 octal sequence */
+        "", ""},                /* empty strings */
     {
-    "\"\"", ""}, {              /* quoted empty string -> empty string */
-    "\" \"", " "}, {            /* allow spaces to be not escaped */
-    "tüüt", "tüüt"},        /* allow special chars to be not escaped */
-        /* Expected FAILURES: */
+        "\"\"", ""}, {          /* quoted empty string -> empty string */
+        "\" \"", " "}, {        /* allow spaces to be not escaped */
+        "tüüt", "tüüt"},    /* allow special chars to be not escaped */
+    /* Expected FAILURES: */
     {
-    "\"\\0\"", NULL}, {         /* unfinished escaped character */
-    "\"", NULL}, {              /* solitary quote */
-    "\"\\380\"", NULL}, {       /* invalid octal sequence */
-    "\"\\344\\204\\062\"", NULL}, {
-      /* invalid utf8: wrong end byte */
-    "\"\\344\\204\"", NULL}     /* invalid utf8: wrong number of bytes */
+        "\"\\0\"", NULL}, {     /* unfinished escaped character */
+        "\"", NULL}, {          /* solitary quote */
+        "\"\\380\"", NULL}, {   /* invalid octal sequence */
+        "\"\\344\\204\\062\"", NULL}, {
+          /* invalid utf8: wrong end byte */
+        "\"\\344\\204\"", NULL} /* invalid utf8: wrong number of bytes */
   };
   guint i;
   GValue v = { 0, };
@@ -2656,25 +2666,73 @@ GST_START_TEST (test_fraction_range)
   fail_unless (gst_value_intersect (&dest, &src, &range) == TRUE);
   fail_unless (G_VALUE_TYPE (&dest) == GST_TYPE_FRACTION);
   fail_unless (gst_value_compare (&dest, &src) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* Check that union of fraction + range = range */
+  fail_unless (gst_value_union (&dest, &src, &range) == TRUE);
+  fail_unless (G_VALUE_TYPE (&dest) == GST_TYPE_FRACTION_RANGE);
+  fail_unless (gst_value_compare (&dest, &range) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* Check that union of fraction that is not in the range fails */
+  gst_value_set_fraction (&src, 1, 20);
+  fail_unless (gst_value_union (&dest, &src, &range) == FALSE);
+  g_value_unset (&dest);
 
   /* Check that a intersection selects the overlapping range */
   gst_value_set_fraction (&start, 1, 3);
   gst_value_set_fraction (&end, 2, 3);
   gst_value_set_fraction_range (&range2, &start, &end);
-  g_value_unset (&dest);
   fail_unless (gst_value_intersect (&dest, &range, &range2) == TRUE);
   fail_unless (G_VALUE_TYPE (&dest) == GST_TYPE_FRACTION_RANGE);
+  fail_unless (gst_value_compare (&dest, &range2) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
 
+  /* Fully enclosed union: [1/4, 2/3] ∪ [1/3, 2/3] = [1/4, 2/3] */
+  fail_unless (gst_value_union (&dest, &range, &range2) == TRUE);
+  fail_unless (G_VALUE_TYPE (&dest) == GST_TYPE_FRACTION_RANGE);
+  fail_unless (gst_value_compare (&dest, &range) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+  /* Same, but swapped args */
+  fail_unless (gst_value_union (&dest, &range2, &range) == TRUE);
+  fail_unless (G_VALUE_TYPE (&dest) == GST_TYPE_FRACTION_RANGE);
+  fail_unless (gst_value_compare (&dest, &range) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+
+  /* Extend union: [1/5, 1/2] ∪ [1/3, 2/3] = [1/5, 2/3] */
+  gst_value_set_fraction (&start, 1, 5);
+  gst_value_set_fraction (&end, 1, 2);
+  gst_value_set_fraction_range (&range2, &start, &end);
+  fail_unless (gst_value_union (&dest, &range, &range2) == TRUE);
+  fail_unless (G_VALUE_TYPE (&dest) == GST_TYPE_FRACTION_RANGE);
+  gst_value_set_fraction (&start, 1, 5);
+  gst_value_set_fraction (&end, 2, 3);
   gst_value_set_fraction_range (&range2, &start, &end);
   fail_unless (gst_value_compare (&dest, &range2) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
+  /* Same, but swapped args */
+  gst_value_set_fraction (&start, 1, 5);
+  gst_value_set_fraction (&end, 1, 2);
+  gst_value_set_fraction_range (&range2, &start, &end);
+  fail_unless (gst_value_union (&dest, &range2, &range) == TRUE);
+  fail_unless (G_VALUE_TYPE (&dest) == GST_TYPE_FRACTION_RANGE);
+  gst_value_set_fraction (&start, 1, 5);
+  gst_value_set_fraction (&end, 2, 3);
+  gst_value_set_fraction_range (&range2, &start, &end);
+  fail_unless (gst_value_compare (&dest, &range2) == GST_VALUE_EQUAL);
+  g_value_unset (&dest);
 
   /* Check that non intersection ranges don't intersect */
   gst_value_set_fraction (&start, 4, 2);
   gst_value_set_fraction (&end, 5, 2);
   gst_value_set_fraction_range (&range2, &start, &end);
-  g_value_unset (&dest);
   fail_unless (gst_value_intersect (&dest, &range, &range2) == FALSE);
 
+  /* [1/4, 2/3] ∪ [4/2, 5/2] should fail */
+  fail_unless (gst_value_union (&dest, &range, &range2) == FALSE);
+  /* Same, but swapped args */
+  fail_unless (gst_value_union (&dest, &range2, &range) == FALSE);
+
   g_value_unset (&start);
   g_value_unset (&end);
   g_value_unset (&range);
@@ -2758,7 +2816,8 @@ GST_START_TEST (test_compare_caps)
 {
   GValue value = { 0 }
   , value2 = {
-  0};
+    0
+  };
 
   g_value_init (&value, GST_TYPE_CAPS);
   g_value_init (&value2, GST_TYPE_CAPS);
@@ -3232,21 +3291,22 @@ GST_START_TEST (test_stepped_int_range_ops)
     const gchar *result;
   } ranges[] = {
     {
-    "[16, 4096, 16]", "inter", "[100, 200, 10]", "160"}, {
-    "[16, 4096, 16]", "inter", "[100, 200, 100]", NULL}, {
-    "[16, 4096, 16]", "inter", "[0, 512, 256]", "[256, 512, 256]"}, {
-    "[16, 32, 16]", "union", "[32, 96, 16]", "[16, 96, 16]"}, {
-    "[16, 32, 16]", "union", "[48, 96, 16]", "[16, 96, 16]"}, {
-    "[112, 192, 16]", "union", "[48, 96, 16]", "[48, 192, 16]"}, {
-    "[16, 32, 16]", "union", "[64, 96, 16]", NULL}, {
-    "[112, 192, 16]", "union", "[48, 96, 8]", NULL}, {
-    "[10, 20, 5]", "union", "10", "[10, 20, 5]"}, {
-    "[10, 20, 5]", "union", "20", "[10, 20, 5]"}, {
-    "[10, 20, 5]", "union", "15", "[10, 20, 5]"}, {
-    "[10, 20, 5]", "union", "5", "[5, 20, 5]"}, {
-    "[10, 20, 5]", "union", "12", NULL}, {
-    "[10, 20, 5]", "union", "30", NULL}, {
-  "[10, 20, 5]", "union", "25", "[10, 25, 5]"},};
+        "[16, 4096, 16]", "inter", "[100, 200, 10]", "160"}, {
+        "[16, 4096, 16]", "inter", "[100, 200, 100]", NULL}, {
+        "[16, 4096, 16]", "inter", "[0, 512, 256]", "[256, 512, 256]"}, {
+        "[16, 32, 16]", "union", "[32, 96, 16]", "[16, 96, 16]"}, {
+        "[16, 32, 16]", "union", "[48, 96, 16]", "[16, 96, 16]"}, {
+        "[112, 192, 16]", "union", "[48, 96, 16]", "[48, 192, 16]"}, {
+        "[16, 32, 16]", "union", "[64, 96, 16]", NULL}, {
+        "[112, 192, 16]", "union", "[48, 96, 8]", NULL}, {
+        "[10, 20, 5]", "union", "10", "[10, 20, 5]"}, {
+        "[10, 20, 5]", "union", "20", "[10, 20, 5]"}, {
+        "[10, 20, 5]", "union", "15", "[10, 20, 5]"}, {
+        "[10, 20, 5]", "union", "5", "[5, 20, 5]"}, {
+        "[10, 20, 5]", "union", "12", NULL}, {
+        "[10, 20, 5]", "union", "30", NULL}, {
+        "[10, 20, 5]", "union", "25", "[10, 25, 5]"},
+  };
 
   for (n = 0; n < G_N_ELEMENTS (ranges); ++n) {
     gchar *end = NULL;
@@ -3349,8 +3409,9 @@ GST_START_TEST (test_structure_single_ops)
     gboolean can_fixate;
   } single_struct[] = {
     {
-    "foo,bar=(int)1", TRUE, TRUE}, {
-  "foo,bar=(int)[1,2]", FALSE, TRUE},};
+        "foo,bar=(int)1", TRUE, TRUE}, {
+        "foo,bar=(int)[1,2]", FALSE, TRUE},
+  };
   gint i;
 
   for (i = 0; i < G_N_ELEMENTS (single_struct); i++) {
diff --git a/tests/check/gstreamer.supp b/tests/check/gstreamer.supp
index e69c0cf..b39a40f 100644
--- a/tests/check/gstreamer.supp
+++ b/tests/check/gstreamer.supp
@@ -2574,6 +2574,17 @@
    fun:getaddrinfo
 }
 
+## Fedora 34 getaddrinfo context tls leak (probably some thread teardown race)
+## https://codebrowser.dev/glibc/glibc/resolv/resolv_context.c.html#current
+{
+   <Context Leaked>
+   Memcheck:Leak
+   ...
+   fun:maybe_init
+   ...
+   fun:getaddrinfo
+}
+
 ## Dynamic pad templates in mxfmux
 {
    <Dynamic pad templates in mxfmux>
@@ -4074,3 +4085,13 @@
   fun:generate_unwind_trace
   fun:gst_debug_get_stack_trace
 }
+
+# since glib 2.65 https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1400
+{
+  glib 2.65+: program may exit before all cancellable sources are freed
+  Memcheck:Leak
+  ...
+  fun:g_cancellable_source_new
+  ...
+  fun:g_socket_create_source
+}
diff --git a/tests/check/libs/aggregator.c b/tests/check/libs/aggregator.c
index 215b061..1f2c5b4 100644
--- a/tests/check/libs/aggregator.c
+++ b/tests/check/libs/aggregator.c
@@ -166,6 +166,24 @@ gst_test_aggregator_aggregate (GstAggregator * aggregator, gboolean timeout)
 #define gst_test_aggregator_parent_class parent_class
 G_DEFINE_TYPE (GstTestAggregator, gst_test_aggregator, GST_TYPE_AGGREGATOR);
 
+static gboolean gst_aggregator_test_slow_down_sink_query = FALSE;
+
+static gboolean
+gst_aggregator_test_slow_sink_query (GstAggregator * self,
+    GstAggregatorPad * aggpad, GstQuery * query)
+{
+  GST_DEBUG ("Handling query %" GST_PTR_FORMAT, query);
+  if (GST_QUERY_IS_SERIALIZED (query)) {
+    GstStructure *s = gst_query_writable_structure (query);
+
+    if (gst_aggregator_test_slow_down_sink_query)
+      g_usleep (G_TIME_SPAN_MILLISECOND * 10);
+    gst_structure_set (s, "some-int", G_TYPE_INT, 123, NULL);
+    GST_DEBUG ("Written to the query %" GST_PTR_FORMAT, query);
+  }
+  return GST_AGGREGATOR_CLASS (parent_class)->sink_query (self, aggpad, query);
+}
+
 static void
 gst_test_aggregator_class_init (GstTestAggregatorClass * klass)
 {
@@ -193,6 +211,7 @@ gst_test_aggregator_class_init (GstTestAggregatorClass * klass)
       GST_DEBUG_FUNCPTR (gst_test_aggregator_aggregate);
 
   base_aggregator_class->get_next_time = gst_aggregator_simple_get_next_time;
+  base_aggregator_class->sink_query = gst_aggregator_test_slow_sink_query;
 }
 
 static void
@@ -646,6 +665,60 @@ GST_START_TEST (test_aggregate_handle_queries)
 
 GST_END_TEST;
 
+GST_START_TEST (test_aggregate_queries_robustness)
+{
+  GThread *thread1;
+  ChainData data1 = { 0, };
+  TestData test = { 0, };
+  GstCaps *caps;
+  gint64 start_time;
+
+  gst_aggregator_test_slow_down_sink_query = TRUE;
+
+  _test_data_init (&test, FALSE);
+
+  caps = gst_caps_new_empty_simple ("foo/x-bar");
+  _chain_data_init (&data1, test.aggregator,
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE),
+      gst_query_new_allocation (caps, FALSE), NULL);
+  gst_caps_unref (caps);
+
+  thread1 = g_thread_try_new ("gst-check", push_data, &data1, NULL);
+  g_usleep (G_TIME_SPAN_MILLISECOND * 5);
+  for (start_time = g_get_monotonic_time ();
+      start_time + G_TIME_SPAN_SECOND > g_get_monotonic_time ();
+      g_usleep (G_TIME_SPAN_MILLISECOND)) {
+    fail_unless (gst_element_send_event (test.aggregator,
+            gst_event_new_flush_start ()));
+    fail_unless (gst_element_send_event (test.aggregator,
+            gst_event_new_flush_stop (TRUE)));
+  }
+
+  g_thread_join (thread1);
+
+  _chain_data_clear (&data1);
+  _test_data_clear (&test);
+
+  gst_aggregator_test_slow_down_sink_query = FALSE;
+}
+
+GST_END_TEST;
+
 #define NUM_BUFFERS 3
 static void
 handoff (GstElement * fakesink, GstBuffer * buf, GstPad * pad, guint * count)
@@ -1398,6 +1471,7 @@ gst_aggregator_suite (void)
   tcase_add_test (general, test_aggregate_gap);
   tcase_add_test (general, test_aggregate_handle_events);
   tcase_add_test (general, test_aggregate_handle_queries);
+  tcase_add_test (general, test_aggregate_queries_robustness);
   tcase_add_test (general, test_flushing_seek);
   tcase_add_test (general, test_infinite_seek);
   tcase_add_test (general, test_infinite_seek_50_src);
diff --git a/tests/check/libs/basesink.c b/tests/check/libs/basesink.c
index 5415d70..f2c58d7 100644
--- a/tests/check/libs/basesink.c
+++ b/tests/check/libs/basesink.c
@@ -282,6 +282,69 @@ GST_START_TEST (basesink_position_query_handles_segment_offset)
 
 GST_END_TEST;
 
+GST_START_TEST (basesink_stream_start_after_eos)
+{
+  GstElement *pipeline, *sink;
+  GstPad *pad;
+  GstEvent *ev;
+  GstSegment segment;
+  GstBuffer *buf;
+  GstFlowReturn ret;
+
+  sink = gst_element_factory_make ("fakesink", "sink");
+  g_object_set (sink, "async", FALSE, "sync", FALSE, NULL);
+  pad = gst_element_get_static_pad (sink, "sink");
+
+  pipeline = gst_pipeline_new (NULL);
+
+  gst_bin_add (GST_BIN (pipeline), sink);
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
+      GST_STATE_CHANGE_SUCCESS);
+
+  /* Normal data flow and EOS */
+  ev = gst_event_new_stream_start ("test");
+  fail_unless (gst_pad_send_event (pad, ev));
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  ev = gst_event_new_segment (&segment);
+  fail_unless (gst_pad_send_event (pad, ev));
+
+  buf = gst_buffer_new_and_alloc (4);
+  ret = gst_pad_chain (pad, buf);
+  fail_unless (ret == GST_FLOW_OK);
+
+  ev = gst_event_new_eos ();
+  fail_unless (gst_pad_send_event (pad, ev));
+
+  /* After EOS event, flow return should be EOS */
+  buf = gst_buffer_new_and_alloc (4);
+  ret = gst_pad_chain (pad, buf);
+  fail_unless (ret == GST_FLOW_EOS);
+
+  /* New data flow with new stream-start */
+  ev = gst_event_new_stream_start ("test");
+  fail_unless (gst_pad_send_event (pad, ev));
+
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  ev = gst_event_new_segment (&segment);
+  fail_unless (gst_pad_send_event (pad, ev));
+
+  buf = gst_buffer_new_and_alloc (4);
+  ret = gst_pad_chain (pad, buf);
+  fail_unless (ret == GST_FLOW_OK);
+
+  ev = gst_event_new_eos ();
+  fail_unless (gst_pad_send_event (pad, ev));
+
+  fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_NULL),
+      GST_STATE_CHANGE_SUCCESS);
+  gst_object_unref (pad);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_basesrc_suite (void)
 {
@@ -294,6 +357,7 @@ gst_basesrc_suite (void)
   tcase_add_test (tc, basesink_test_gap);
   tcase_add_test (tc, basesink_test_eos_after_playing);
   tcase_add_test (tc, basesink_position_query_handles_segment_offset);
+  tcase_add_test (tc, basesink_stream_start_after_eos);
 
   return s;
 }
diff --git a/tests/check/libs/gsttestclock.c b/tests/check/libs/gsttestclock.c
index 386a191..21cb259 100644
--- a/tests/check/libs/gsttestclock.c
+++ b/tests/check/libs/gsttestclock.c
@@ -116,7 +116,7 @@ gst_test_util_wait_for_clock_id_begin (GstTestClock * test_clock, GstClockID id,
 {
   GtuClockWaitContext *wait_ctx;
 
-  wait_ctx = g_slice_new (GtuClockWaitContext);
+  wait_ctx = g_new (GtuClockWaitContext, 1);
   wait_ctx->test_clock = gst_object_ref (test_clock);
   wait_ctx->reference = gst_clock_get_time (GST_CLOCK (wait_ctx->test_clock));
   wait_ctx->id = gst_clock_id_ref (id);
@@ -179,7 +179,7 @@ gst_test_util_wait_for_clock_id_end (GtuClockWaitContext * wait_ctx)
 
   gst_clock_id_unref (wait_ctx->id);
   gst_object_unref (wait_ctx->test_clock);
-  g_slice_free (GtuClockWaitContext, wait_ctx);
+  g_free (wait_ctx);
 
   return status;
 }
diff --git a/tests/check/libs/queuearray.c b/tests/check/libs/queuearray.c
index acd8e5c..ecce1ec 100644
--- a/tests/check/libs/queuearray.c
+++ b/tests/check/libs/queuearray.c
@@ -200,9 +200,9 @@ GST_START_TEST (test_array_grow_end)
 GST_END_TEST;
 
 static int
-compare_pointer_value (gconstpointer a, gconstpointer b)
+compare_pointer_value (guintptr a, guintptr b)
 {
-  return (int) ((guintptr) a - (guintptr) b);
+  return (int) (a - b);
 }
 
 GST_START_TEST (test_array_drop2)
@@ -232,8 +232,8 @@ GST_START_TEST (test_array_drop2)
       gpointer dropped;
 
       if (g_random_boolean () && g_random_boolean () && in_array[i]) {
-        idx = gst_queue_array_find (array, compare_pointer_value,
-            GUINT_TO_POINTER (i));
+        idx = gst_queue_array_find (array,
+            (GCompareFunc) compare_pointer_value, GUINT_TO_POINTER (i));
         dropped = gst_queue_array_drop_element (array, idx);
         fail_unless_equals_int (i, GPOINTER_TO_INT (dropped));
         in_array[i] = FALSE;
@@ -341,6 +341,273 @@ GST_START_TEST (test_array_peek_pop_tail)
 
 GST_END_TEST;
 
+GST_START_TEST (test_array_push_sorted)
+{
+  GstQueueArray *array;
+  gint i;
+
+  /* Create an array of initial size 10 */
+  array = gst_queue_array_new (10);
+
+  /* Fill it with odd values */
+  for (i = 1; i < 10; i += 2)
+    gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
+
+  /* Now try to push even values, in reverse order because why not */
+  for (i = 8; i >= 0; i -= 2)
+    gst_queue_array_push_sorted (array, GINT_TO_POINTER (i),
+        (GCompareDataFunc) compare_pointer_value, NULL);
+
+  fail_unless_equals_int (gst_queue_array_get_length (array), 10);
+
+  /* Check that the array is now 0-9 in correct order */
+  for (i = 0; i < 10; i++)
+    fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
+        i);
+
+  gst_queue_array_free (array);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_array_push_sorted_wrapped)
+{
+  GstQueueArray *array;
+  gint i;
+
+  /* Create an array of initial size 10 */
+  array = gst_queue_array_new (10);
+
+  /* Push and pull 4 values to offset head/tail.
+   * Pushing +1's the tail and popping +1's the head, so the push after this will
+   * store data at [4] internally, and further 10 pushes will cause the array
+   * to wrap around. */
+  for (i = 0; i < 4; i++) {
+    gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
+    fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
+        i);
+  }
+
+  /* Fill it with odd values */
+  for (i = 1; i < 10; i += 2)
+    gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
+
+  /* Now try to push even values, in reverse order because why not */
+  for (i = 8; i >= 0; i -= 2)
+    gst_queue_array_push_sorted (array, GINT_TO_POINTER (i),
+        (GCompareDataFunc) compare_pointer_value, NULL);
+
+  fail_unless_equals_int (gst_queue_array_get_length (array), 10);
+
+  /* Check that the array is now 0-9 in correct order */
+  for (i = 0; i < 10; i++)
+    fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
+        i);
+
+  gst_queue_array_free (array);
+}
+
+GST_END_TEST;
+
+typedef struct
+{
+  gint value;
+} CompareTestStruct;
+
+static int
+compare_struct_value (CompareTestStruct * a, CompareTestStruct * b)
+{
+  return a->value - b->value;
+}
+
+GST_START_TEST (test_array_push_sorted_struct)
+{
+  GstQueueArray *array;
+  gint i;
+
+  /* Create an array of initial size 10 */
+  array = gst_queue_array_new_for_struct (sizeof (CompareTestStruct), 10);
+
+  /* Fill it with odd values */
+  for (i = 1; i < 10; i += 2) {
+    CompareTestStruct s = { i };
+    gst_queue_array_push_tail_struct (array, &s);
+  }
+
+  /* Now try to push even values, in reverse order because why not */
+  for (i = 8; i >= 0; i -= 2) {
+    CompareTestStruct s = { i };
+    gst_queue_array_push_sorted_struct (array, &s,
+        (GCompareDataFunc) compare_struct_value, NULL);
+  }
+
+  fail_unless_equals_int (gst_queue_array_get_length (array), 10);
+
+  /* Check that the array is now 0-9 in correct order */
+  for (i = 0; i < 10; i++) {
+    CompareTestStruct *s = gst_queue_array_pop_head_struct (array);
+    fail_unless_equals_int (s->value, i);
+  }
+
+  gst_queue_array_free (array);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_array_push_sorted_struct_wrapped)
+{
+  GstQueueArray *array;
+  gint i;
+
+  /* Create an array of initial size 10 */
+  array = gst_queue_array_new_for_struct (sizeof (CompareTestStruct), 10);
+
+  /* Push and pull 4 values to offset head/tail.
+   * Pushing +1's the tail and popping +1's the head, so the push after this will
+   * store data at [4] internally, and further 10 pushes will cause the array
+   * to wrap around. */
+  for (i = 0; i < 4; i++) {
+    gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
+    fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
+        i);
+  }
+
+  /* Fill it with odd values */
+  for (i = 1; i < 10; i += 2) {
+    CompareTestStruct s = { i };
+    gst_queue_array_push_tail_struct (array, &s);
+  }
+
+  /* Now try to push even values, in reverse order because why not */
+  for (i = 8; i >= 0; i -= 2) {
+    CompareTestStruct s = { i };
+    gst_queue_array_push_sorted_struct (array, &s,
+        (GCompareDataFunc) compare_struct_value, NULL);
+  }
+
+  fail_unless_equals_int (gst_queue_array_get_length (array), 10);
+
+  /* Check that the array is now 0-9 in correct order */
+  for (i = 0; i < 10; i++) {
+    CompareTestStruct *s = gst_queue_array_pop_head_struct (array);
+    fail_unless_equals_int (s->value, i);
+  }
+
+  gst_queue_array_free (array);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_array_sort)
+{
+  GstQueueArray *array;
+  gint i;
+
+  /* Create an array of initial size 10 */
+  array = gst_queue_array_new (10);
+
+  /* Fill it with odd values */
+  for (i = 1; i < 10; i += 2)
+    gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
+
+  /* Now try to push even values, in reverse order because why not */
+  for (i = 8; i >= 0; i -= 2)
+    gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
+
+  fail_unless_equals_int (gst_queue_array_get_length (array), 10);
+
+  /* Sort the array */
+  gst_queue_array_sort (array, (GCompareDataFunc) compare_pointer_value, NULL);
+
+  fail_unless_equals_int (gst_queue_array_get_length (array), 10);
+
+  /* Check that the array is now 0-9 in correct order */
+  for (i = 0; i < 10; i++)
+    fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
+        i);
+
+  gst_queue_array_free (array);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_array_sort_struct)
+{
+  GstQueueArray *array;
+  gint i;
+
+  /* Create an array of initial size 10 */
+  array = gst_queue_array_new_for_struct (sizeof (CompareTestStruct), 10);
+
+  /* Fill it with odd values */
+  for (i = 1; i < 10; i += 2) {
+    CompareTestStruct s = { i };
+    gst_queue_array_push_tail_struct (array, &s);
+  }
+
+  /* Now try to push even values, in reverse order because why not */
+  for (i = 8; i >= 0; i -= 2) {
+    CompareTestStruct s = { i };
+    gst_queue_array_push_tail_struct (array, &s);
+  }
+
+  fail_unless_equals_int (gst_queue_array_get_length (array), 10);
+
+  /* Sort the array */
+  gst_queue_array_sort (array, (GCompareDataFunc) compare_struct_value, NULL);
+
+  /* Check that the array is now 0-9 in correct order */
+  for (i = 0; i < 10; i++) {
+    CompareTestStruct *s = gst_queue_array_pop_head_struct (array);
+    fail_unless_equals_int (s->value, i);
+  }
+
+  gst_queue_array_free (array);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_array_sort_wrapped)
+{
+  GstQueueArray *array;
+  gint i;
+
+  /* Create an array of initial size 10 */
+  array = gst_queue_array_new (10);
+
+  /* Push and pull 4 values to offset head/tail */
+  for (i = 0; i < 4; i++) {
+    gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
+    fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
+        i);
+  }
+
+  fail_unless_equals_int (gst_queue_array_get_length (array), 0);
+
+  /* Fill it with odd values */
+  for (i = 1; i < 10; i += 2)
+    gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
+
+  /* Now try to push even values, in reverse order because why not
+   * At this point the array should've wrapped around (head > tail) */
+  for (i = 8; i >= 0; i -= 2)
+    gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
+
+  fail_unless_equals_int (gst_queue_array_get_length (array), 10);
+
+  /* Sort the array */
+  gst_queue_array_sort (array, (GCompareDataFunc) compare_pointer_value, NULL);
+
+  /* Check that the array is now 0-9 in correct order */
+  for (i = 0; i < 10; i++)
+    fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
+        i);
+
+  gst_queue_array_free (array);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_queue_array_suite (void)
 {
@@ -358,6 +625,13 @@ gst_queue_array_suite (void)
   tcase_add_test (tc_chain, test_array_grow_from_prealloc1);
   tcase_add_test (tc_chain, test_array_peek_pop_tail);
   tcase_add_test (tc_chain, test_array_peek_nth);
+  tcase_add_test (tc_chain, test_array_push_sorted);
+  tcase_add_test (tc_chain, test_array_push_sorted_wrapped);
+  tcase_add_test (tc_chain, test_array_push_sorted_struct);
+  tcase_add_test (tc_chain, test_array_push_sorted_struct_wrapped);
+  tcase_add_test (tc_chain, test_array_sort);
+  tcase_add_test (tc_chain, test_array_sort_struct);
+  tcase_add_test (tc_chain, test_array_sort_wrapped);
 
   return s;
 }
diff --git a/tests/check/meson.build b/tests/check/meson.build
index 9787b0a..7d68212 100644
--- a/tests/check/meson.build
+++ b/tests/check/meson.build
@@ -120,11 +120,12 @@ if add_languages('cpp', native: false, required: false)
   ]
 endif
 
+fsmod = import('fs')
 test_defines = [
   '-UG_DISABLE_ASSERT',
   '-UG_DISABLE_CAST_CHECKS',
   '-DGST_CHECK_TEST_ENVIRONMENT_BEACON="GST_STATE_IGNORE_ELEMENTS"',
-  '-DTESTFILE="' + meson.current_source_dir() + '/meson.build"',
+  '-DTESTFILE="' + fsmod.as_posix(meson.current_source_dir()) + '/meson.build"',
   '-DGST_DISABLE_DEPRECATED',
 ]
 
@@ -135,7 +136,7 @@ if get_option('check').disabled()
   endif
 endif
 
-gst_deps = [gst_dep, gst_base_dep, gst_check_dep, gst_net_dep, gst_controller_dep, gio_dep, gmodule_dep]
+gst_deps = [gst_dep, gst_base_dep, gst_check_dep, gst_net_dep, gst_controller_dep, gio_dep, gmodule_dep, network_deps]
 
 foreach t : core_tests
   fname = t[0]
diff --git a/tests/check/pipelines/parse-launch.c b/tests/check/pipelines/parse-launch.c
index f0fd735..0d8ee62 100644
--- a/tests/check/pipelines/parse-launch.c
+++ b/tests/check/pipelines/parse-launch.c
@@ -111,6 +111,10 @@ static const gchar *test_lines[] = {
   "fakesrc : video/x-all : fakesink",   /* linking all matching pads with filter */
   "fakesrc ! video/x-all : fakesink",   /* linking all matching pads with filter */
   "fakesrc : video/x-all ! fakesink",   /* linking all matching pads with filter */
+  "fakesrc ! audio/x-opus, channel-mapping=(int)<0, 1> ! fakesink silent=true", /* array in capsfilter */
+  "fakesrc ! audio/x-opus, channel-mapping=(int)<0,\\ 1> ! fakesink silent=true",       /* array in capsfilter with escaped spaces */
+  "fakesrc ! capsfilter caps=\"audio/x-opus, channel-mapping=(int)<0, 1>\" ! fakesink silent=true",     /* array in explicit capsfilter */
+  "fakesrc ! capsfilter caps=\"audio/x-opus, channel-mapping=(int)<0,\\ 1>\" ! fakesink silent=true",   /* array in explicit capsfilter with escaped spaces */
   NULL
 };
 
diff --git a/tests/check/tools/gstinspect.c b/tests/check/tools/gstinspect.c
index 72e23a4..1ea6ee2 100644
--- a/tests/check/tools/gstinspect.c
+++ b/tests/check/tools/gstinspect.c
@@ -30,10 +30,27 @@ static int gst_inspect_main (int argc, char **argv);
 #include "../../tools/gst-inspect.c"
 #undef main
 
+// A plugin whose version does not match the gstreamer major/minor
+// see https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6191
+#define TEST_PLUGIN_VERSION "0.1.0"
+#define TEST_ELEMENT_NAME "local_test_bin"
+static gboolean
+test_plugin_init (G_GNUC_UNUSED GstPlugin * plugin)
+{
+  gst_element_register (plugin, TEST_ELEMENT_NAME, GST_RANK_NONE, GST_TYPE_BIN);
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
+    test_plugin, "Test Plugin", test_plugin_init, TEST_PLUGIN_VERSION,
+    "LGPL", "gsttestplugin", "testing");
+
 GST_START_TEST (test_exists)
 {
 #define ARGV_LEN (G_N_ELEMENTS (argv) - 1)
 
+  gst_plugin_test_plugin_register ();
+
   {
     const gchar *argv[] = { "gst-inspect-1.0", "--exists", "foo", NULL };
 
@@ -44,6 +61,16 @@ GST_START_TEST (test_exists)
 
     fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 0);
   }
+  {
+    // --exists should work even if the plugin's version does not equal
+    // the gstreamer version (i.e., the --atleast-version check is not
+    // implicitly enforced when not present).
+    const gchar *argv[] = { "gst-inspect-1.0", "--exists",
+      TEST_ELEMENT_NAME, NULL
+    };
+
+    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 0);
+  }
   {
     const gchar *argv[] = { "gst-inspect-1.0", "--exists",
       "--atleast-version=" VERSION, "bin", NULL
@@ -77,28 +104,41 @@ GST_START_TEST (test_exists)
       "--atleast-version=2.0", "bin", NULL
     };
 
-    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 1);
+    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 2);
   }
   {
     const gchar *argv[] = { "gst-inspect-1.0", "--exists",
       "--atleast-version=2.0.0", "bin", NULL
     };
 
-    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 1);
+    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 2);
   }
   {
     const gchar *argv[] = { "gst-inspect-1.0", "--exists",
       "--atleast-version=1.44", "bin", NULL
     };
 
-    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 1);
+    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 2);
   }
   {
     const gchar *argv[] = { "gst-inspect-1.0", "--exists",
       "--atleast-version=1.60.4", "bin", NULL
     };
 
-    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 1);
+    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 2);
+  }
+  {
+    // The 'atleast-version' supplied here will not match the test plugin's
+    // version, above, so the test case should return "2" because the test
+    // plugin's 0.1.0 will not meet the minimum version specified by the arg.
+    gchar *atleast = g_strdup_printf ("--atleast-version=%d.%d",
+        GST_VERSION_MAJOR, GST_VERSION_MINOR);
+    const gchar *argv[] = { "gst-inspect-1.0", "--exists",
+      atleast, TEST_ELEMENT_NAME, NULL
+    };
+
+    fail_unless_equals_int (gst_inspect_main (ARGV_LEN, (gchar **) argv), 2);
+    g_free (atleast);
   }
   {
     /* check for plugin should fail like this */
diff --git a/tests/examples/memory/my-memory.c b/tests/examples/memory/my-memory.c
index 2c1b7cb..07d61d6 100644
--- a/tests/examples/memory/my-memory.c
+++ b/tests/examples/memory/my-memory.c
@@ -36,7 +36,7 @@ _my_alloc (GstAllocator * allocator, gsize size, GstAllocationParams * params)
 
   GST_DEBUG ("alloc from allocator %p", allocator);
 
-  mem = g_slice_new (MyMemory);
+  mem = g_new (MyMemory, 1);
 
   gst_memory_init (GST_MEMORY_CAST (mem), params->flags, allocator, NULL,
       maxsize, params->align, params->prefix, size);
@@ -52,7 +52,7 @@ _my_free (GstAllocator * allocator, GstMemory * mem)
   MyMemory *mmem = (MyMemory *) mem;
 
   g_free (mmem->data);
-  g_slice_free (MyMemory, mmem);
+  g_free (mmem);
   GST_DEBUG ("%p: freed", mmem);
 }
 
@@ -101,7 +101,7 @@ _my_mem_share (MyMemory * mem, gssize offset, gsize size)
   if (size == -1)
     size = mem->mem.size - offset;
 
-  sub = g_slice_new (MyMemory);
+  sub = g_new (MyMemory, 1);
   /* the shared memory is always readonly */
   gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) |
       GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->mem.allocator, parent,
diff --git a/tests/examples/memory/my-vidmem.c b/tests/examples/memory/my-vidmem.c
index 1303a67..9f74245 100644
--- a/tests/examples/memory/my-vidmem.c
+++ b/tests/examples/memory/my-vidmem.c
@@ -47,7 +47,7 @@ _my_free (GstAllocator * allocator, GstMemory * mem)
   MyVidmem *vmem = (MyVidmem *) mem;
 
   g_free (vmem->data);
-  g_slice_free (MyVidmem, vmem);
+  g_free (vmem);
   GST_DEBUG ("%p: freed", vmem);
 }
 
@@ -96,7 +96,7 @@ _my_vidmem_share (MyVidmem * mem, gssize offset, gsize size)
   if (size == -1)
     size = mem->mem.size - offset;
 
-  sub = g_slice_new (MyVidmem);
+  sub = g_new (MyVidmem, 1);
   /* the shared memory is always readonly */
   gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) |
       GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->mem.allocator, parent,
@@ -161,7 +161,7 @@ my_vidmem_alloc (guint format, guint width, guint height)
 
   maxsize = (GST_ROUND_UP_4 (width) * height);
 
-  mem = g_slice_new (MyVidmem);
+  mem = g_new (MyVidmem, 1);
 
   gst_memory_init (GST_MEMORY_CAST (mem), 0, _my_allocator, NULL,
       maxsize, 31, 0, maxsize);
diff --git a/tests/examples/streams/testrtpool.c b/tests/examples/streams/testrtpool.c
index 0a29fda..40bdcf6 100644
--- a/tests/examples/streams/testrtpool.c
+++ b/tests/examples/streams/testrtpool.c
@@ -55,7 +55,7 @@ default_push (GstTaskPool * pool, GstTaskPoolFunction func, gpointer data,
 
   g_message ("pushing Realtime pool %p, %p", pool, func);
 
-  tid = g_slice_new0 (TestRTId);
+  tid = g_new0 (TestRTId, 1);
 
   g_message ("set policy");
   pthread_attr_init (&attr);
@@ -77,7 +77,7 @@ default_push (GstTaskPool * pool, GstTaskPoolFunction func, gpointer data,
   if (res != 0) {
     g_set_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN,
         "Error creating thread: %s", g_strerror (res));
-    g_slice_free (TestRTId, tid);
+    g_free (tid);
     tid = NULL;
   }
 
@@ -93,7 +93,7 @@ default_join (GstTaskPool * pool, gpointer id)
 
   pthread_join (tid->thread, NULL);
 
-  g_slice_free (TestRTId, tid);
+  g_free (tid);
 }
 
 static void
diff --git a/tests/meson.build b/tests/meson.build
index f3589a5..69541dc 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,7 +1,11 @@
+if get_option('tests').disabled() or static_build
+  subdir_done()
+endif
+
 if not get_option('benchmarks').disabled()
   subdir('benchmarks')
 endif
-if not get_option('tests').disabled() and gst_check_dep.found()
+if gst_check_dep.found()
   subdir('validate')
   subdir('check')
 endif
diff --git a/tests/misc/meson.build b/tests/misc/meson.build
index ca9b5fa..b679118 100644
--- a/tests/misc/meson.build
+++ b/tests/misc/meson.build
@@ -1,3 +1,4 @@
 executable('netclock-replay', 'netclock-replay.c',
+    c_args : gst_c_args,
     include_directories: libsinc,
-    dependencies : [gio_dep, gst_dep])
+    dependencies : [gio_dep, gst_dep, network_deps])
diff --git a/tests/misc/network-clock-utils.scm b/tests/misc/network-clock-utils.scm
index 1a71e32..ca4d2d5 100644
--- a/tests/misc/network-clock-utils.scm
+++ b/tests/misc/network-clock-utils.scm
@@ -1,22 +1,19 @@
 ;; GStreamer
 ;; Copyright (C) 2005 Andy Wingo <wingo at pobox.com>
-
-;; This program is free software; you can redistribute it and/or    
-;; modify it under the terms of the GNU General Public License as   
-;; published by the Free Software Foundation; either version 2 of   
-;; the License, or (at your option) any later version.              
-;;                                                                  
-;; This program is distributed in the hope that it will be useful,  
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of   
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    
-;; GNU General Public License for more details.                     
-;;                                                                  
-;; You should have received a copy of the GNU General Public License
-;; along with this program; if not, contact:
 ;;
-;; Free Software Foundation           Voice:  +1-617-542-5942
-;; 51 Franklin St, Fifth Floor        Fax:    +1-617-542-2652
-;; Boston, MA  02110-1301,  USA       gnu@gnu.org
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 2.1 of the License, or (at your option) any later version.
+;;
+;; This library is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 
 ;;; Commentary:
diff --git a/tests/misc/network-clock.scm b/tests/misc/network-clock.scm
index cd21bef..596d859 100755
--- a/tests/misc/network-clock.scm
+++ b/tests/misc/network-clock.scm
@@ -5,23 +5,20 @@ exec guile --debug -l $0 -e main -- "$@"
 
 ;; GStreamer
 ;; Copyright (C) 2005 Andy Wingo <wingo at pobox.com>
-
-;; This program is free software; you can redistribute it and/or    
-;; modify it under the terms of the GNU General Public License as   
-;; published by the Free Software Foundation; either version 2 of   
-;; the License, or (at your option) any later version.              
-;;                                                                  
-;; This program is distributed in the hope that it will be useful,  
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of   
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    
-;; GNU General Public License for more details.                     
-;;                                                                  
-;; You should have received a copy of the GNU General Public License
-;; along with this program; if not, contact:
 ;;
-;; Free Software Foundation           Voice:  +1-617-542-5942
-;; 51 Franklin St, Fifth Floor        Fax:    +1-617-542-2652
-;; Boston, MA  02110-1301,  USA       gnu@gnu.org
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 2.1 of the License, or (at your option) any later version.
+;;
+;; This library is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 
 ;;; Commentary:
diff --git a/tests/validate/gst-tester.c b/tests/validate/gst-tester.c
index 2ab4865..bebdaef 100644
--- a/tests/validate/gst-tester.c
+++ b/tests/validate/gst-tester.c
@@ -156,6 +156,7 @@ main (int argc, gchar ** argv)
   GError *err = NULL;
   gchar *filename;
   gboolean is_tty = isatty (STDOUT_FILENO);
+  GThread *thread;
 
   if (argc < 2) {
     g_print ("1..0\nnot ok # Missing <testfile> argument\n");
@@ -210,9 +211,10 @@ main (int argc, gchar ** argv)
 
 /* Running the subprocess in it own thread so that we can properly catch
  * interuptions in the main thread main loop */
-  g_thread_new ("gst-tester-thread", (GThreadFunc) _run_app, &app);
+  thread = g_thread_new ("gst-tester-thread", (GThreadFunc) _run_app, &app);
   g_main_loop_run (app.ml);
   g_main_loop_unref (app.ml);
+  g_thread_join (thread);
   g_strfreev (args);
 
   return app.exitcode;
diff --git a/tests/validate/meson.build b/tests/validate/meson.build
index 29e5264..11d8a7c 100644
--- a/tests/validate/meson.build
+++ b/tests/validate/meson.build
@@ -18,7 +18,7 @@ env.set('GST_PLUGIN_PATH_1_0', meson.global_build_root())
 env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '')
 env.set('GST_REGISTRY', '@0@/@1@.registry'.format(meson.current_build_dir(), 'validate'))
 env.set('GST_PLUGIN_SCANNER_1_0', gst_scanner_dir + '/gst-plugin-scanner')
-env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer', 'gst-validate')
+env.set('GST_PLUGIN_LOADING_WHITELIST', 'gstreamer', 'gst-validate', 'debugutilsbad')
 
 foreach t: tests
     test_dir_name = t.split('/')
diff --git a/tools/gst-inspect-1.0.1 b/tools/gst-inspect-1.0.1
index 6299f4c..97080a9 100644
--- a/tools/gst-inspect-1.0.1
+++ b/tools/gst-inspect-1.0.1
@@ -74,10 +74,6 @@ Useful in connection with external automatic plugin installation mechanisms.
 .B  \-\-gst\-mask=FLAGS
 \fIGStreamer\fP info and debugging flags to set (list with \-\-help)
 .TP 8
-.B  \-\-gst\-plugin\-spew
-\fIGStreamer\fP info flags to set
-Enable printout of errors while loading \fIGStreamer\fP plugins
-.TP 8
 .B  \-\-gst\-plugin\-path=PATH
 Add directories separated with ':' to the plugin search path
 .
diff --git a/tools/gst-inspect.c b/tools/gst-inspect.c
index 40001a1..a413340 100644
--- a/tools/gst-inspect.c
+++ b/tools/gst-inspect.c
@@ -78,6 +78,7 @@ GMainLoop *loop = NULL;
 /* Console colors */
 
 /* Escape values for colors */
+#define RED       "\033[31m"
 #define BLUE      "\033[34m"
 #define BRBLUE    "\033[94m"
 #define BRCYAN    "\033[96m"
@@ -432,6 +433,7 @@ print_object_properties_info (GObject * obj, GObjectClass * obj_class,
       (GCompareDataFunc) sort_gparamspecs, NULL);
 
   n_print ("%s%s%s:\n", HEADING_COLOR, desc, RESET_COLOR);
+  n_print ("\n");
 
   push_indent ();
 
@@ -455,7 +457,7 @@ print_object_properties_info (GObject * obj, GObjectClass * obj_class,
 
     first_flag = TRUE;
     n_print ("%sflags%s: ", PROP_ATTR_NAME_COLOR, RESET_COLOR);
-    readable = ! !(param->flags & G_PARAM_READABLE);
+    readable = !!(param->flags & G_PARAM_READABLE);
     if (readable && obj != NULL) {
       g_object_get_property (obj, param->name, &value);
     } else {
@@ -489,7 +491,10 @@ print_object_properties_info (GObject * obj, GObjectClass * obj_class,
           RESET_COLOR);
       first_flag = FALSE;
     }
-    if (param->flags & GST_PARAM_MUTABLE_PLAYING) {
+    if (param->flags & G_PARAM_CONSTRUCT_ONLY) {
+      g_print (", %s%s%s", PROP_ATTR_VALUE_COLOR,
+          _("can be set only at object construction time"), RESET_COLOR);
+    } else if (param->flags & GST_PARAM_MUTABLE_PLAYING) {
       g_print (", %s%s%s", PROP_ATTR_VALUE_COLOR,
           _("changeable in NULL, READY, PAUSED or PLAYING state"), RESET_COLOR);
     } else if (param->flags & GST_PARAM_MUTABLE_PAUSED) {
@@ -780,6 +785,8 @@ print_object_properties_info (GObject * obj, GObjectClass * obj_class,
     pop_indent_n (11);
 
     g_value_reset (&value);
+
+    n_print ("\n");
   }
   if (num_properties == 0)
     n_print ("%snone%s\n", PROP_VALUE_COLOR, RESET_COLOR);
@@ -921,17 +928,9 @@ print_clocking_info (GstElement * element)
     n_print ("%selement requires a clock%s\n", PROP_VALUE_COLOR, RESET_COLOR);
   }
 
-  if (provides_clock) {
-    GstClock *clock;
 
-    clock = gst_element_get_clock (element);
-    if (clock) {
-      n_print ("%selement provides a clock%s: %s%s%s\n", PROP_VALUE_COLOR,
-          RESET_COLOR, DATATYPE_COLOR, GST_OBJECT_NAME (clock), RESET_COLOR);
-      gst_object_unref (clock);
-    } else
-      n_print ("%selement is supposed to provide a clock but returned NULL%s\n",
-          PROP_VALUE_COLOR, RESET_COLOR);
+  if (provides_clock) {
+    n_print ("%selement provides a clock%s\n", PROP_VALUE_COLOR, RESET_COLOR);
   }
 
   pop_indent ();
@@ -999,7 +998,6 @@ print_pad_info (GstElement * element)
   pads = element->pads;
   while (pads) {
     gchar *name;
-    GstCaps *caps;
 
     pad = GST_PAD (pads->data);
     pads = g_list_next (pads);
@@ -1023,15 +1021,6 @@ print_pad_info (GstElement * element)
           PROP_VALUE_COLOR, pad->padtemplate->name_template, RESET_COLOR);
       pop_indent ();
     }
-
-    caps = gst_pad_get_current_caps (pad);
-    if (caps) {
-      n_print ("%sCapabilities:%s\n", PROP_NAME_COLOR, RESET_COLOR);
-      push_indent ();
-      print_caps (caps, "");    // FIXME
-      pop_indent ();
-      gst_caps_unref (caps);
-    }
   }
 
 done:
@@ -1065,6 +1054,21 @@ gtype_needs_ptr_marker (GType type)
   return FALSE;
 }
 
+static const gchar *
+pretty_type_name (GType type, const gchar ** p_pmark)
+{
+  if (type == G_TYPE_STRING) {
+    *p_pmark = " * ";
+    return "gchar";
+  } else if (type == G_TYPE_STRV) {
+    *p_pmark = " ** ";
+    return "gchar";
+  } else {
+    *p_pmark = gtype_needs_ptr_marker (type) ? " * " : " ";
+    return g_type_name (type);
+  }
+}
+
 static void
 print_signal_info (GstElement * element)
 {
@@ -1077,11 +1081,13 @@ print_signal_info (GstElement * element)
   GSList *found_signals, *l;
 
   for (k = 0; k < 2; k++) {
+    gboolean want_actions = (k == 1);
+
     found_signals = NULL;
 
     /* For elements that have sometimes pads, also list a few useful GstElement
      * signals. Put these first, so element-specific ones come later. */
-    if (k == 0 && has_sometimes_template (element)) {
+    if (!want_actions && has_sometimes_template (element)) {
       query = g_new0 (GSignalQuery, 1);
       g_signal_query (g_signal_lookup ("pad-added", GST_TYPE_ELEMENT), query);
       found_signals = g_slist_append (found_signals, query);
@@ -1106,8 +1112,8 @@ print_signal_info (GstElement * element)
         query = g_new0 (GSignalQuery, 1);
         g_signal_query (signals[i], query);
 
-        if ((k == 0 && !(query->signal_flags & G_SIGNAL_ACTION)) ||
-            (k == 1 && (query->signal_flags & G_SIGNAL_ACTION)))
+        if ((!want_actions && !(query->signal_flags & G_SIGNAL_ACTION)) ||
+            (want_actions && (query->signal_flags & G_SIGNAL_ACTION)))
           found_signals = g_slist_append (found_signals, query);
         else
           g_free (query);
@@ -1118,10 +1124,11 @@ print_signal_info (GstElement * element)
 
     if (found_signals) {
       n_print ("\n");
-      if (k == 0)
+      if (!want_actions)
         n_print ("%sElement Signals%s:\n", HEADING_COLOR, RESET_COLOR);
       else
         n_print ("%sElement Actions%s:\n", HEADING_COLOR, RESET_COLOR);
+      n_print ("\n");
     } else {
       continue;
     }
@@ -1129,47 +1136,65 @@ print_signal_info (GstElement * element)
     for (l = found_signals; l; l = l->next) {
       gchar *indent;
       const gchar *pmark;
+      const gchar *retval_type_name;
       int indent_len;
 
       query = (GSignalQuery *) l->data;
-      indent_len = strlen (query->signal_name) +
-          strlen (g_type_name (query->return_type)) + 24;
+      retval_type_name = pretty_type_name (query->return_type, &pmark);
 
-      if (gtype_needs_ptr_marker (query->return_type)) {
-        pmark = "* ";
-        indent_len += 2;
-      } else {
-        pmark = " ";
-      }
+      indent_len = strlen (query->signal_name) + strlen (retval_type_name);
+      indent_len += strlen (pmark) - 1;
+      indent_len += (want_actions) ? 36 : 24;
 
       indent = g_new0 (gchar, indent_len + 1);
       memset (indent, ' ', indent_len);
 
-      n_print ("  %s\"%s\"%s :  %s%s%s%suser_function%s (%s%s%s* object%s",
-          PROP_NAME_COLOR, query->signal_name, RESET_COLOR,
-          DATATYPE_COLOR, g_type_name (query->return_type), PROP_VALUE_COLOR,
-          pmark, RESET_COLOR, DATATYPE_COLOR, g_type_name (type),
-          PROP_VALUE_COLOR, RESET_COLOR);
+      if (want_actions) {
+        n_print
+            ("  %s\"%s\"%s -> %s%s%s %s:  g_signal_emit_by_name%s (%selement%s, %s\"%s\"%s",
+            PROP_NAME_COLOR, query->signal_name, RESET_COLOR, DATATYPE_COLOR,
+            retval_type_name, PROP_VALUE_COLOR, pmark,
+            RESET_COLOR, PROP_VALUE_COLOR, RESET_COLOR, PROP_NAME_COLOR,
+            query->signal_name, RESET_COLOR);
+      } else {
+        n_print ("  %s\"%s\"%s :  %s%s%s%suser_function%s (%s%s%s * object%s",
+            PROP_NAME_COLOR, query->signal_name, RESET_COLOR,
+            DATATYPE_COLOR, retval_type_name, PROP_VALUE_COLOR,
+            pmark, RESET_COLOR, DATATYPE_COLOR, g_type_name (type),
+            PROP_VALUE_COLOR, RESET_COLOR);
+      }
 
       for (j = 0; j < query->n_params; j++) {
-        const gchar *type_name, *asterisk;
+        const gchar *type_name, *asterisk, *const_prefix;
 
-        type_name = g_type_name (query->param_types[j]);
-        asterisk = gtype_needs_ptr_marker (query->param_types[j]) ? "*" : "";
+        type_name = pretty_type_name (query->param_types[j], &asterisk);
+
+        /* Add const prefix for string and string array arguments */
+        if (g_str_equal (type_name, "gchar") && strchr (asterisk, '*')) {
+          const_prefix = "const ";
+        } else {
+          const_prefix = "";
+        }
 
         g_print (",\n");
-        n_print ("%s%s%s%s%s arg%d%s", indent, DATATYPE_COLOR, type_name,
-            PROP_VALUE_COLOR, asterisk, j, RESET_COLOR);
+        n_print ("%s%s%s%s%s%sarg%d%s", indent, DATATYPE_COLOR, const_prefix,
+            type_name, PROP_VALUE_COLOR, asterisk, j, RESET_COLOR);
       }
 
-      if (k == 0) {
+      if (!want_actions) {
         g_print (",\n");
         n_print ("%s%sgpointer %suser_data%s);\n", indent, DATATYPE_COLOR,
             PROP_VALUE_COLOR, RESET_COLOR);
-      } else
-        g_print (");\n");
-
+      } else if (query->return_type == G_TYPE_NONE) {
+        n_print ("%s);\n", RESET_COLOR);
+      } else {
+        g_print (",\n");
+        n_print ("%s%s%s%s *%sp_return_value%s);\n", indent, DATATYPE_COLOR,
+            g_type_name (query->return_type), PROP_VALUE_COLOR, pmark,
+            RESET_COLOR);
+      }
       g_free (indent);
+      g_print ("\n");
     }
 
     if (found_signals) {
@@ -1297,7 +1322,8 @@ print_element_list (gboolean print_all, gchar * ftypes)
 
   orig_plugins = plugins = gst_registry_get_plugin_list (gst_registry_get ());
   if (sort_output == SORT_TYPE_NAME)
-    plugins = g_list_sort (plugins, gst_plugin_name_compare_func);
+    orig_plugins = plugins =
+        g_list_sort (plugins, gst_plugin_name_compare_func);
   while (plugins) {
     GList *features, *orig_features;
     GstPlugin *plugin;
@@ -1315,7 +1341,8 @@ print_element_list (gboolean print_all, gchar * ftypes)
         gst_registry_get_feature_list_by_plugin (gst_registry_get (),
         gst_plugin_get_name (plugin));
     if (sort_output == SORT_TYPE_NAME)
-      features = g_list_sort (features, gst_plugin_feature_name_compare_func);
+      orig_features = features =
+          g_list_sort (features, gst_plugin_feature_name_compare_func);
     while (features) {
       GstPluginFeature *feature;
 
@@ -1653,6 +1680,50 @@ print_plugin_features (GstPlugin * plugin)
   n_print ("\n");
 }
 
+static void
+print_plugin_status_message (const gchar * label, const gchar * msg,
+    const gchar * color)
+{
+  if (msg != NULL) {
+    /* TODO: do something fancy with multi-line strings to preserve indentation */
+    n_print ("%s%s:%s %s\n\n", color, label, RESET_COLOR, msg);
+  }
+}
+
+static void
+print_plugin_status (GstPlugin * plugin)
+{
+  gchar **msgs, **s;
+
+  push_indent ();
+
+  msgs = gst_plugin_get_status_infos (plugin);
+  for (s = msgs; s != NULL && *s != NULL; ++s) {
+    const gchar *info_msg = *s;
+
+    print_plugin_status_message ("Info", info_msg, GREEN);
+  }
+  g_strfreev (msgs);
+
+  msgs = gst_plugin_get_status_warnings (plugin);
+  for (s = msgs; s != NULL && *s != NULL; ++s) {
+    const gchar *warning_msg = *s;
+
+    print_plugin_status_message ("Warning", warning_msg, YELLOW);
+  }
+  g_strfreev (msgs);
+
+  msgs = gst_plugin_get_status_errors (plugin);
+  for (s = msgs; s != NULL && *s != NULL; ++s) {
+    const gchar *err_msg = *s;
+
+    print_plugin_status_message ("Error", err_msg, RED);
+  }
+  g_strfreev (msgs);
+
+  pop_indent ();
+}
+
 static int
 print_feature_info (const gchar * feature_name, gboolean print_all)
 {
@@ -1884,11 +1955,13 @@ print_plugin_automatic_install_info_codecs (GstElementFactory * factory)
 
   if (strstr (klass, "Demuxer") ||
       strstr (klass, "Decoder") ||
+      strstr (klass, "Decryptor") ||
       strstr (klass, "Depay") || strstr (klass, "Parser")) {
     type_name = "decoder";
     direction = GST_PAD_SINK;
   } else if (strstr (klass, "Muxer") ||
-      strstr (klass, "Encoder") || strstr (klass, "Pay")) {
+      strstr (klass, "Encoder") ||
+      strstr (klass, "Encryptor") || strstr (klass, "Pay")) {
     type_name = "encoder";
     direction = GST_PAD_SRC;
   } else {
@@ -2100,6 +2173,7 @@ real_main (int argc, char *argv[])
   gboolean print_aii = FALSE;
   gboolean uri_handlers = FALSE;
   gboolean check_exists = FALSE;
+  gboolean check_version = FALSE;
   gboolean color_always = FALSE;
   gchar *min_version = NULL;
   guint minver_maj = GST_VERSION_MAJOR;
@@ -2171,7 +2245,12 @@ real_main (int argc, char *argv[])
   ctx = g_option_context_new ("[ELEMENT-NAME | PLUGIN-NAME]");
   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
   g_option_context_add_group (ctx, gst_init_get_option_group ());
-  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+#if defined(G_OS_WIN32) && !defined(GST_CHECK_MAIN)
+  if (!g_option_context_parse_strv (ctx, &argv, &err))
+#else
+  if (!g_option_context_parse (ctx, &argc, &argv, &err))
+#endif
+  {
     g_printerr ("Error initializing: %s\n", err->message);
     g_clear_error (&err);
     g_option_context_free (ctx);
@@ -2182,6 +2261,10 @@ real_main (int argc, char *argv[])
   gst_init (&argc, &argv);
 #endif
 
+#if defined(G_OS_WIN32) && !defined(GST_CHECK_MAIN)
+  argc = g_strv_length (argv);
+#endif
+
   gst_tools_print_version ();
 
   if (print_all && argc > 1) {
@@ -2205,6 +2288,7 @@ real_main (int argc, char *argv[])
     }
     g_free (min_version);
     check_exists = TRUE;
+    check_version = TRUE;
   }
 
   if (check_exists) {
@@ -2216,9 +2300,13 @@ real_main (int argc, char *argv[])
         GstPluginFeature *feature;
 
         feature = gst_registry_lookup_feature (gst_registry_get (), argv[1]);
-        if (feature != NULL && gst_plugin_feature_check_version (feature,
-                minver_maj, minver_min, minver_micro)) {
-          exit_code = 0;
+        if (feature != NULL) {
+          if (check_version && !gst_plugin_feature_check_version (feature,
+                  minver_maj, minver_min, minver_micro)) {
+            exit_code = 2;
+          } else {
+            exit_code = 0;
+          }
         } else {
           exit_code = 1;
         }
@@ -2287,6 +2375,7 @@ real_main (int argc, char *argv[])
           print_plugin_automatic_install_info (plugin);
         } else {
           print_plugin_info (plugin);
+          print_plugin_status (plugin);
           print_plugin_features (plugin);
         }
       } else {
@@ -2300,6 +2389,7 @@ real_main (int argc, char *argv[])
               print_plugin_automatic_install_info (plugin);
             } else {
               print_plugin_info (plugin);
+              print_plugin_status (plugin);
               print_plugin_features (plugin);
             }
           } else {
@@ -2338,9 +2428,22 @@ done:
 int
 main (int argc, char *argv[])
 {
+  int ret;
+
+  /* gstinspect.c calls this function */
+#if defined(G_OS_WIN32) && !defined(GST_CHECK_MAIN)
+  argv = g_win32_get_command_line ();
+#endif
+
 #if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE
-  return gst_macos_main ((GstMainFunc) real_main, argc, argv, NULL);
+  ret = gst_macos_main ((GstMainFunc) real_main, argc, argv, NULL);
 #else
-  return real_main (argc, argv);
+  ret = real_main (argc, argv);
 #endif
+
+#if defined(G_OS_WIN32) && !defined(GST_CHECK_MAIN)
+  g_strfreev (argv);
+#endif
+
+  return ret;
 }
diff --git a/tools/gst-launch-1.0.1 b/tools/gst-launch-1.0.1
index 8195768..8e2dd75 100644
--- a/tools/gst-launch-1.0.1
+++ b/tools/gst-launch-1.0.1
@@ -128,10 +128,6 @@ Disables debugging.
 .B  \-\-gst\-debug\-help
 Prints a list of available debug categories and their default debugging level.
 .TP 8
-.B  \-\-gst\-plugin\-spew
-\fIGStreamer\fP info flags to set
-Enable printout of errors while loading \fIGStreamer\fP plugins
-.TP 8
 .B  \-\-gst\-plugin\-path=PATH
 Add directories separated with ':' to the plugin search path
 .TP 8
diff --git a/tools/gst-launch.c b/tools/gst-launch.c
index 7d93993..c27d5da 100644
--- a/tools/gst-launch.c
+++ b/tools/gst-launch.c
@@ -56,7 +56,7 @@
 
 extern volatile gboolean glib_on_error_halt;
 
-#ifdef G_OS_UNIX
+#if defined (G_OS_UNIX) && !defined (__APPLE__)
 static void fault_restore (void);
 static void fault_spin (void);
 #endif
@@ -80,6 +80,7 @@ static gboolean toc = FALSE;
 static gboolean messages = FALSE;
 static gboolean eos_on_shutdown = FALSE;
 static gchar **exclude_args = NULL;
+static gchar *prog_name = NULL;
 
 /* pipeline status */
 static gboolean is_live = FALSE;
@@ -95,7 +96,7 @@ static gboolean waiting_eos = FALSE;
 /* convenience macro so we don't have to litter the code with if(!quiet) */
 #define PRINT if(!quiet)gst_print
 
-#ifdef G_OS_UNIX
+#if defined (G_OS_UNIX) && !defined (__APPLE__)
 static void
 fault_handler_sighandler (int signum)
 {
@@ -161,7 +162,7 @@ fault_setup (void)
   sigaction (SIGSEGV, &action, NULL);
   sigaction (SIGQUIT, &action, NULL);
 }
-#endif /* G_OS_UNIX */
+#endif /* G_OS_UNIX && !__APPLE__ */
 
 #if 0
 typedef struct _GstIndexStats
@@ -1102,6 +1103,9 @@ real_main (int argc, char *argv[])
           N_("Do not output status information for the specified property "
               "if verbose output is enabled (can be used multiple times)"),
         N_("PROPERTY-NAME")},
+    {"prog-name", 'p', 0, G_OPTION_ARG_STRING, &prog_name,
+          N_("Set the name of the program"),
+        N_("PROGRAM-NAME")},
     {"no-fault", 'f', 0, G_OPTION_ARG_NONE, &no_fault,
         N_("Do not install a fault handler"), NULL},
     {"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown,
@@ -1159,7 +1163,12 @@ real_main (int argc, char *argv[])
   ctx = g_option_context_new ("PIPELINE-DESCRIPTION");
   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
   g_option_context_add_group (ctx, gst_init_get_option_group ());
-  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+#ifdef G_OS_WIN32
+  if (!g_option_context_parse_strv (ctx, &argv, &err))
+#else
+  if (!g_option_context_parse (ctx, &argc, &argv, &err))
+#endif
+  {
     if (err)
       gst_printerr ("Error initializing: %s\n", GST_STR_NULL (err->message));
     else
@@ -1173,9 +1182,19 @@ real_main (int argc, char *argv[])
   gst_init (&argc, &argv);
 #endif
 
+  if (prog_name) {
+    g_set_prgname (prog_name);
+  } else if (!g_get_prgname ()) {
+    g_set_prgname ((const gchar *) argv[0]);
+  }
+
+#ifdef G_OS_WIN32
+  argc = g_strv_length (argv);
+#endif
+
   gst_tools_print_version ();
 
-#ifdef G_OS_UNIX
+#if defined (G_OS_UNIX) && !defined (__APPLE__)
   if (!no_fault)
     fault_setup ();
 #endif
@@ -1368,9 +1387,21 @@ real_main (int argc, char *argv[])
 int
 main (int argc, char *argv[])
 {
+  int ret;
+
+#ifdef G_OS_WIN32
+  argv = g_win32_get_command_line ();
+#endif
+
 #if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE
-  return gst_macos_main ((GstMainFunc) real_main, argc, argv, NULL);
+  ret = gst_macos_main ((GstMainFunc) real_main, argc, argv, NULL);
 #else
-  return real_main (argc, argv);
+  ret = real_main (argc, argv);
+#endif
+
+#ifdef G_OS_WIN32
+  g_strfreev (argv);
 #endif
+
+  return ret;
 }
diff --git a/tools/gst-stats.c b/tools/gst-stats.c
index 597c1ba..ac34627 100644
--- a/tools/gst-stats.c
+++ b/tools/gst-stats.c
@@ -30,6 +30,7 @@
 #include "tools.h"
 
 /* log parser */
+static GRegex *custom_log = NULL;
 static GRegex *raw_log = NULL;
 static GRegex *ansi_log = NULL;
 
@@ -174,7 +175,7 @@ free_latency_stats (gpointer data)
   GstLatencyStats *ls = data;
 
   g_free (ls->name);
-  g_slice_free (GstLatencyStats, data);
+  g_free (data);
 }
 
 static void
@@ -191,7 +192,7 @@ free_reported_latency (gpointer data)
 static void
 free_element_stats (gpointer data)
 {
-  g_slice_free (GstElementStats, data);
+  g_free (data);
 }
 
 static inline GstElementStats *
@@ -211,7 +212,7 @@ get_pad_stats (guint ix)
 static void
 free_pad_stats (gpointer data)
 {
-  g_slice_free (GstPadStats, data);
+  g_free (data);
 }
 
 static inline GstThreadStats *
@@ -220,7 +221,7 @@ get_thread_stats (gpointer id)
   GstThreadStats *stats = g_hash_table_lookup (threads, id);
 
   if (G_UNLIKELY (!stats)) {
-    stats = g_slice_new0 (GstThreadStats);
+    stats = g_new0 (GstThreadStats, 1);
     stats->tthread = GST_CLOCK_TIME_NONE;
     g_hash_table_insert (threads, id, stats);
   }
@@ -246,7 +247,7 @@ new_pad_stats (GstStructure * s)
       "pad-direction", GST_TYPE_PAD_DIRECTION, &dir,
       "thread-id", G_TYPE_UINT64, &thread_id, NULL);
 
-  stats = g_slice_new0 (GstPadStats);
+  stats = g_new0 (GstPadStats, 1);
   if (is_ghost_pad)
     num_ghostpads++;
   num_pads++;
@@ -279,7 +280,7 @@ new_element_stats (GstStructure * s)
       "name", G_TYPE_STRING, &name,
       "type", G_TYPE_STRING, &type, "is-bin", G_TYPE_BOOLEAN, &is_bin, NULL);
 
-  stats = g_slice_new0 (GstElementStats);
+  stats = g_new0 (GstElementStats, 1);
   if (is_bin)
     num_bins++;
   num_elements++;
@@ -298,13 +299,13 @@ new_element_stats (GstStructure * s)
 static void
 free_thread_stats (gpointer data)
 {
-  g_slice_free (GstThreadStats, data);
+  g_free (data);
 }
 
 static GstPluginStats *
 new_plugin_stats (const gchar * plugin_name)
 {
-  GstPluginStats *plugin = g_slice_new (GstPluginStats);
+  GstPluginStats *plugin = g_new0 (GstPluginStats, 1);
   guint i;
 
   plugin->name = g_strdup (plugin_name);
@@ -328,7 +329,7 @@ free_plugin_stats (gpointer data)
   for (i = 0; i < N_FACTORY_TYPES; i++)
     g_ptr_array_unref (plugin->factories[i]);
 
-  g_slice_free (GstPluginStats, data);
+  g_free (data);
 }
 
 static void
@@ -909,25 +910,36 @@ process_leaf_bins (gpointer key, gpointer value, gpointer user_data)
 /* main */
 
 static gboolean
-init (void)
+init (const gchar * tracer_regexp)
 {
   /* compile the parser regexps */
+
+  if (tracer_regexp) {
+    GError *gerr = NULL;
+    custom_log = g_regex_new (tracer_regexp, 0, 0, &gerr);
+    if (!custom_log) {
+      g_warning ("Could not compile tracer regexp: %s\n", gerr->message);
+      g_clear_error (&gerr);
+      return FALSE;
+    }
+  }
+
   /* 0:00:00.004925027 31586      0x1c5c600 DEBUG           GST_REGISTRY gstregistry.c:463:gst_registry_add_plugin:<registry0> adding plugin 0x1c79160 for filename "/usr/lib/gstreamer-1.0/libgstxxx.so"
    * 0:00:02.719599000 35292 000001C031A49C60 DEBUG             GST_TRACER gsttracer.c:162:gst_tracer_register:<registry0> update existing feature 000001C02F9843C0 (latency)
    */
   raw_log = g_regex_new (
       /* 1: ts */
-      "^([0-9:.]+) +"
+      "^[0-9:.]+ +"
       /* 2: pid */
-      "([0-9]+) +"
+      "[0-9]+ +"
       /* 3: thread */
-      "(0?x?[0-9a-fA-F]+) +"
+      "0?x?[0-9a-fA-F]+ +"
       /* 4: level */
-      "([A-Z]+) +"
+      "TRACE +"
       /* 5: category */
-      "([a-zA-Z_-]+) +"
+      "[a-zA-Z_-]+ +"
       /* 6: file:line:func: */
-      "([^:]*:[0-9]+:[^:]*:) +"
+      "[^:]*:[0-9]+:[^:]*: +"
       /* 7: (obj)? log-text */
       "(.*)$", 0, 0, NULL);
   if (!raw_log) {
@@ -937,20 +949,20 @@ init (void)
 
   ansi_log = g_regex_new (
       /* 1: ts */
-      "^([0-9:.]+) +"
+      "^[0-9:.]+ +"
       /* 2: pid */
-      "\\\x1b\\[[0-9;]+m *([0-9]+)\\\x1b\\[00m +"
+      "\\\x1b\\[[0-9;]+m *[0-9]+\\\x1b\\[00m +"
       /* 3: thread */
-      "(0x[0-9a-fA-F]+) +"
+      "0x[0-9a-fA-F]+ +"
       /* 4: level */
-      "(?:\\\x1b\\[[0-9;]+m)?([A-Z]+) +\\\x1b\\[00m +"
+      "(?:\\\x1b\\[[0-9;]+m)?TRACE +\\\x1b\\[00m +"
       /* 5: category */
-      "\\\x1b\\[[0-9;]+m +([a-zA-Z_-]+) +"
+      "\\\x1b\\[[0-9;]+m +[a-zA-Z_-]+ +"
       /* 6: file:line:func: */
-      "([^:]*:[0-9]+:[^:]*:)(?:\\\x1b\\[00m)? +"
+      "[^:]*:[0-9]+:[^:]*:?:\\\x1b\\[00m? +"
       /* 7: (obj)? log-text */
       "(.*)$", 0, 0, NULL);
-  if (!raw_log) {
+  if (!ansi_log) {
     GST_WARNING ("failed to compile the 'ansi' parser");
     return FALSE;
   }
@@ -1000,6 +1012,8 @@ done (void)
     g_regex_unref (raw_log);
   if (ansi_log)
     g_regex_unref (ansi_log);
+  if (custom_log)
+    g_regex_unref (custom_log);
 }
 
 static gint
@@ -1177,9 +1191,12 @@ collect_stats (const gchar * filename)
       GRegex *parser;
       GstStructure *s;
       guint lnr = 0;
-      gchar *level, *data;
+      gchar *data;
 
-      if (strchr (line, 27)) {
+      if (custom_log) {
+        parser = custom_log;
+        GST_INFO ("format is 'custom'");
+      } else if (strchr (line, 27)) {
         parser = ansi_log;
         GST_INFO ("format is 'ansi'");
       } else {
@@ -1192,50 +1209,45 @@ collect_stats (const gchar * filename)
       while (!feof (log)) {
         if (fgets (line, 5000, log)) {
           if (g_regex_match (parser, line, 0, &match_info)) {
-            /* filter by level */
-            level = g_match_info_fetch (match_info, 4);
-            if (!strcmp (level, "TRACE")) {
-              data = g_match_info_fetch (match_info, 7);
-              if ((s = gst_structure_from_string (data, NULL))) {
-                const gchar *name = gst_structure_get_name (s);
-
-                if (!strcmp (name, "new-pad")) {
-                  new_pad_stats (s);
-                } else if (!strcmp (name, "new-element")) {
-                  new_element_stats (s);
-                } else if (!strcmp (name, "buffer")) {
-                  do_buffer_stats (s);
-                } else if (!strcmp (name, "event")) {
-                  do_event_stats (s);
-                } else if (!strcmp (name, "message")) {
-                  do_message_stats (s);
-                } else if (!strcmp (name, "query")) {
-                  do_query_stats (s);
-                } else if (!strcmp (name, "thread-rusage")) {
-                  do_thread_rusage_stats (s);
-                } else if (!strcmp (name, "proc-rusage")) {
-                  do_proc_rusage_stats (s);
-                } else if (!strcmp (name, "latency")) {
-                  do_latency_stats (s);
-                } else if (!strcmp (name, "element-latency")) {
-                  do_element_latency_stats (s);
-                } else if (!strcmp (name, "element-reported-latency")) {
-                  do_element_reported_latency (s);
-                } else if (!strcmp (name, "factory-used")) {
-                  do_factory_used (s);
-                } else {
-                  // TODO(ensonic): parse the xxx.class log lines
-                  if (!g_str_has_suffix (data, ".class")) {
-                    GST_WARNING ("unknown log entry: '%s'", data);
-                  }
-                }
-                gst_structure_free (s);
+            data = g_match_info_fetch (match_info, 1);
+            if ((s = gst_structure_from_string (data, NULL))) {
+              const gchar *name = gst_structure_get_name (s);
+
+              if (!strcmp (name, "new-pad")) {
+                new_pad_stats (s);
+              } else if (!strcmp (name, "new-element")) {
+                new_element_stats (s);
+              } else if (!strcmp (name, "buffer")) {
+                do_buffer_stats (s);
+              } else if (!strcmp (name, "event")) {
+                do_event_stats (s);
+              } else if (!strcmp (name, "message")) {
+                do_message_stats (s);
+              } else if (!strcmp (name, "query")) {
+                do_query_stats (s);
+              } else if (!strcmp (name, "thread-rusage")) {
+                do_thread_rusage_stats (s);
+              } else if (!strcmp (name, "proc-rusage")) {
+                do_proc_rusage_stats (s);
+              } else if (!strcmp (name, "latency")) {
+                do_latency_stats (s);
+              } else if (!strcmp (name, "element-latency")) {
+                do_element_latency_stats (s);
+              } else if (!strcmp (name, "element-reported-latency")) {
+                do_element_reported_latency (s);
+              } else if (!strcmp (name, "factory-used")) {
+                do_factory_used (s);
               } else {
-                GST_WARNING ("unknown log entry: '%s'", data);
+                // TODO(ensonic): parse the xxx.class log lines
+                if (!g_str_has_suffix (data, ".class")) {
+                  GST_WARNING ("unknown log entry: '%s'", data);
+                }
               }
-              g_free (data);
+              gst_structure_free (s);
+            } else {
+              GST_WARNING ("unknown log entry: '%s'", data);
             }
-            g_free (level);
+            g_free (data);
           } else {
             if (*line) {
               GST_WARNING ("foreign log entry: %s:%d:'%s'", filename, lnr,
@@ -1263,6 +1275,7 @@ gint
 main (gint argc, gchar * argv[])
 {
   gchar **filenames = NULL;
+  gchar *tracer_regexp = NULL;
   guint num;
   GError *err = NULL;
   GOptionContext *ctx;
@@ -1270,6 +1283,8 @@ main (gint argc, gchar * argv[])
     GST_TOOLS_GOPTION_VERSION,
     // TODO(ensonic): add a summary flag, if set read the whole thing, print
     // stats once, and exit
+    {"tracer-regexp", 't', 0, G_OPTION_ARG_STRING, &tracer_regexp,
+        "Custom Perl regular expression to extract tracer data", "regexp"},
     {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL}
     ,
     {NULL}
@@ -1283,15 +1298,28 @@ main (gint argc, gchar * argv[])
 
   g_set_prgname ("gst-stats-" GST_API_VERSION);
 
+#ifdef G_OS_WIN32
+  argv = g_win32_get_command_line ();
+#endif
+
   ctx = g_option_context_new ("FILE");
   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
   g_option_context_add_group (ctx, gst_init_get_option_group ());
-  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+#ifdef G_OS_WIN32
+  if (!g_option_context_parse_strv (ctx, &argv, &err))
+#else
+  if (!g_option_context_parse (ctx, &argc, &argv, &err))
+#endif
+  {
     g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
     exit (1);
   }
   g_option_context_free (ctx);
 
+#ifdef G_OS_WIN32
+  argc = g_strv_length (argv);
+#endif
+
   gst_tools_print_version ();
 
   if (filenames == NULL || *filenames == NULL) {
@@ -1305,12 +1333,17 @@ main (gint argc, gchar * argv[])
     return 1;
   }
 
-  if (init ()) {
+  if (init (tracer_regexp)) {
     collect_stats (filenames[0]);
     print_stats ();
   }
   done ();
 
   g_strfreev (filenames);
+
+#ifdef G_OS_WIN23
+  g_strfreev (argv);
+#endif
+
   return 0;
 }
diff --git a/tools/gst-typefind-1.0.1 b/tools/gst-typefind-1.0.1
index b5bf0b7..c1f6886 100644
--- a/tools/gst-typefind-1.0.1
+++ b/tools/gst-typefind-1.0.1
@@ -25,10 +25,6 @@ Print help synopsis and available FLAGS
 .B  \-\-gst\-mask=FLAGS
 \fIGStreamer\fP info and debugging flags to set (list with \-\-help)
 .TP 8
-.B  \-\-gst\-plugin\-spew
-\fIGStreamer\fP info flags to set
-Enable printout of errors while loading \fIGStreamer\fP plugins
-.TP 8
 .B  \-\-gst\-plugin\-path=PATH
 Add directories separated with ':' to the plugin search path
 .
diff --git a/tools/gst-typefind.c b/tools/gst-typefind.c
index b6b1b8a..38fc894 100644
--- a/tools/gst-typefind.c
+++ b/tools/gst-typefind.c
@@ -164,7 +164,12 @@ real_main (int argc, char *argv[])
   ctx = g_option_context_new ("FILES");
   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
   g_option_context_add_group (ctx, gst_init_get_option_group ());
-  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+#ifdef G_OS_WIN32
+  if (!g_option_context_parse_strv (ctx, &argv, &err))
+#else
+  if (!g_option_context_parse (ctx, &argc, &argv, &err))
+#endif
+  {
     g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
     g_clear_error (&err);
     g_option_context_free (ctx);
@@ -172,6 +177,10 @@ real_main (int argc, char *argv[])
   }
   g_option_context_free (ctx);
 
+#ifdef G_OS_WIN32
+  argc = g_strv_length (argv);
+#endif
+
   gst_tools_print_version ();
 
   if (filenames == NULL || *filenames == NULL) {
@@ -193,9 +202,21 @@ real_main (int argc, char *argv[])
 int
 main (int argc, char *argv[])
 {
+  int ret;
+
+#ifdef G_OS_WIN32
+  argv = g_win32_get_command_line ();
+#endif
+
 #if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE
-  return gst_macos_main ((GstMainFunc) real_main, argc, argv, NULL);
+  ret = gst_macos_main ((GstMainFunc) real_main, argc, argv, NULL);
 #else
-  return real_main (argc, argv);
+  ret = real_main (argc, argv);
 #endif
+
+#ifdef G_OS_WIN32
+  g_strfreev (argv);
+#endif
+
+  return ret;
 }
diff --git a/tools/meson.build b/tools/meson.build
index cc1ec2f..04eedfe 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -31,7 +31,7 @@ foreach tool : tools
   endif
 
   man_page = files('@0@-1.0.1'.format(tool))
-  if not get_option('tools').disabled()
+  if not get_option('tools').disabled() and not static_build
     executable(exe_name,
       src_file,
       install: true,
-- 
GitLab


From c9740460208b5ebbdf25b80e71e236c39bb3ab00 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dylan=20A=C3=AFssi?= <dylan.aissi@collabora.com>
Date: Tue, 18 Mar 2025 15:35:11 +0100
Subject: [PATCH 2/3] Release gstreamer1.0 version 1.24.12-1+apertis1
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Dylan Aïssi <dylan.aissi@collabora.com>
---
 debian/changelog | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 0adaada..3dd6794 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+gstreamer1.0 (1.24.12-1+apertis1) apertis; urgency=medium
+
+  * Sync from debian/trixie.
+  * Remaining Apertis specific changes:
+    - Drop dependency on LGPL-3 libdw, only used for better backtraces.
+
+ -- Dylan Aïssi <dylan.aissi@collabora.com>  Tue, 18 Mar 2025 15:34:16 +0100
+
 gstreamer1.0 (1.24.12-1) unstable; urgency=medium
 
   * New upstream version 1.24.12
-- 
GitLab


From f5fdfa038b53e941e3a3b74a3eeb7069945025ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dylan=20A=C3=AFssi?= <dylan.aissi@collabora.com>
Date: Tue, 18 Mar 2025 14:35:50 +0000
Subject: [PATCH 3/3] Refresh the automatically detected licensing information
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Dylan Aïssi <dylan.aissi@collabora.com>
---
 debian/apertis/copyright | 367 +++++++++++++++++++--------------------
 1 file changed, 178 insertions(+), 189 deletions(-)

diff --git a/debian/apertis/copyright b/debian/apertis/copyright
index 8941513..cb87211 100644
--- a/debian/apertis/copyright
+++ b/debian/apertis/copyright
@@ -8,25 +8,37 @@ Files: NEWS
 Copyright: no-info-found
 License: CC-BY-SA-4.0
 
-Files: data/*
+Files: data/bash-completion/*
 Copyright: 2015, Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
 License: LGPL-2+
 
-Files: debian/*
-Copyright: 2007-2010, Sebastian Dröge <sebastian.droege@collabora.co.uk>
+Files: debian/gst-codec-info.c
+Copyright: 2007-2010, 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
+License: LGPL-2+
+
+Files: docs/*
+Copyright: no-info-found
 License: LGPL-2+
 
 Files: docs/gst-plugins-doc-cache-generator.py
 Copyright: 2018, Thibault Saunier <tsaunier@igalia.com>
 License: LGPL-2.1+
 
-Files: docs/random/*
-Copyright: Ronald Bultje, 2003, <rbultje@ronald.bitfreak.net> under the
-License: GFDL
+Files: docs/gst/overview.md
+Copyright: no-info-found
+License: LGPL
 
-Files: docs/random/wtay/*
+Files: docs/index.md
 Copyright: no-info-found
-License: LGPL-2+
+License: LGPL
+
+Files: docs/plugins/gst_plugins_cache.json
+Copyright: no-info-found
+License: LGPL
+
+Files: docs/random/typefind
+Copyright: Ronald Bultje, 2003, <rbultje@ronald.bitfreak.net> under the
+License: GFDL
 
 Files: docs/random/wtay/pipelineinfo
 Copyright: name etc..
@@ -49,18 +61,25 @@ License: LGPL-2+
 
 Files: gst/gstallocator.c
  gst/gstallocator.h
+ gst/gstbufferpool.c
+ gst/gstbufferpool.h
+ gst/gstbus.c
+ gst/gstbus.h
  gst/gstmemory.c
  gst/gstmemory.h
+ gst/gstmessage.c
+ gst/gstmessage.h
+ gst/gstmeta.c
  gst/gstmeta.h
-Copyright: 2009, 2011, 2012, Wim Taymans <wim.taymans@gmail.be>
-License: LGPL-2+
-
-Files: gst/gstandroid.c
-Copyright: no-info-found
+ gst/gstsample.c
+ gst/gstsegment.c
+ gst/gstsegment.h
+ gst/gsttaskpool.c
+Copyright: 2004-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
 Files: gst/gstatomicqueue.c
-Copyright: 2009, 2010, Edward Hervey <bilboed@bilboed.com>
+Copyright: 2006, 2009, 2010, Edward Hervey <bilboed@bilboed.com>
 License: LGPL-2+
 
 Files: gst/gstatomicqueue.h
@@ -69,7 +88,7 @@ Copyright: 2011, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
 Files: gst/gstbufferlist.c
-Copyright: 2014, Tim-Philipp Müller <tim at centricular dot com>
+Copyright: 2014, Tim-Philipp Müller <tim centricular net>
  2009, Axis Communications <dev-gstreamer at axis dot com>
 License: LGPL-2+
 
@@ -77,21 +96,8 @@ Files: gst/gstbufferlist.h
 Copyright: 2009, Axis Communications <dev-gstreamer at axis dot com>
 License: LGPL-2+
 
-Files: gst/gstbufferpool.c
- gst/gstbufferpool.h
- gst/gstmeta.c
- gst/gstsample.c
- gst/gsttaskpool.c
-Copyright: 2005-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
-License: LGPL-2+
-
-Files: gst/gstbus.c
- gst/gstbus.h
- gst/gstmessage.c
- gst/gstmessage.h
- gst/gstsegment.c
- gst/gstsegment.h
-Copyright: 2004, 2005, Wim Taymans <wim@fluendo.com>
+Files: gst/gstbytearrayinterface.h
+Copyright: 2023, Netflix Inc.
 License: LGPL-2+
 
 Files: gst/gstcaps.c
@@ -109,7 +115,7 @@ License: LGPL-2+
 
 Files: gst/gstcapsfeatures.c
  gst/gstcapsfeatures.h
-Copyright: 2013, 2021, Collabora Ltd.
+Copyright: 2013, 2016, 2021, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
 License: LGPL-2+
 
 Files: gst/gstchildproxy.c
@@ -123,8 +129,8 @@ License: LGPL-2+
 
 Files: gst/gstcontext.c
  gst/gstcontext.h
-Copyright: 2013, Sebastian Dröge <slomo@circular-chaos.org>
- 2013, Collabora Ltd.
+Copyright: 2013, Sebastian Dröge <sebastian@centricular.com>
+ 2013, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
 License: LGPL-2+
 
 Files: gst/gstcontrolbinding.c
@@ -142,7 +148,7 @@ License: LGPL-2+
 
 Files: gst/gstcontrolsource.c
  gst/gstcontrolsource.h
-Copyright: 2007, Sebastian Dröge <slomo@circular-chaos.org>
+Copyright: 2007-2010, 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
 License: LGPL-2+
 
 Files: gst/gstdatetime.c
@@ -161,11 +167,15 @@ License: LGPL-2+
 
 Files: gst/gstdynamictypefactory.c
  gst/gstdynamictypefactory.h
-Copyright: 2014, 2015, Jan Schmidt <jan@centricular.com>
+ gst/gstpluginloader.c
+ gst/gstpluginloader.h
+ gst/gstquark.c
+ gst/gstquark.h
+Copyright: 2005, 2006, 2008, 2014, 2015, Jan Schmidt <jan@centricular.com>
 License: LGPL-2+
 
 Files: gst/gsterror.h
-Copyright: 2004-2006, Thomas Vander Stichele <thomas at apestaart dot org>
+Copyright: 2003-2006, Thomas Vander Stichele <thomas at apestaart dot org>
 License: LGPL-2+
 
 Files: gst/gstinfo.c
@@ -175,8 +185,8 @@ License: LGPL-2+
 
 Files: gst/gstiterator.c
  gst/gstiterator.h
-Copyright: 2011, Sebastian Dröge <sebastian.droege@collabora.co.uk>
- 2004, Wim Taymans <wim@fluendo.com>
+Copyright: 2011, Sebastian Dröge <sebastian@centricular.com>
+ 2004, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
 Files: gst/gstmacros.h
@@ -190,9 +200,8 @@ Files: gst/gstparamspecs.c
 Copyright: 2006-2017, 2020, Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
-Files: gst/gstpluginloader.c
- gst/gstpluginloader.h
-Copyright: 2008, Jan Schmidt <jan.schmidt@sun.com>
+Files: gst/gstpluginloader-win32.c
+Copyright: 2023, Seungha Yang <seungha@centricular.com>
 License: LGPL-2+
 
 Files: gst/gstpoll.c
@@ -221,11 +230,6 @@ Files: gst/gstprotection.h
 Copyright: <2015> YouView TV Ltd.
 License: LGPL-2+
 
-Files: gst/gstquark.c
- gst/gstquark.h
-Copyright: 2006, Jan Schmidt <thaytan@noraisin.net>
-License: LGPL-2+
-
 Files: gst/gstregistrybinary.c
  gst/gstregistrychunks.c
 Copyright: 2006, Josep Torra <josep@fluendo.com>
@@ -233,7 +237,7 @@ License: LGPL-2+
 
 Files: gst/gstregistrybinary.h
  gst/gstregistrychunks.h
-Copyright: 2006, Stefan Kost <ensonic@sonicpulse.de>
+Copyright: 2006, Stefan Kost <ensonic@users.sf.net>
  2006, Mathieu Garcia <matthieu@fluendo.com>
  2006, Josep Torra <josep@fluendo.com>
 License: LGPL-2+
@@ -253,7 +257,7 @@ Files: gst/gsttaglist.c
  gst/gsttypefind.h
  gst/gsttypefindfactory.c
  gst/gsttypefindfactory.h
-Copyright: 2003, Benjamin Otte <in7y118@public.uni-hamburg.de>
+Copyright: 2003-2005, Benjamin Otte <otte@gnome.org>
 License: LGPL-2+
 
 Files: gst/gsttaskpool.h
@@ -271,7 +275,7 @@ Files: gst/gsturi.c
 Copyright: 2014, David Waring, British Broadcasting Corporation
  2011, Tim-Philipp Müller <tim centricular net>
  1999, 2000, Erik Walthinsen <omega@cse.ogi.edu>
-License: BSD-3-clause and/or LGPL-2+
+License: BSD-3-clause or LGPL-2+
 
 Files: gst/printf/*
 Copyright: 1999, 2000, 2002, 2003, Free Software Foundation, Inc.
@@ -289,8 +293,8 @@ Copyright: 2006-2017, 2020, Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
 Files: libs/*
-Copyright: 2018, Pengutronix, Michael Olbrich <m.olbrich@pengutronix.de>
-License: LGPL-2+
+Copyright: 2001, 2002, Arien Malec
+License: LGPL-2.1+
 
 Files: libs/gst/base/*
 Copyright: 1999, 2000, Erik Walthinsen <omega@cse.ogi.edu>
@@ -303,19 +307,15 @@ License: LGPL-2+
 
 Files: libs/gst/base/gstadapter.c
  libs/gst/base/gstadapter.h
-Copyright: 2004, 2005, Benjamin Otte <otte@gnome.org>
+Copyright: 2003-2005, Benjamin Otte <otte@gnome.org>
 License: LGPL-2+
 
 Files: libs/gst/base/gstaggregator.c
-Copyright: 2014, Thibault Saunier <tsaunier@gnome.org>
+ libs/gst/base/gstaggregator.h
+Copyright: 2014, Thibault Saunier <tsaunier@igalia.com>
  2014, Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
 License: LGPL-2+
 
-Files: libs/gst/base/gstaggregator.h
-Copyright: 2014, Thibault Saunier <tsaunier@gnome.org>
- 2014, Mathieu Duponchelle <mathieu.duponchelle@oencreed.com>
-License: LGPL-2+
-
 Files: libs/gst/base/gstbaseparse.c
 Copyright: 2011, Hewlett-Packard Development Company, L.P.
  2008, Sebastian Dröge <sebastian.droege@collabora.co.uk>.
@@ -327,12 +327,12 @@ Copyright: 2008, Nokia Corporation.
 License: LGPL-2+
 
 Files: libs/gst/base/gstbasesink.c
-Copyright: 2005-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
+Copyright: 2004-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
 Files: libs/gst/base/gstbitreader-docs.h
  libs/gst/base/gstbytewriter-docs.h
-Copyright: 2007-2010, Sebastian Dröge <sebastian.droege@collabora.co.uk>
+Copyright: 2007-2010, 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
 License: LGPL-2+
 
 Files: libs/gst/base/gstbitreader.c
@@ -367,19 +367,20 @@ Copyright: 2009, 2014, Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
 Files: libs/gst/base/gstcollectpads.c
-Copyright: 2010, Sebastian Dröge <sebastian.droege@collabora.co.uk>
- 2008, Mark Nauwelaerts <mnauw@users.sourceforge.net>
- 2005, Wim Taymans <wim@fluendo.com>
+Copyright: 2010, Sebastian Dröge <sebastian@centricular.com>
+ 2008, Mark Nauwelaerts <mnauw users sourceforge net>
+ 2005, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
 Files: libs/gst/base/gstcollectpads.h
-Copyright: 2008, Mark Nauwelaerts <mnauw@users.sourceforge.net>
- 2005, Wim Taymans <wim@fluendo.com>
+Copyright: 2008, Mark Nauwelaerts <mnauw users sourceforge net>
+ 2005, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
 Files: libs/gst/base/gstdataqueue.c
  libs/gst/base/gstdataqueue.h
-Copyright: 2006, Edward Hervey <edward@fluendo.com>
+ libs/gst/base/gstqueuearray.h
+Copyright: 2006, 2009, 2010, Edward Hervey <bilboed@bilboed.com>
 License: LGPL-2+
 
 Files: libs/gst/base/gstflowcombiner.c
@@ -396,28 +397,25 @@ Copyright: <1999> Erik Walthinsen <omega@cse.ogi.edu>
 License: LGPL-2+
 
 Files: libs/gst/base/gstqueuearray.c
-Copyright: 2015, Tim-Philipp Müller <tim@centricular.com>
+Copyright: 2015, Tim-Philipp Müller <tim centricular net>
  2009, Edward Hervey <bilboed@bilboed.com>
 License: LGPL-2+
 
-Files: libs/gst/base/gstqueuearray.h
-Copyright: 2009, 2010, Edward Hervey <bilboed@bilboed.com>
-License: LGPL-2+
-
 Files: libs/gst/base/gsttypefindhelper.c
  libs/gst/base/gsttypefindhelper.h
 Copyright: 2006, Tim-Philipp Müller <tim centricular net>
- 2000, 2005, Wim Taymans <wim@fluendo.com>
+ 2000, 2005, Wim Taymans <wim.taymans@gmail.com>
  1999, 2000, Erik Walthinsen <omega@cse.ogi.edu>
 License: LGPL-2+
 
-Files: libs/gst/check/*
+Files: libs/gst/check/check-prelude.h
+ libs/gst/check/check.h
 Copyright: 2012, 2018, GStreamer developers
 License: LGPL-2+
 
 Files: libs/gst/check/gstbufferstraw.c
  libs/gst/check/gstbufferstraw.h
-Copyright: 2006, Andy Wingo <wingo at pobox.com>
+Copyright: 2005, 2006, Andy Wingo <wingo@pobox.com>
 License: LGPL-2+
 
 Files: libs/gst/check/gstcheck.c
@@ -436,7 +434,7 @@ Copyright: 2012, Stefan Sauer <ensonic@users.sf.net>
 License: LGPL-2+
 
 Files: libs/gst/check/gstconsistencychecker.h
-Copyright: 2009, 2010, Edward Hervey <bilboed@bilboed.com>
+Copyright: 2006, 2009, 2010, Edward Hervey <bilboed@bilboed.com>
 License: LGPL-2+
 
 Files: libs/gst/check/gstharness.c
@@ -444,6 +442,12 @@ Files: libs/gst/check/gstharness.c
 Copyright: 2012-2015, Pexip <pexip.com>
 License: LGPL-2+
 
+Files: libs/gst/check/gstharnesslink.c
+ libs/gst/check/gstharnesslink.h
+Copyright: 2023, Metrological
+ 2023, Igalia S.L.
+License: LGPL-2+
+
 Files: libs/gst/check/gsttestclock.c
  libs/gst/check/gsttestclock.h
 Copyright: 2013, Haakon Sporsheim <haakon@pexip.com>
@@ -452,12 +456,8 @@ Copyright: 2013, Haakon Sporsheim <haakon@pexip.com>
  2008, Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
 License: LGPL-2+
 
-Files: libs/gst/check/libcheck/*
-Copyright: 2001, 2002, Arien Malec
-License: LGPL-2.1+
-
 Files: libs/gst/controller/*
-Copyright: 2007-2010, Sebastian Dröge <sebastian.droege@collabora.co.uk>
+Copyright: 2007-2010, 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
 License: LGPL-2+
 
 Files: libs/gst/controller/controller-prelude.h
@@ -472,32 +472,29 @@ Files: libs/gst/controller/gstargbcontrolbinding.c
 Copyright: 2011, 2013, 2014, 2016, Stefan Sauer <ensonic@users.sf.net>
 License: LGPL-2+
 
-Files: libs/gst/controller/gstinterpolationcontrolsource.h
- libs/gst/controller/gstlfocontrolsource.h
- libs/gst/controller/gsttimedvaluecontrolsource.h
- libs/gst/controller/gsttriggercontrolsource.h
-Copyright: 2007, Sebastian Dröge <slomo@circular-chaos.org>
-License: LGPL-2+
-
 Files: libs/gst/controller/gstproxycontrolbinding.c
  libs/gst/controller/gstproxycontrolbinding.h
 Copyright: 2016, 2017, Matthew Waters <matthew@centricular.com>
 License: LGPL-2+
 
+Files: libs/gst/helpers/*
+Copyright: 2015-2023, Sebastian Dröge <sebastian@centricular.com>
+License: MPL-2.0
+
 Files: libs/gst/helpers/gst-completion-helper.c
 Copyright: 2015, Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
 License: LGPL-2+
 
 Files: libs/gst/helpers/gst-plugin-scanner.c
-Copyright: 2008, Jan Schmidt <jan.schmidt@sun.com>
+Copyright: 2005, 2006, 2008, 2014, 2015, Jan Schmidt <jan@centricular.com>
 License: LGPL-2+
 
-Files: libs/gst/helpers/gst-ptp-helper.c
-Copyright: 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
+Files: libs/gst/helpers/gst_gdb.py
+Copyright: 2018, Pengutronix, Michael Olbrich <m.olbrich@pengutronix.de>
 License: LGPL-2+
 
 Files: libs/gst/net/*
-Copyright: 2005, Andy Wingo <wingo@pobox.com>
+Copyright: 2005, 2006, Andy Wingo <wingo@pobox.com>
 License: LGPL-2+
 
 Files: libs/gst/net/gstnetaddressmeta.c
@@ -507,12 +504,12 @@ License: LGPL-2+
 
 Files: libs/gst/net/gstnetclientclock.c
 Copyright: 2015, Sebastian Dröge <sebastian@centricular.com>
- 2012, Collabora Ltd. <tim.muller@collabora.co.uk>
+ 2012, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
  1999, 2000, Erik Walthinsen <omega@cse.ogi.edu>
 License: LGPL-2+
 
 Files: libs/gst/net/gstnetclientclock.h
-Copyright: 2012, Collabora Ltd. <tim.muller@collabora.co.uk>
+Copyright: 2012, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
  1999, 2000, Erik Walthinsen <omega@cse.ogi.edu>
 License: LGPL-2+
 
@@ -522,13 +519,13 @@ Copyright: <2014> William Manley <will@williammanley.net>
 License: LGPL-2+
 
 Files: libs/gst/net/gstnettimepacket.c
-Copyright: 2012, Collabora Ltd. <tim.muller@collabora.co.uk>
+Copyright: 2012, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
  2010, Tim-Philipp Müller <tim centricular net>
  2005, Andy Wingo <wingo@pobox.com>
 License: LGPL-2+
 
 Files: libs/gst/net/gstnettimeprovider.h
-Copyright: 2012, Collabora Ltd. <tim.muller@collabora.co.uk>
+Copyright: 2012, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
  2005, Andy Wingo <wingo@pobox.com>
 License: LGPL-2+
 
@@ -540,7 +537,7 @@ License: LGPL-2+
 
 Files: libs/gst/net/gstntppacket.c
 Copyright: 2015, Sebastian Dröge <sebastian@centricular.com>
- 2012, Collabora Ltd. <tim.muller@collabora.co.uk>
+ 2012, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
  2010, Tim-Philipp Müller <tim centricular net>
  2005, Andy Wingo <wingo@pobox.com>
 License: LGPL-2+
@@ -552,7 +549,7 @@ License: LGPL-2+
 
 Files: libs/gst/net/gstptpclock.c
  libs/gst/net/gstptpclock.h
-Copyright: 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
+Copyright: 2007-2010, 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
 License: LGPL-2+
 
 Files: libs/gst/net/net-prelude.h
@@ -572,7 +569,7 @@ License: LGPL-2+
 
 Files: plugins/elements/gstconcat.c
  plugins/elements/gstconcat.h
-Copyright: 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
+Copyright: 2007-2010, 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
 License: LGPL-2+
 
 Files: plugins/elements/gstcoreelementselements.h
@@ -581,35 +578,36 @@ License: LGPL-2+
 
 Files: plugins/elements/gstdataurisrc.c
  plugins/elements/gstdataurisrc.h
-Copyright: 2009, Sebastian Dröge <sebastian.droege@collabora.co.uk>
+Copyright: 2009, Sebastian Dröge <sebastian@centricular.com>
  2009, Igalia S.L
 License: LGPL-2+
 
 Files: plugins/elements/gstdownloadbuffer.c
  plugins/elements/gstdownloadbuffer.h
-Copyright: 2005-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
+ plugins/elements/gstsparsefile.c
+ plugins/elements/gstsparsefile.h
+Copyright: 2004-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
 Files: plugins/elements/gstelements_private.c
-Copyright: 2014, Vincent Penquerch <vincent@collabora.co.uk>
- 2014, Tim-Philipp Müller <tim@centricular.com>
- 2011, Tim-Philipp Müller <tim.muller@collabora.co.uk>
+Copyright: 2014, Vincent Penquerc'h <vincent@collabora.co.uk>
  2011, David Schleef <ds@schleef.org>
+ 2011, 2014, Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
 Files: plugins/elements/gstfunnel.c
  plugins/elements/gstfunnel.h
 Copyright: 2007, Nokia Corp.
- 2007, Collabora Ltd.
+ 2007, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
 License: LGPL-2.1+
 
 Files: plugins/elements/gstinputselector.c
-Copyright: 2011, Sebastian Dröge <sebastian.droege@collabora.co.uk>
+Copyright: 2011, Sebastian Dröge <sebastian@centricular.com>
  2008, Nokia Corporation. (contact <stefan.kost@nokia.com>)
  2007, Wim Taymans <wim.taymans@gmail.com>
  2007, Andy Wingo <wingo@pobox.com>
  2005, Ronald S. Bultje <rbultje@ronald.bitfreak.net>
- 2005, Jan Schmidt <thaytan@mad.scientist.com>
+ 2005, Jan Schmidt <jan@centricular.com>
  2003, Julien Moutte <julien@moutte.net>
 License: LGPL-2+
 
@@ -620,14 +618,14 @@ Copyright: 2008, Nokia Corporation. (contact <stefan.kost@nokia.com>)
 License: LGPL-2+
 
 Files: plugins/elements/gstmultiqueue.c
-Copyright: 2011, Sebastian Dröge <sebastian.droege@collabora.co.uk>
- 2007, Wim Taymans <wim@fluendo.com>
- 2007, Jan Schmidt <jan@fluendo.com>
- 2006, Edward Hervey <edward@fluendo.com>
+Copyright: 2011, Sebastian Dröge <sebastian@centricular.com>
+ 2007, Wim Taymans <wim.taymans@gmail.com>
+ 2007, Jan Schmidt <jan@centricular.com>
+ 2006, Edward Hervey <bilboed@bilboed.com>
 License: LGPL-2+
 
 Files: plugins/elements/gstmultiqueue.h
-Copyright: 2006, Edward Hervey <edward@fluendo.com>
+Copyright: 2006, 2009, 2010, Edward Hervey <bilboed@bilboed.com>
 License: LGPL-2+
 
 Files: plugins/elements/gstoutputselector.c
@@ -635,11 +633,6 @@ Files: plugins/elements/gstoutputselector.c
 Copyright: 2008, Nokia Corporation. (contact <stefan.kost@nokia.com>)
 License: LGPL-2+
 
-Files: plugins/elements/gstsparsefile.c
- plugins/elements/gstsparsefile.h
-Copyright: 2014, Wim Taymans <wtaymans@redhat.com>
-License: LGPL-2+
-
 Files: plugins/elements/gststreamiddemux.c
  plugins/elements/gststreamiddemux.h
 Copyright: 2013, LGE Corporation.
@@ -647,7 +640,7 @@ License: LGPL-2.1+
 
 Files: plugins/elements/gsttypefindelement.c
  plugins/elements/gsttypefindelement.h
-Copyright: 2003, Benjamin Otte <in7y118@public.uni-hamburg.de>
+Copyright: 2003-2005, Benjamin Otte <otte@gnome.org>
 License: LGPL-2+
 
 Files: plugins/elements/gstvalve.c
@@ -662,7 +655,8 @@ License: LGPL-2+
 
 Files: plugins/tracers/gstfactories.c
  plugins/tracers/gstfactories.h
-Copyright: 2013, 2021, Collabora Ltd.
+ plugins/tracers/gstleaks.h
+Copyright: 2013, 2016, 2021, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
 License: LGPL-2+
 
 Files: plugins/tracers/gstleaks.c
@@ -670,28 +664,22 @@ Copyright: 2019, Nirbheek Chauhan <nirbheek@centricular.com>
  2016, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
 License: LGPL-2+
 
-Files: plugins/tracers/gstleaks.h
-Copyright: 2016, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
-License: LGPL-2+
-
-Files: scripts/*
-Copyright: 2015-2017, 2020, Tim-Philipp Müller <tim centricular com>
-License: LGPL-2+
-
 Files: scripts/dist-translations.py
+ scripts/extract-release-date-from-doap-file.py
 Copyright: 2006-2017, 2020, Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
-Files: tests/*
-Copyright: 2005, Andy Wingo
+Files: tests/benchmarks/*
+Copyright: 2005, Andy Wingo <wingo@pobox.com>
 License: LGPL-2.1+
 
 Files: tests/benchmarks/caps.c
-Copyright: 2005, Andy Wingo <wingo@pobox.com>
+Copyright: 2005, 2006, Andy Wingo <wingo@pobox.com>
 License: LGPL-2+
 
 Files: tests/benchmarks/capsnego.c
  tests/benchmarks/controller.c
+ tests/benchmarks/init.c
 Copyright: 2005-2007, 2009-2011, Stefan Kost <ensonic@users.sf.net>
 License: LGPL-2+
 
@@ -717,19 +705,15 @@ Files: tests/benchmarks/gstpoolstress.c
 Copyright: <2013> Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
-Files: tests/benchmarks/init.c
-Copyright: 2006, Stefan Kost <stefan.kost@nokia.com>
-License: LGPL-2+
-
 Files: tests/benchmarks/mass-elements.c
-Copyright: 2004, 2005, Benjamin Otte <otte@gnome.org>
+Copyright: 2003-2005, Benjamin Otte <otte@gnome.org>
 License: LGPL-2+
 
 Files: tests/benchmarks/tracerserialize.c
 Copyright: 2011, 2013, 2014, 2016, Stefan Sauer <ensonic@users.sf.net>
 License: LGPL-2+
 
-Files: tests/check/*
+Files: tests/check/elements/*
 Copyright: 2006-2017, 2020, Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
@@ -762,7 +746,7 @@ Copyright: 2007, Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
 Files: tests/check/elements/filesrc.c
-Copyright: 2004-2006, Thomas Vander Stichele <thomas at apestaart dot org>
+Copyright: 2003-2006, Thomas Vander Stichele <thomas at apestaart dot org>
 License: LGPL-2+
 
 Files: tests/check/elements/funnel.c
@@ -798,7 +782,7 @@ License: LGPL-2+
 
 Files: tests/check/elements/valve.c
 Copyright: 2009, Nokia Corp.
- 2009, Collabora Ltd.
+ 2009, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
 License: LGPL-2+
 
 Files: tests/check/generic/*
@@ -819,7 +803,7 @@ License: LGPL-2+
 Files: tests/check/gst/gstabi.c
  tests/check/gst/gstghostpad.c
  tests/check/gst/gstsystemclock.c
-Copyright: 2004, 2005, Wim Taymans <wim@fluendo.com>
+Copyright: 2004-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
 Files: tests/check/gst/gstatomicqueue.c
@@ -827,7 +811,7 @@ Copyright: <2011> Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
 Files: tests/check/gst/gstbin.c
-Copyright: 2005, Wim Taymans <wim@fluendo.com>
+Copyright: 2005, Wim Taymans <wim.taymans@gmail.com>
  2005, Thomas Vander Stichele <thomas at apestaart dot org>
 License: LGPL-2+
 
@@ -851,7 +835,7 @@ Copyright: <2005> Thomas Vander Stichele <thomas at apestaart dot org>
 License: LGPL-2+
 
 Files: tests/check/gst/gstcapsfeatures.c
-Copyright: 2013, 2021, Collabora Ltd.
+Copyright: 2013, 2016, 2021, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
 License: LGPL-2+
 
 Files: tests/check/gst/gstchildproxy.c
@@ -860,12 +844,12 @@ Copyright: 2005-2007, 2009-2011, Stefan Kost <ensonic@users.sf.net>
 License: LGPL-2+
 
 Files: tests/check/gst/gstclock.c
-Copyright: 2010, Alessandro Decina <alessandro.decina@collabora.co.uk>
+Copyright: 2006, 2010, Alessandro Decina <alessandro.decina@collabora.co.uk>
 License: LGPL-2+
 
 Files: tests/check/gst/gstcontext.c
-Copyright: 2013, Sebastian Dröge <slomo@circular-chaos.org>
- 2013, Collabora Ltd.
+Copyright: 2013, Sebastian Dröge <sebastian@centricular.com>
+ 2013, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
 License: LGPL-2+
 
 Files: tests/check/gst/gstcontroller.c
@@ -875,8 +859,14 @@ License: LGPL-2+
 
 Files: tests/check/gst/gstcpp.cc
  tests/check/gst/gstdeinit.c
+ tests/check/gst/gstindex.c
+ tests/check/gst/gstinfo.c
+ tests/check/gst/gstparamspecs.c
  tests/check/gst/gstprintf.c
-Copyright: 2015-2017, 2020, Tim-Philipp Müller <tim centricular com>
+ tests/check/gst/gstregistry.c
+ tests/check/gst/gsttagsetter.c
+ tests/check/gst/gsturi.c
+Copyright: 2006-2017, 2020, Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
 Files: tests/check/gst/gstdatetime.c
@@ -891,16 +881,16 @@ License: LGPL-2+
 Files: tests/check/gst/gstelement.c
  tests/check/gst/gstpipeline.c
  tests/check/gst/gsttask.c
-Copyright: 2004-2006, Thomas Vander Stichele <thomas at apestaart dot org>
+Copyright: 2003-2006, Thomas Vander Stichele <thomas at apestaart dot org>
 License: LGPL-2+
 
 Files: tests/check/gst/gstevent.c
  tests/check/gst/gstsegment.c
-Copyright: 2005, Jan Schmidt <thaytan@mad.scientist.com>
+Copyright: 2005, 2006, 2008, 2014, 2015, Jan Schmidt <jan@centricular.com>
 License: LGPL-2+
 
 Files: tests/check/gst/gstiterator.c
-Copyright: 2005, Andy Wingo <wingo@pobox.com>
+Copyright: 2005, 2006, Andy Wingo <wingo@pobox.com>
 License: LGPL-2+
 
 Files: tests/check/gst/gstmemory.c
@@ -954,7 +944,7 @@ Copyright: <2015> Edward Hervey <edward@centricular.com>
 License: LGPL-2+
 
 Files: tests/check/gst/gsttag.c
-Copyright: 2003, Benjamin Otte <in7y118@public.uni-hamburg.de>
+Copyright: 2003-2005, Benjamin Otte <otte@gnome.org>
 License: LGPL-2+
 
 Files: tests/check/gst/gsttoc.c
@@ -972,18 +962,14 @@ Copyright: <2005> Thomas Vander Stichele <thomas at apestaart dot org>
  <2004> David Schleef <david at schleef dot org>
 License: LGPL-2+
 
-Files: tests/check/libs/*
-Copyright: 2005-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
-License: LGPL-2+
-
 Files: tests/check/libs/adapter.c
 Copyright: <2005> Wim Taymans <wim at fluendo dot com>
 License: LGPL-2+
 
 Files: tests/check/libs/aggregator.c
-Copyright: 2014, Thibault Saunier <tsaunier@opencreed.com>
- 2014, Mathieu Duponchelle <mathieu.duponchelle@oencreed.com>
- 2006, Alessandro Decina <alessandro.d@gmail.com>
+Copyright: 2014, Thibault Saunier <tsaunier@igalia.com>
+ 2014, Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
+ 2006, Alessandro Decina <alessandro.decina@collabora.co.uk>
 License: LGPL-2+
 
 Files: tests/check/libs/baseparse.c
@@ -992,21 +978,19 @@ Copyright: 2014, Samsung Electronics.
 License: LGPL-2+
 
 Files: tests/check/libs/basesink.c
-Copyright: 2010, Alessandro Decina <alessandro.decina@collabora.co.uk>
+ tests/check/libs/collectpads.c
+Copyright: 2006, 2010, Alessandro Decina <alessandro.decina@collabora.co.uk>
 License: LGPL-2+
 
 Files: tests/check/libs/basesrc.c
+ tests/check/libs/bitreader-noinline.c
+ tests/check/libs/bytereader-noinline.c
+ tests/check/libs/bytewriter-noinline.c
  tests/check/libs/gstlibscpp.cc
  tests/check/libs/typefindhelper.c
 Copyright: 2006-2017, 2020, Tim-Philipp Müller <tim centricular net>
 License: LGPL-2+
 
-Files: tests/check/libs/bitreader-noinline.c
- tests/check/libs/bytereader-noinline.c
- tests/check/libs/bytewriter-noinline.c
-Copyright: 2013, Tim-Philipp Müller <tim@centricular.com>
-License: LGPL-2+
-
 Files: tests/check/libs/bitreader.c
  tests/check/libs/bytereader.c
 Copyright: <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
@@ -1021,10 +1005,6 @@ Files: tests/check/libs/bytewriter.c
 Copyright: <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
 License: LGPL-2+
 
-Files: tests/check/libs/collectpads.c
-Copyright: 2006, Alessandro Decina <alessandro.d@gmail.com>
-License: LGPL-2+
-
 Files: tests/check/libs/controller.c
 Copyright: <2006-2007> Sebastian Dröge <slomo@circular-chaos.org>
  <2005> Stefan Kost <ensonic at users dot sf dot net>
@@ -1036,7 +1016,7 @@ License: LGPL-2+
 
 Files: tests/check/libs/gstnetclientclock.c
  tests/check/libs/gstnettimeprovider.c
-Copyright: 2005, Andy Wingo <wingo@pobox.com>
+Copyright: 2005, 2006, Andy Wingo <wingo@pobox.com>
 License: LGPL-2+
 
 Files: tests/check/libs/gsttestclock.c
@@ -1044,16 +1024,20 @@ Copyright: 2012, Sebastian Rasmussen <sebastian.rasmussen@axis.com>
  2008, Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
 License: LGPL-2+
 
-Files: tests/check/libs/queuearray.c
-Copyright: <2009> Edward Hervey <bilboed@bilboed.com>
+Files: tests/check/libs/libsabi.c
+ tests/check/libs/sparsefile.c
+ tests/check/libs/test_transform.c
+ tests/check/libs/transform1.c
+ tests/check/libs/transform2.c
+Copyright: 2004-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
-Files: tests/check/libs/sparsefile.c
-Copyright: 2014, Wim Taymans <wtaymans@redhat.com>
+Files: tests/check/libs/queuearray.c
+Copyright: <2009> Edward Hervey <bilboed@bilboed.com>
 License: LGPL-2+
 
 Files: tests/check/pipelines/*
-Copyright: 2005, Andy Wingo <wingo@pobox.com>
+Copyright: 2005, 2006, Andy Wingo <wingo@pobox.com>
 License: LGPL-2+
 
 Files: tests/check/pipelines/cleanup.c
@@ -1076,50 +1060,55 @@ License: LGPL-2+
 
 Files: tests/check/pipelines/seek.c
 Copyright: Julien Isorce <jisorce@oblong.com>
- 2012, Collabora Ltd.
+ 2012, Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
 License: LGPL-2+
 
-Files: tests/examples/*
+Files: tests/check/tools/*
+Copyright: 2006-2017, 2020, Tim-Philipp Müller <tim centricular net>
+License: LGPL-2+
+
+Files: tests/examples/controller/controller-graph.c
 Copyright: <2015> Stefan Sauer <ensonic@users.sf.net>
 License: LGPL-2+
 
 Files: tests/examples/memory/*
-Copyright: 2009, 2011, 2012, Wim Taymans <wim.taymans@gmail.be>
+Copyright: 2004-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
-Files: tests/examples/netclock/*
-Copyright: 2014, 2015, Jan Schmidt <jan@centricular.com>
+Files: tests/examples/netclock/netclock-server.c
+Copyright: 2005, 2006, 2008, 2014, 2015, Jan Schmidt <jan@centricular.com>
 License: LGPL-2+
 
-Files: tests/examples/ptp/*
-Copyright: 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
+Files: tests/examples/ptp/ptp-print-times.c
+Copyright: 2007-2010, 2014, 2015, Sebastian Dröge <sebastian@centricular.com>
 License: LGPL-2+
 
-Files: tests/examples/streams/*
-Copyright: 2005-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
+Files: tests/examples/streams/testrtpool.c
+Copyright: 2004-2012, 2014, Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
 Files: tests/examples/streams/testrtpool.h
 Copyright: <2009> Wim Taymans <wim.taymans@gmail.com>
 License: LGPL-2+
 
-Files: tests/misc/*
+Files: tests/misc/netclock-replay.c
 Copyright: 2016, Centricular Ltd.
 License: LGPL-2+
 
 Files: tests/misc/network-clock-utils.scm
-Copyright: 2005, Andy Wingo <wingo at pobox.com>
-License: GPL-2+
+Copyright: 2005, Andy Wingo <wingo@pobox.com>
+License: LGPL-2.1+
 
 Files: tests/misc/network-clock.scm
-Copyright: 2005, Andy Wingo <wingo at pobox.com>
+Copyright: 2005, Andy Wingo <wingo@pobox.com>
 License: GPL-2
 
-Files: tests/validate/*
+Files: tests/validate/gst-tester.c
 Copyright: 2020, Igalia, S.L.
 License: LGPL-2+
 
-Files: tools/*
+Files: tools/gst-inspect.c
+ tools/gst-launch.c
 Copyright: 1999, 2000, Erik Walthinsen <omega@cse.ogi.edu>
 License: LGPL-2+
 
@@ -1128,9 +1117,9 @@ Copyright: 2011, 2013, 2014, 2016, Stefan Sauer <ensonic@users.sf.net>
 License: LGPL-2+
 
 Files: tools/gst-typefind.c
-Copyright: 2003, Thomas Vander Stichele <thomas@apestaart.org>
+Copyright: 2003-2006, Thomas Vander Stichele <thomas at apestaart dot org>
 License: LGPL-2+
 
 Files: tools/tools.h
-Copyright: 2004, 2005, Benjamin Otte <otte@gnome.org>
+Copyright: 2003-2005, Benjamin Otte <otte@gnome.org>
 License: LGPL-2+
-- 
GitLab