=== release 1.29.2 ===

2026-06-29 00:04:39 +0100  Tim-Philipp Müller <tim@centricular.com>

	* gst-editing-services.doap:
	* meson.build:
	  Release 1.29.2

2026-06-18 05:27:43 -0400  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-command-line-formatter.c:
	  ges: command-line-formatter: fix leaks when serializing a timeline
	  ges_title_clip_get_text() returns a transfer-full string that was never
	  freed. The early-out paths in _serialize_object_properties() also
	  skipped g_value_unset() on the property GValue.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11434>

2026-05-12 15:11:42 -0400  Thibault Saunier <tsaunier@igalia.com>

	* tests/check/meson.build:
	* tests/check/scenarios/check_selector_title_glvideomixer.validatetest:
	  ges: validate: add title source selector test for glvideomixer
	  Adds check_selector_title_glvideomixer.validatetest, which exercises
	  the GESVideoElementSelector with a +title clip routed through
	  glvideomixer. The existing check_selector_* scenarios all use
	  +test-clip (videotestsrc) and never exercise the title source's
	  filter chain (videotestsrc ! textoverlay) against a non-software
	  compositor. This adds the first coverage of titles end-to-end with
	  the GL family.
	  Asserts the selector picks memory:GLMemory + glvideomixer +
	  glcolorconvert + glupload + gldownload.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11434>

2026-04-18 02:31:38 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-internal.h:
	* ges/ges-validate.c:
	* ges/ges-video-element-selector.c:
	* tests/check/meson.build:
	* tests/check/scenarios/check_selector_glvideomixer.validatetest:
	* tests/check/scenarios/check_selector_glvideomixerelement_strict.validatetest:
	* tests/check/scenarios/check_selector_software.validatetest:
	  ges: validate: add check-ges-video-element-selector action
	  Assert on the resolved GESVideoElementSelector state from a
	  validatetest. Every field is optional (strict / memory-feature /
	  <role>-factory); unspecified fields are not checked. Empty strings
	  assert the corresponding field is unset.
	  Backed by ges_video_element_selector_describe(), so no extra ABI
	  surface is pulled in just for testing.
	  And add tests using that new action type
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11434>

2026-04-18 02:31:33 +0000  Thibault Saunier <tsaunier@igalia.com>

	* tools/ges-launcher.c:
	* tools/ges-validate.c:
	* tools/ges-validate.h:
	  ges: launch: add `ges="compositor-factory=..."` testfile meta
	  Let validatetests override the auto-picked compositor the way they
	  already override individual plugin-feature ranks - e.g.
	  meta, tool=..., ges="compositor-factory=glvideomixer", ...
	  The meta is parsed up-front (before ges_pipeline builds any track,
	  which would otherwise resolve GESVideoElementSelector against the
	  unmodified ranks) and bumps the named factory above every other
	  Compositor-klass factory so the selector picks it.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11434>

2026-04-18 01:21:16 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-video-element-selector.c:
	* ges/gstframepositioner.c:
	* ges/gstframepositioner.h:
	  ges: invalidate GESVideoElementSelector on compositor rank changes
	  The selector was cached once for the process lifetime on first resolve,
	  and `gst_compositor_operator_get_type_and_default_value` - called from
	  `gst_frame_positioner_class_init` during plugin registration - triggers
	  that first resolve very early, before any user code has a chance to
	  change compositor ranks. Any later `gst_plugin_feature_set_rank` was
	  a no-op as far as the selector was concerned.
	  Connect `notify::rank` on every `Compositor`-klass factory and reset
	  both caches (selector + framepositioner's operator enum) on rank
	  change. The next resolve picks up the new ranks. The framepositioner
	  `operator` property GType stays pinned to whatever was first queried,
	  but that's harmless: `GstCompositorOperator` has the same enum values
	  across compositor/glvideomixer/etc.
	  Replaces the selector's g_once_init_enter pattern with a mutex-backed
	  init flag so invalidation and re-resolve work. The deinit path
	  disconnects all rank signals and drops the anchoring refs.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11434>

2026-04-15 22:59:46 +0000  Thibault Saunier <tsaunier@igalia.com>

	* docs/design/video-element-selection.md:
	* docs/hardware-acceleration.md:
	* docs/sitemap.txt:
	* ges/ges-effect-asset.c:
	* ges/ges-image-source.c:
	* ges/ges-internal.h:
	* ges/ges-smart-video-mixer.c:
	* ges/ges-text-overlay.c:
	* ges/ges-utils.c:
	* ges/ges-video-element-selector.c:
	* ges/ges-video-source.c:
	* ges/ges-video-track.c:
	* ges/ges-video-transition.c:
	* ges/ges-video-uri-source.c:
	* ges/ges.c:
	* ges/gesvideoscale.c:
	* ges/gstframepositioner.c:
	* ges/meson.build:
	  ges: add a video converter/videoflip element selector
	  Introduce GESVideoElementSelector, picks the best-ranked compositor
	  in the registry and, for its memory family, every raw-video primitive GES
	  needs in the source filter chain and smart mixer: colorconvert, convert+scale
	  (combined or a `colorconvert ! scale ! colorconvert` sandwich), scale, deinterlace,
	  videoflip, uploader and downloader.
	  Each role is resolved from the registry via klass keywords + pad
	  template caps + (for videoflip) the `GstVideoDirection` interface.
	  Factories from the compositor's own plugin win ties. A new backend
	  (Vulkan, CUDA, D3D, ...) lights up the moment its plugin is
	  installed - no GES change needed.
	  When the compositor's sink only accepts its native memory (strict),
	  the downloader is elided from each role's wrapper. Otherwise every
	  role is wrapped with `uploader ! core ! downloader` so the rest of
	  the chain stays in system memory.
	  When a role has no native factory, the selector retries with sysmem
	  and wraps the core with `downloader ! sw_core ! uploader` at build
	  time (bare in non-strict mode, where the chain is already sysmem).
	  Memory types that would need fallback but ship no uploader/downloader
	  are refused loudly. Any fallback forces non-strict, since strict
	  mode assumes every role ships a native factory.
	  Replace every hard-coded `gst_element_factory_make("videoconvert" |
	  "videoscale" | "videoflip" | "deinterlace")` in ges, ges-effect-asset,
	  ges-smart-video-mixer, ges-video-source, ges-video-uri-source,
	  ges-video-transition, ges-image-source, ges-text-overlay and
	  gesvideoscale with the selector's makers.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11434>

2026-05-21 15:26:24 -0400  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-command-line-formatter.c:
	* ges/ges-structured-interface.c:
	* ges/ges-structured-interface.h:
	  ges: command-line-formatter: smart defaults from clip discovery
	  A ges:// URI or ges-launch description that does not declare any
	  +track and/or any restrictions= had two ergonomic gaps:
	  * No +track at all left the timeline with no tracks, so
	  gst-launch-1.0 uridecodebin3 uri="ges:+clip /path/file.mov" ! ...
	  hung in PREROLLING with no source pads to expose.
	  * A bare +track video kept the construction-time default of
	  1280x720 @ 30fps (44100Hz/2ch for audio), downscaling 1080p/4k
	  sources and resampling 48kHz audio for no reason.
	  Plug both gaps in the formatter's _load() after structures have been
	  parsed (assets are already discovered at that point, since
	  _ges_get_asset_from_timeline uses ges_project_create_asset_sync):
	  * _auto_create_tracks() inspects the discovered stream types of
	  the +clip URI assets and adds a video and/or audio track when
	  none was declared. Falls back to audio+video when only test
	  clips are present, matching ges-launch's --track-types default.
	  ges_timeline_add_track retroactively wires existing clips.
	  * _auto_derive_track_restrictions() mirrors the get_smart_profile
	  histogram from ges-launcher and picks the most-frequent
	  (w, h, fps_n, fps_d) tuple over video streams and the most-
	  frequent (rate, channels) over audio streams. Ties break to the
	  larger canvas / higher rate. Applied via
	  ges_track_update_restriction_caps so existing feature flags
	  (e.g. video/x-raw(ANY)) survive.
	  Tracks the user explicitly restricted via the structured action are
	  tagged with a GObject qdata in _ges_add_track_from_struct and are
	  skipped by the auto-derive pass, so user overrides still win.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11671>

2026-05-21 14:45:37 -0400  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-structure-parser.c:
	* ges/ges-structure-parser.h:
	  ges: structure-parser: don't coerce nested [...] values to string
	  The ={VALUE} lex rule unconditionally rewrote every parsed value to
	  =(string)<value>, which broke restriction caps literals like
	  restrictions=[video/x-raw,width=1920,height=1080]
	  width and height ended up typed as (string)1920 / (string)1080 and
	  never intersected with the compositor's (int) range, leaving the
	  track capsfilter empty and the source pad unlinkable.
	  Track [/] bracket depth in the parser and skip the (string) cast
	  when inside a nested literal, mirroring GstStructure's own naked
	  bracket counting in _priv_gst_value_parse_struct_or_caps. Top-level
	  values keep the cast so unquoted enum names etc. still parse as
	  strings.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11671>

2026-04-24 13:26:41 +0200  Carlos Bentzen <cadubentzen@igalia.com>

	* ges/gstframepositioner.c:
	  ges: framepositioner: clear cached size on track==natural
	  A prior non-natural auto_position run otherwise leaks stale
	  width/height/posx/posy into the composition meta when the track
	  returns to natural size (e.g. after a reformat), making the
	  compositor render at the wrong dimensions.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11671>

2026-06-22 11:07:43 +0900  Seungha Yang <seungha@centricular.com>

	* meson.build:
	  msvc: Fix build after adding new tracer macros
	  MSVC's legacy preprocessor does not expand variadic args in
	  recursive macros correctly, causing new tracer macros to fail
	  with cl version 19.41.34120.
	  Use standard conforming preprocessor mode instead
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11907>

2026-05-20 17:45:34 -0400  Thibault Saunier <tsaunier@igalia.com>

	* plugins/nle/nlecomposition.c:
	  nlecomposition: Trace pipeline updates with custom spans
	  Wrap `update_pipeline` and its sub-steps (toplevel-stack computation,
	  deactivate / relink / activate) along with the seek paths in custom
	  spans carrying the composition name, update reason, seqnum and target
	  position.
	  The `setup-new-stack-to-first-buffer` span starts on tear-down and is
	  closed when the first buffer arrives on the new stack.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11708>

2026-04-07 13:09:24 +0100  Nirbheek Chauhan <nirbheek@centricular.com>

	* meson.build:
	  meson: Require C std gnu11 or c11
	  When using gcc or clang, gnu11 will be used, and when using MSVC c11
	  will be used which will pass /std:c11. This provides us with the
	  `restrict` keyword on all supported platforms.
	  We can do this now because we require Visual Studio 2019.
	  This feature was added in Meson 1.3
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11266>

2024-01-09 15:22:55 +0200  Vivia Nikolaidou <vivia@ahiru.eu>

	* tests/check/scenarios/check_keyframes_in_compositor_two_sources.validatetest:
	* tests/check/scenarios/check_keyframes_in_compositor_two_sources/flow-expectations/log-videosink-sink-expected:
	* tests/check/scenarios/complex_effect_bin_desc.validatetest:
	* tests/check/scenarios/complex_effect_bin_desc/flow-expectations/log-videosink-sink-expected:
	* tests/check/scenarios/edit_while_seeked_with_stop.validatetest:
	* tests/check/scenarios/edit_while_seeked_with_stop/flow-expectations/log-videosink-sink-expected:
	* tests/check/scenarios/seek_with_stop.check_clock_sync.validatetest:
	* tests/check/scenarios/seek_with_stop.check_clock_sync/flow-expectations/log-videosink-sink-expected:
	* tests/check/scenarios/seek_with_stop.validatetest:
	* tests/check/scenarios/seek_with_stop/flow-expectations/log-videosink-sink-expected:
	  compositor: Fix caps negotiation for messy downstream caps
	  compositor was assuming that the first structure of the downstream caps
	  was the preferred one. That may not always be the case, it might come
	  from e.g. a tee, which is media agnostic and just zig-zags the
	  structures. We should instead try to negotiate the best possible quality
	  out of the combination of downstream caps.
	  First we try to use square pixels, otherwise any PAR the default negotiation has
	  fed us with. Then we try to pick the best dimensions/framerate, giving priority
	  to dimensions over framerate if we can't get the best for both.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11342>

2026-04-16 16:13:56 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-uri-source.c:
	  ges: fix use-after-free in GESUriSource decodebin callbacks
	  uridecodebin streaming threads can fire autoplug-select and source-setup
	  after the owning GESVideoUriSource/GESAudioUriSource has started being
	  disposed, dereferencing a self->element that points at freed private
	  data (self is embedded in the owner's private data).
	  Connect those two signals with g_signal_connect_object(), passing the
	  owning track element as the lifetime-binding object. GLib then keeps
	  a temporary reference on it for the duration of each invocation and
	  invalidates the closure once the element is destroyed, covering both
	  the in-flight and future-invocation races without manual bookkeeping.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11374>

2026-03-09 21:37:34 +0000  Thibault Saunier <tsaunier@igalia.com>

	* plugins/nle/nleghostpad.c:
	  nle: ghostpad: Replace gst_pad_get_element_private with NleGhostPad subclass
	  The NLE ghost pad code stored per-pad data (NleObject pointer,
	  original event/query functions, pending seek, etc.) using
	  gst_pad_set_element_private() on both the ghost pad and its
	  internal proxy pad. Which is not MT safe.
	  Replace this with NleGhostPad, a proper GstGhostPad subclass that
	  embeds all the necessary data directly in its struct. The internal
	  proxy pad callbacks navigate back to their owning NleGhostPad via
	  gst_proxy_pad_get_internal(), which is safe because the proxy
	  pad's lifetime is bounded by the ghost pad's lifetime.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10992>

2026-03-03 18:04:20 -0300  Thibault Saunier <tsaunier@igalia.com>

	* tests/check/scenarios/check-clip-positioning.validatetest:
	* tests/check/scenarios/check-zorder.validatetest:
	* tests/check/scenarios/check_keyframes_in_compositor_two_sources.validatetest:
	* tests/check/scenarios/complex_effect_bin_desc.validatetest:
	* tests/check/scenarios/edit_while_seeked_with_stop.validatetest:
	* tests/check/scenarios/seek_with_stop.check_clock_sync.validatetest:
	* tests/check/scenarios/seek_with_stop.validatetest:
	* tests/check/scenarios/set-layer-on-command-line.validatetest:
	* tests/validate/nle/ensure_no_unnecessary_stack_init_seeks.validatetest:
	* tests/validate/nle/simple_source_in_composition_playback.validatetest:
	* tests/validate/nle/simple_source_playback.validatetest:
	  validate: Reindent all validatetest files
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10965>

2026-03-23 10:16:12 -0300  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-structured-interface.c:
	  structured-interface: fix use-after-free of last container reference
	  The LAST_CONTAINER_QDATA was stored as a raw pointer on the timeline,
	  which could become stale if the container was destroyed. Replace it with
	  a GWeakRef so that lookups safely return NULL when the container is gone
	  instead of dereferencing freed memory.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11348>

2025-11-21 10:59:39 -0300  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-asset.c:
	  ges: asset: fix potential crash in cache_deinit
	  Add a null check before destroying type_entries_table to handle cases
	  where the cache was never initialized or already deinitialized.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11348>

2026-02-06 19:31:12 +0000  Thibault Saunier <tsaunier@igalia.com>

	* plugins/nle/nlecomposition.c:
	  nlecomposition: fix race condition with seek_seqnum during concurrent seeks
	  When a new seek arrives via _add_seek_action() while _seek_pipeline_func()
	  is still processing a previous seek on the task thread, zeroing seek_seqnum
	  in _add_seek_action() causes a race condition. The task thread's
	  _set_current_bin_to_ready() would then create a FLUSH_START event with
	  seqnum 0, which gets dropped by the ghost event probe (seqnum mismatch).
	  Downstream elements then receive FLUSH_STOP without a preceding FLUSH_START,
	  leading to pipeline hangs/timeouts.
	  Fix this by:
	  1. Removing the seek_seqnum = 0 reset from _add_seek_action(), since the
	  seqnum will be properly set in _seek_pipeline_func() when the new seek
	  action is actually executed on the task thread.
	  2. Using flush_seqnum instead of seek_seqnum in _set_current_bin_to_ready()
	  for the FLUSH_START event, since both are set to the same value in
	  _seek_pipeline_func() and flush_seqnum is semantically correct for
	  flush events.
	  Fixes #4020
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10198>

2026-02-11 17:40:27 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-track.c:
	  ges: track: use ges_timeline_get_duration in update_gaps
	  Use the direct API instead of g_object_get to read the timeline
	  duration. This avoids going through the GObject property machinery
	  and is more efficient.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10198>

2026-02-11 14:36:54 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-extractable.c:
	* ges/ges-extractable.h:
	  ges: add MT-safe ges_extractable_get_asset_full()
	  ges_extractable_get_asset() returns a borrowed reference via
	  g_object_get_qdata() with no protection against concurrent modification.
	  A concurrent ges_extractable_set_asset() call can replace and unref the
	  asset, leaving callers with a dangling pointer.
	  Add ges_extractable_get_asset_full() which uses g_object_dup_data() to
	  atomically get and ref the asset under GLib's internal datalist lock,
	  returning a transfer-full reference that is safe to use across threads.
	  The old ges_extractable_get_asset() is deprecated in favor of the new
	  _full variant.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10198>

2026-02-09 18:27:57 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-container.c:
	* ges/ges-container.h:
	* ges/ges-group.c:
	* ges/ges-layer.c:
	* tests/check/ges/test-utils.h:
	  ges: make GES_CONTAINER_HEIGHT and GES_CONTAINER_CHILDREN macros MT-safe
	  Add ges_container_get_height() getter with proper timeline locking and
	  redirect GES_CONTAINER_HEIGHT macro to use it, matching the pattern
	  established for GES_TIMELINE_ELEMENT_* macros.
	  Deprecate GES_CONTAINER_CHILDREN macro in favor of the existing
	  ges_container_get_children() which returns a properly referenced list.
	  Internal callers in ges-group.c and ges-layer.c that are already under
	  lock use direct field access to avoid redundant locking. Test macros
	  are updated to use the MT-safe ges_container_get_children() API.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10198>

2026-01-21 19:06:44 -0300  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-internal.h:
	* ges/ges-timeline-element.h:
	* ges/ges-track-element.c:
	* tests/check/ges/test-utils.h:
	  ges: make GES_TIMELINE_ELEMENT_* macros MT-safe
	  Update the value macros (START, END, INPOINT, DURATION, MAX_DURATION,
	  PRIORITY) to call their corresponding getter functions which have proper
	  locking for MT-safety. These macros can no longer be used as lvalues.
	  Add deprecation notices to the reference macros (PARENT, TIMELINE, NAME)
	  pointing users to the proper getter functions that return referenced
	  objects/strings.
	  Update internal macros in ges-internal.h to use direct field access for
	  performance when called from within GES where locks are already held.
	  Update test-utils.h to explicitly use the public API macros so tests
	  exercise the same code paths as external users.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10198>

2026-01-21 16:23:44 -0300  Thibault Saunier <tsaunier@igalia.com>

	* tests/check/scenarios/check_keyframes_in_compositor_two_sources.validatetest:
	  tests: ges: add expected race condition pattern for keyframe test
	  Add another expected validateflow mismatch pattern for content-id
	  ordering variation (1 vs 11) that can occur due to race conditions
	  in the compositor two sources keyframe test.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10198>

2026-01-21 12:51:55 -0300  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-asset.c:
	* ges/ges-asset.h:
	* ges/ges-clip.c:
	* ges/ges-clip.h:
	* ges/ges-formatter.c:
	* ges/ges-formatter.h:
	* ges/ges-layer.c:
	* ges/ges-layer.h:
	* ges/ges-marker-list.c:
	* ges/ges-marker-list.h:
	* ges/ges-meta-container.c:
	* ges/ges-meta-container.h:
	* ges/ges-project.c:
	* ges/ges-project.h:
	* ges/ges-timeline.c:
	* ges/ges-timeline.h:
	* ges/ges-track-element.c:
	* ges/ges-track-element.h:
	* ges/ges-track.c:
	* ges/ges-track.h:
	  ges: add _full variants for all public API returning borrowed references
	  Add MT-safe _full variants that return owned references (transfer full)
	  for all public API functions that previously returned borrowed references
	  (transfer none). This completes the MT-safety implementation for GES.
	  New _full variants added:
	  - ges_track_get_caps_full()
	  - ges_asset_get_error_full()
	  - ges_clip_add_asset_full()
	  - ges_clip_add_child_to_track_full()
	  - ges_formatter_get_default_full()
	  - ges_find_formatter_for_uri_full()
	  - ges_marker_list_add_full()
	  - ges_meta_container_get_string_full()
	  - ges_meta_container_get_meta_full()
	  - ges_project_list_encoding_profiles_full()
	  Also fixes race conditions:
	  - ges_track_set_timeline() now protects trackelements_by_start iteration
	  - _get_container_data() uses double-checked locking for atomic creation
	  The original functions are deprecated with GES_DEPRECATED_FOR annotations
	  pointing to their _full counterparts.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10198>

2025-11-28 11:56:36 -0300  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-base-effect.c:
	* ges/ges-clip.c:
	* ges/ges-container.c:
	* ges/ges-internal.h:
	* ges/ges-layer.c:
	* ges/ges-pipeline.c:
	* ges/ges-project.c:
	* ges/ges-text-overlay-clip.c:
	* ges/ges-timeline-element.c:
	* ges/ges-timeline-element.h:
	* ges/ges-timeline.c:
	* ges/ges-title-clip.c:
	* ges/ges-track-element.c:
	* ges/ges-track.c:
	* ges/ges-uri-clip.c:
	* ges/ges-video-source.c:
	  ges: add internal locking to all public API functions
	  Make GES thread-safe by having every public API function internally
	  acquire/release a recursive mutex. This removes the need for users to
	  manually manage locking.
	  Each object type uses an appropriate locking strategy:
	  - GESTimeline: uses existing dyn_mutex
	  - GESTimelineElement/GESLayer/GESTrack: use _LOCK/_UNLOCK macros that
	  lock the timeline's mutex when in a timeline, or a local api_lock
	  when orphaned
	  Added GMutex timeline_lock and GRecMutex api_lock to GESLayerPrivate
	  and GESTrackPrivate for thread-safe timeline pointer access and
	  orphan state locking.
	  101 public API functions now have internal locking:
	  - ges-timeline-element.c: 42 functions
	  - ges-timeline.c: 30 functions
	  - ges-layer.c: 16 functions
	  - ges-track.c: 13 functions
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10198>

2025-11-25 11:04:32 -0300  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-timeline-element.c:
	  ges: add timeline_lock for thread-safe timeline pointer access
	  Add a mutex to protect the timeline pointer in GESTimelineElement.
	  This enables thread-safe access to the timeline pointer when setting
	  or getting the timeline, which is necessary for safe multi-threaded
	  usage of GES.
	  The timeline_lock protects:
	  - ges_timeline_element_set_timeline(): Safe update of timeline pointer
	  - ges_timeline_element_get_timeline(): Safe read with reference increment
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10198>

2026-03-30 16:40:02 +0300  Sebastian Dröge <sebastian@centricular.com>

	* ges/ges-multi-file-source.c:
	  gst: Fix a couple of const correctness bugs around strchr() usage
	  `assignment discards ‘const’ qualifier from pointer target type`
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11185>

2026-03-04 20:17:15 +0000  Thibault Saunier <tsaunier@igalia.com>

	* tests/check/scenarios/check_keyframes_in_compositor_two_sources.validatetest:
	  validate: flow: compare expectations live as lines are produced
	  Previously mismatches were only discovered after the pipeline finished,
	  losing information about when during execution the divergence happened.
	  By comparing each line as it is produced, the validate report now
	  captures the exact moment of mismatch with a backtrace pointing to the
	  code responsible.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10975>

2026-03-22 17:15:18 +0000  Tim-Philipp Müller <tim@centricular.com>

	* NEWS:
	* RELEASE:
	  modules: remove zombie RELEASE and NEWS files
	  They seem to have come back from the dead by mistake.

2026-03-22 15:00:47 +0000  Tim-Philipp Müller <tim@centricular.com>

	* meson.build:
	  Back to development after 1.29.1

=== release 1.29.1 ===

2026-03-22 14:56:37 +0000  Tim-Philipp Müller <tim@centricular.com>

	* NEWS:
	* RELEASE:
	* gst-editing-services.doap:
	* meson.build:
	  Release 1.29.1

2023-04-02 16:53:45 +0100  Tim-Philipp Müller <tim@centricular.com>

	* meson.build:
	* scripts/dist-common-files.py:
	  modules: dist common files from monorepo root
	  Less noise when making releases, and just need to maintain one copy.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11094>

2026-03-22 14:20:18 +0000  Tim-Philipp Müller <tim@centricular.com>

	* RELEASE:
	  modules: remove RELEASE from git, will be generated from template on dist

2026-02-15 15:02:07 +0000  Tim-Philipp Müller <tim@centricular.com>

	* NEWS:
	  modules: Remove NEWS from git which is generated from full release notes
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11094>

2025-07-09 18:10:13 -0400  Thibault Saunier <tsaunier@igalia.com>

	* tools/ges-launcher.c:
	  ges-launcher: fix crash when error message has no source
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11093>

2026-03-18 10:04:29 +0100  Xabier Rodriguez Calvar <calvaris@igalia.com>

	* meson.build:
	  ges: remove spurious python-embed dependency from libges
	  libges does not use any Python API directly — the only Python-related
	  code is gst_plugin_load("python") in ges-formatter.c, which is a
	  GStreamer API call. The gst-python plugin itself handles all Python
	  interaction.
	  The python-embed dependency was added to libges_deps, causing:
	  - An unnecessary python-X.Y-embed in Requires.private of the .pc file
	  - Unnecessary linkage against libpython on macOS
	  The config.h entries HAS_PYTHON and PY_LIB_FNAME were also dead code,
	  never referenced by any C source file.
	  Remove python_dep, gmodule_dep, and libdl from libges_deps along with
	  all the libpython search logic, since none of these are actually used.
	  This is a follow-up to !9759 which moved the OTIO formatter to a
	  separate Python plugin but left behind the now-unused python-embed
	  dependency and libpython search logic in the GES meson.build.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11065>

2026-03-03 15:02:23 +0000  Thibault Saunier <tsaunier@igalia.com>

	* tests/check/scenarios/check_keyframes_in_compositor_two_sources.validatetest:
	* tests/check/scenarios/complex_effect_bin_desc.validatetest:
	* tests/check/scenarios/edit_while_seeked_with_stop.validatetest:
	* tests/check/scenarios/seek_with_stop.check_clock_sync.validatetest:
	* tests/check/scenarios/seek_with_stop.validatetest:
	* tests/validate/nle/ensure_no_unnecessary_stack_init_seeks.validatetest:
	  validateflow: auto-derive directories from test file path
	  Allow validateflow configs to be written as proper nested structures
	  instead of requiring the $(validateflow) variable expansion:
	  configs = {
	  [validateflow, pad=sink:sink, buffers-checksum=true],
	  }
	  instead of:
	  configs = {
	  "$(validateflow), pad=sink:sink, buffers-checksum=true",
	  }
	  When expectations-dir or actual-results-dir are not explicitly set,
	  validate_flow_override_new() now derives them from the __filename__
	  metadata field (already attached to each config structure by the
	  parser). This mirrors the path computation done in
	  gst_validate_structure_set_variables_from_struct_file().
	  The $(validateflow) variable and the old string syntax remain fully
	  supported for backward compatibility.
	  Port all existing .validatetest files to the new syntax.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10962>

2026-02-10 16:26:05 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-pipeline.c:
	* tests/check/ges/basic.c:
	  ges: pipeline: fix shared task pool context handling
	  The shared task pool context created in ges_pipeline_handle_message
	  was never stored on the pipeline element itself. This meant
	  gst_element_get_context() would always return NULL for subsequent
	  NEED_CONTEXT requests, causing a new pool to be created for every
	  child element that requested one instead of reusing the same pool.
	  Fix this by calling gst_element_set_context() after creating the
	  pool, and clean up the pool in dispose.
	  Add a test verifying the context is properly stored on the pipeline.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-08 13:37:10 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-xml-formatter.c:
	  ges: xml-formatter: fix asset list leak in _save_assets
	  Two issues with the asset list in _save_assets:
	  The return value of g_list_sort was not assigned back to the assets
	  variable. Since g_list_sort may change the list head, the subsequent
	  g_list_free_full could miss nodes that were sorted before the original
	  head pointer.
	  Also, the early return on _save_subproject failure did not free the
	  assets list.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-08 13:37:03 +0000  Thibault Saunier <tsaunier@igalia.com>

	* plugins/ges/gesdemux.c:
	  gesdemux: fix buffer and event leaks in EOS handler
	  The EOS handler in ges_demux_sink_event takes a buffer from the input
	  adapter and maps it but never unmaps or unrefs it. The EOS event
	  parameter is also never unreffed on the success/error code paths since
	  the function returns before reaching gst_pad_event_default.
	  This caused "definitely lost" leaks of the xges file content buffer and
	  EOS events in every nested timeline test.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-06 23:30:13 +0000  Thibault Saunier <tsaunier@igalia.com>

	* plugins/ges/gesbasebin.c:
	  ges: fix memory leaks during nested timeline teardown
	  GESBaseBin locks the inner timeline's state (commit b283b3b5442) to
	  prevent the parent NLE composition's action thread from cascading state
	  changes into it, which would cause SELECT_STREAM events to be pushed
	  from the wrong thread. During shutdown however, this locked state
	  prevents the inner timeline from being properly set to NULL during
	  the normal state change cascade, leaking pads' sticky events and
	  buffers.
	  Fix this by unlocking the timeline state in GESBaseBin's PAUSED_TO_READY
	  handler - by this point the composition's action thread is already
	  stopping and the race condition no longer applies.
	  Also set the inner timeline to NULL in GESBaseBin's dispose as a safety
	  net for cases where the state change cascade doesn't run.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-06 21:23:20 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-validate.c:
	  ges: validate: fix action type leak in prepare_seek_action
	  gst_validate_get_action_type() returns a new reference that must be
	  released by the caller. prepare_seek_action() never unreffed the
	  returned type, leaking a reference on every seek action preparation.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-06 17:10:51 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-timeline.c:
	  ges: timeline: fix SELECT_STREAMS event leak in send_event
	  GstElement::send_event is transfer-full for the event parameter.
	  When ges_timeline_send_event() handles a GST_EVENT_SELECT_STREAMS
	  event internally instead of chaining up, it must unref the event.
	  The event was leaked on every stream selection.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-06 17:10:46 +0000  Thibault Saunier <tsaunier@igalia.com>

	* plugins/nle/nleobject.c:
	  nle: fix message leaks in nle_bin_handle_message
	  GstBin::handle_message is transfer-full for the message parameter.
	  When the method returns without chaining up to the parent class, it
	  must unref the message itself.
	  Both early-return paths (NLE_QUERY_PARENT_NLE_OBJECT handling and
	  GST_MESSAGE_STREAM_COLLECTION dropping) were missing the
	  gst_message_unref() call, leaking the message on every occurrence.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-06 17:10:39 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-project.c:
	  ges: project: fix URI string leak in missing-uri signal emission
	  g_signal_emit() with a G_TYPE_STRING return value overwrites the
	  output pointer without freeing the previous value. When
	  _request_id_update() returns a non-NULL new_id, that string was
	  leaked by the subsequent g_signal_emit() call which unconditionally
	  overwrites the pointer.
	  Save the proposed id before emitting the signal and free it only if
	  the signal handler provides a different replacement.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-06 17:10:33 +0000  Thibault Saunier <tsaunier@igalia.com>

	* ges/ges-track.c:
	  ges: track: fix stream collection leak in handle_message
	  gst_structure_get() with GST_TYPE_STREAM_COLLECTION returns a new
	  reference that was never released after being passed to
	  ges_track_select_subtimeline_streams().
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-06 17:10:27 +0000  Thibault Saunier <tsaunier@igalia.com>

	* plugins/ges/gesdemux.c:
	  gesdemux: fix caps and query leaks
	  Fix two memory leaks found with valgrind:
	  - In ges_demux_get_extension(), the caps created from mimetype were
	  not freed when no matching structure was found in the loop iteration,
	  leaking on every non-matching formatter.
	  - In ges_demux_create_timeline(), the URI query was never unreffed
	  after being used, leaking on every timeline creation.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10784>

2026-02-03 12:44:32 -0300  Thibault Saunier <tsaunier@igalia.com>

	* tests/validate/geslaunch.py:
	  integration-testsuites: rename medias/ to media/
	  "Media" is already the plural of "medium", so "medias" is a double
	  plural. Rename the submodule directory from medias/ to media/ and update
	  all references throughout the codebase.
	  The --media-paths argument is now the primary name for the launcher
	  option, with --medias-paths kept as a deprecated alias for backward
	  compatibility.
	  The gitlab repo has been renamed from gst-integration-testsuites to
	  gst-test-media to better reflect its contents (media files only, not
	  testsuites), though the URL path remains gst-integration-testsuites due
	  to gitlab limitations.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10537>

2026-01-27 18:25:19 +0100  Piotr Brzeziński <piotr@centricular.com>

	* meson.build:
	  meson: Fix libxml2 not building due to wrong option type
	  'python' was moved from a boolean to a feature a few months ago and
	  4f4260dbe3489699aba0a724a3d55020666a0d6a pulled that in on our side.
	  Notably, this was causing adaptivedemux2 to not build on my system.
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10615>

2026-01-27 18:36:19 +0000  Tim-Philipp Müller <tim@centricular.com>

	* RELEASE:
	* meson.build:
	  Back to development in main branch after 1.28.0
	  - Track orc main branch
	  - Track gst-plugins-rs main branch
	  Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/10616>

=== release 1.28.0 ===

