Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package gstreamer for openSUSE:Factory 
checked in at 2026-07-12 16:20:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/gstreamer (Old)
 and      /work/SRC/openSUSE:Factory/.gstreamer.new.1991 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "gstreamer"

Sun Jul 12 16:20:36 2026 rev:124 rq:1364875 version:1.28.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/gstreamer/gstreamer.changes      2026-06-13 
18:46:56.120427022 +0200
+++ /work/SRC/openSUSE:Factory/.gstreamer.new.1991/gstreamer.changes    
2026-07-12 16:21:07.543938060 +0200
@@ -1,0 +2,44 @@
+Thu Jul  9 17:11:31 UTC 2026 - Bjørn Lie <[email protected]>
+
+- Update to version 1.28.5:
+  + Highlighted bugfixes:
+    - Various security fixes and playback fixes
+    - Fix subtitles cause green flickering with VA decoders on AMD
+      GPUs
+    - core: Fix sticky event raciness when pads are linked mid-push
+    - appsrc: Uniformly handle EOS events being pushed
+    - audio-resampler-neon fails to build for targets with neon but
+      without thumb
+    - avtp: Correct ptime generation from avtp timestamp
+    - fmp4mux: Various fixes for splitting at fragment boundaries
+    - gldownload: fix wrong DRM format negotiation causing R/B
+      channel swap
+    - gdkpixbufdec: Drop rank to NONE and handle resolution/format
+      changes
+    - gopbuffer: add support for H.266/VVC
+    - h265decoder: Fix HEVC with alpha decoding
+    - mp4mux: fix AC-3 template caps so muxer can accept input from
+      ac3parse
+    - mpegtsmux: Always assign PTS to output buffers in CBR mode
+    - mpegtsmux: Output buffers with PCR-only bitrate-padding
+      packets have wrong PTS
+    - rtcpbuffer: Fix parsing of SR+SDES compound packets
+      (regression from security fix)
+    - rtspsrc2: Allow disabling SRTP/SRTCP encryption and SRTP
+      authentication
+    - tsdemux: Improve PTS rollover handling in ignore-pcr mode,
+      fixing intermittent corruption with YouTube HLS streams
+    - textaccumulate: output joined single buffer, add list as meta
+    - threadshare: add ts-clocksync
+    - webrtcsink: negotiation fixes and improvements
+    - Various bug fixes, build fixes, memory leak fixes, and other
+      stability and reliability improvements
+  + gstreamer:
+    - caps: fix field name leak in gst_caps_structure_simplify
+    - info: Use a more optimized version of GST_TIME_ARGS
+    - pads: Fix sticky event raciness when linked mid-push
+    - typefindhelper: Drop unnecessary check for factories without
+      a function
+    - Use named pipes when spawning gst-ptp-helper on Windows
+
+-------------------------------------------------------------------

Old:
----
  gstreamer-1.28.4.obscpio

New:
----
  gstreamer-1.28.5.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ gstreamer.spec ++++++
--- /var/tmp/diff_new_pack.gDyL00/_old  2026-07-12 16:21:08.339965287 +0200
+++ /var/tmp/diff_new_pack.gDyL00/_new  2026-07-12 16:21:08.339965287 +0200
@@ -19,7 +19,7 @@
 %define gst_branch 1.0
 
 Name:           gstreamer
-Version:        1.28.4
+Version:        1.28.5
 Release:        0
 Summary:        Streaming-Media Framework Runtime
 License:        LGPL-2.1-or-later

++++++ _service ++++++
--- /var/tmp/diff_new_pack.gDyL00/_old  2026-07-12 16:21:08.367966245 +0200
+++ /var/tmp/diff_new_pack.gDyL00/_new  2026-07-12 16:21:08.371966381 +0200
@@ -5,7 +5,7 @@
     <param 
name="url">https://gitlab.freedesktop.org/gstreamer/gstreamer.git</param>
     <param name="subdir">subprojects/gstreamer</param>
     <param name="filename">gstreamer</param>
-    <param name="revision">1.28.4</param>
+    <param name="revision">1.28.5</param>
     <param name="versionformat">@PARENT_TAG@+@TAG_OFFSET@</param>
     <param name="versionrewrite-pattern">v?(.*)\+0</param>
     <param name="versionrewrite-replacement">\1</param>

++++++ gstreamer-1.28.4.obscpio -> gstreamer-1.28.5.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/gst/gstcaps.c 
new/gstreamer-1.28.5/gst/gstcaps.c
--- old/gstreamer-1.28.4/gst/gstcaps.c  2026-06-12 14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/gst/gstcaps.c  2026-07-08 23:42:39.000000000 +0200
@@ -2547,9 +2547,11 @@
       g_free (one);
       g_free (two);
     }
+    gst_id_str_clear (&field.name);
     return ret;
   }
 
+  gst_id_str_clear (&field.name);
   return FALSE;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/gst/gstinfo.c 
new/gstreamer-1.28.5/gst/gstinfo.c
--- old/gstreamer-1.28.4/gst/gstinfo.c  2026-06-12 14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/gst/gstinfo.c  2026-07-08 23:42:39.000000000 +0200
@@ -146,6 +146,105 @@
 #define GST_ENABLE_FORMAT_NONLITERAL_WARNING
 #endif
 
+#undef GST_TIME_ARGS
+#undef GST_STIME_ARGS
+#undef GST_TIME_FORMAT
+#undef GST_STIME_FORMAT
+
+static inline int
+_u32_to_dec (char *p, guint32 v)
+{
+  if (v == 0) {
+    *p = '0';
+    return 1;
+  }
+  char tmp[10];                 /* UINT32_MAX = 4294967295, 10 digits */
+  int n = 0;
+  while (v) {
+    tmp[n++] = '0' + (v % 10);
+    v /= 10;
+  }
+  for (int i = 0; i < n; ++i)
+    p[i] = tmp[n - 1 - i];
+  return n;
+}
+
+/* Internal: writes "[H...]H:MM:SS.nnnnnnnnn" at p, returns the end pointer.
+   Caller guarantees ns < GST_SECOND. */
+static inline char *
+_gst_write_hms_ns (char *p, guint64 sec, guint ns)
+{
+  guint h = (guint) (sec / 3600);       /* fits in 32 bits:
+                                           max ≈ 5.12e6 (unsigned)
+                                           max ≈ 2.56e6 (signed) */
+  guint r = (guint) (sec - (guint64) h * 3600);
+  guint m = r / 60;
+  guint s = r - m * 60;
+
+  p += _u32_to_dec (p, h);
+  *p++ = ':';
+  *p++ = '0' + (m / 10);
+  *p++ = '0' + (m % 10);
+  *p++ = ':';
+  *p++ = '0' + (s / 10);
+  *p++ = '0' + (s % 10);
+  *p++ = '.';
+  for (int i = 8; i >= 0; --i) {
+    p[i] = '0' + (ns % 10);
+    ns /= 10;
+  }
+  return p + 9;
+}
+
+static inline const char *
+_gst_t_str (GstClockTime t, char *buf)
+{
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (t))) {
+    memcpy (buf, "99:99:99.999999999", 19);     /* incl. NUL */
+    return buf;
+  }
+  guint64 sec = t / GST_SECOND;
+  guint ns = (guint) (t - sec * GST_SECOND);
+  *_gst_write_hms_ns (buf, sec, ns) = '\0';
+  return buf;
+}
+
+static inline const char *
+_gst_st_str (GstClockTimeDiff t, char *buf)
+{
+  if (G_UNLIKELY (!GST_CLOCK_STIME_IS_VALID (t))) {
+    memcpy (buf, "+99:99:99.999999999", 20);    /* incl. NUL */
+    return buf;
+  }
+  char *p = buf;
+  guint64 abs_t;
+  if (t < 0) {
+    *p++ = '-';
+    /* Unsigned negation is defined modulo 2^64 and yields the correct
+       magnitude even at t == G_MININT64, where -(gint64)t would be UB.
+       For valid inputs (t != G_MININT64) the magnitude fits in gint64
+       anyway; this idiom just avoids a special case. */
+    abs_t = -(guint64) t;
+  } else {
+    *p++ = '+';
+    abs_t = (guint64) t;
+  }
+  guint64 sec = abs_t / GST_SECOND;
+  guint ns = (guint) (abs_t - sec * GST_SECOND);
+  *_gst_write_hms_ns (p, sec, ns) = '\0';
+  return buf;
+}
+
+/*
+ * The use of compound literals here is fine because the scope is the enclosing
+ * block, which is more than enough. The memory is only used for log formatting
+ * and isn't used outside of the formatting function call.
+ */
+#define GST_TIME_FORMAT  "s"
+#define GST_TIME_ARGS(t) _gst_t_str((t), (char[32]){0})
+
+#define GST_STIME_FORMAT  "s"
+#define GST_STIME_ARGS(t) _gst_st_str((t), (char[32]){0})
 
 #ifdef G_OS_WIN32
 #  define WIN32_LEAN_AND_MEAN   /* prevents from including too many things */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/gst/gstpad.c 
new/gstreamer-1.28.5/gst/gstpad.c
--- old/gstreamer-1.28.4/gst/gstpad.c   2026-06-12 14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/gst/gstpad.c   2026-07-08 23:42:39.000000000 +0200
@@ -122,6 +122,12 @@
 
 #define _PAD_PROBE_TYPE_ALL_BOTH_AND_FLUSH (GST_PAD_PROBE_TYPE_ALL_BOTH | 
GST_PAD_PROBE_TYPE_EVENT_FLUSH)
 
+/* Some internal aliasing on flow return values to ease reading */
+#define GST_FLOW_PROBE_DROPPED GST_FLOW_CUSTOM_SUCCESS
+#define GST_FLOW_PROBE_HANDLED GST_FLOW_CUSTOM_SUCCESS_1
+#define GST_FLOW_PROBE_UNSENT GST_FLOW_CUSTOM_SUCCESS_2
+#define GST_FLOW_PROBE_INTERRUPTED (GST_FLOW_CUSTOM_SUCCESS_2 + 1)
+
 /* we have a pending and an active event on the pad. On source pads only the
  * active event is used. On sinkpads, events are copied to the pending entry 
and
  * moved to the active event when the eventfunc returned %TRUE. */
@@ -136,11 +142,14 @@
 {
   guint events_cookie;
   GArray *events;
-  guint last_cookie;
+  guint last_events_cookie;
 
   gint using;
   guint probe_list_cookie;
 
+  /* Incremented when the peer changes */
+  guint peer_cookie;
+
   /* counter of how many idle probes are running directly from the add_probe
    * call. Used to block any data flowing in the pad while the idle callback
    * Doesn't finish its work */
@@ -425,7 +434,8 @@
 
   pad->priv->events = g_array_sized_new (FALSE, TRUE, sizeof (PadEvent), 16);
   pad->priv->events_cookie = 0;
-  pad->priv->last_cookie = -1;
+  pad->priv->last_events_cookie = -1;
+  pad->priv->peer_cookie = 0;
   g_cond_init (&pad->priv->activation_cond);
 
   pad->ABI.abi.last_flowret = GST_FLOW_FLUSHING;
@@ -2579,6 +2589,10 @@
   GST_PAD_PEER (srcpad) = sinkpad;
   GST_PAD_PEER (sinkpad) = srcpad;
 
+  /* Increment the srcpad's link cookie that peer might have changed
+   * to abort in-progress sticky event replay */
+  srcpad->priv->peer_cookie++;
+
   /* check events, when something is different, mark pending */
   schedule_events (srcpad, sinkpad);
 
@@ -3973,7 +3987,7 @@
     GST_DEBUG_OBJECT (pad, "data is dropped");
     if (data.called_probes_size > N_STACK_ALLOCATE_PROBES)
       g_free (data.called_probes);
-    return GST_FLOW_CUSTOM_SUCCESS;
+    return GST_FLOW_PROBE_DROPPED;
   }
 passed:
   {
@@ -3988,7 +4002,7 @@
     GST_DEBUG_OBJECT (pad, "data was handled");
     if (data.called_probes_size > N_STACK_ALLOCATE_PROBES)
       g_free (data.called_probes);
-    return GST_FLOW_CUSTOM_SUCCESS_1;
+    return GST_FLOW_PROBE_HANDLED;
   }
 }
 
@@ -4078,6 +4092,11 @@
    * next. Don't forward sticky events
    * that would come after that */
   GstEvent *event;
+
+  /* The peer cookie when this push_sticky cycle
+   * started, to detect the case where the pad
+   * gets re-linked mid-way */
+  guint peer_cookie;
 } PushStickyData;
 
 /* Push the sticky event in the #PadEvent pointed by @ev.
@@ -4111,7 +4130,7 @@
   if (data->event && GST_EVENT_IS_STICKY (data->event) &&
       data_sticky_order <= _to_sticky_order (GST_EVENT_SEGMENT) &&
       data_sticky_order < ev->sticky_order) {
-    data->ret = GST_FLOW_CUSTOM_SUCCESS_1;
+    data->ret = GST_FLOW_PROBE_UNSENT;
   } else {
     GST_OBJECT_UNLOCK (pad);
     /* The event argument remains valid during the unlock as the caller must
@@ -4132,8 +4151,9 @@
     GST_TRACER_PAD_PUSH_EVENT_POST (pad, data->ret >= GST_FLOW_OK);
     GST_OBJECT_LOCK (pad);
 
-    if (data->ret == GST_FLOW_CUSTOM_SUCCESS_1)
+    if (data->ret == GST_FLOW_PROBE_HANDLED)
       data->ret = GST_FLOW_OK;
+
   }
 
   switch (data->ret) {
@@ -4142,14 +4162,14 @@
       GST_DEBUG_OBJECT (pad, "event %s marked received",
           GST_EVENT_TYPE_NAME (event));
       break;
-    case GST_FLOW_CUSTOM_SUCCESS:
+    case GST_FLOW_PROBE_DROPPED:
       /* we can't assume the event is received when it was dropped */
       GST_DEBUG_OBJECT (pad, "event %s was dropped, mark pending",
           GST_EVENT_TYPE_NAME (event));
       GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
       data->ret = GST_FLOW_OK;
       break;
-    case GST_FLOW_CUSTOM_SUCCESS_1:
+    case GST_FLOW_PROBE_UNSENT:
       /* event was ignored and should be sent later */
       GST_DEBUG_OBJECT (pad, "event %s was ignored, mark pending",
           GST_EVENT_TYPE_NAME (event));
@@ -4158,7 +4178,8 @@
       break;
     case GST_FLOW_NOT_LINKED:
       /* not linked is not a problem, we are sticky so the event will be
-       * rescheduled to be sent later on re-link, but only for non-EOS events 
*/
+       * rescheduled to be sent later on re-link, except for EOS events
+       * which must be received */
       GST_DEBUG_OBJECT (pad, "pad was not linked, mark pending");
       if (GST_EVENT_TYPE (event) != GST_EVENT_EOS) {
         data->ret = GST_FLOW_OK;
@@ -4175,6 +4196,14 @@
   if (data->ret != GST_FLOW_OK && GST_EVENT_TYPE (event) == GST_EVENT_EOS)
     data->was_eos = TRUE;
 
+  /* We unlocked above an in pushing the event, so the pad might have been
+   * relinked. In that case, we abort and start sending sticky events again */
+  if (data->peer_cookie != pad->priv->peer_cookie
+      && GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLAG_PENDING_EVENTS)) {
+    GST_DEBUG_OBJECT (pad, "Pad peer changed during sticky event pushing");
+    data->ret = GST_FLOW_PROBE_INTERRUPTED;
+  }
+
   return data->ret == GST_FLOW_OK;
 }
 
@@ -4182,13 +4211,17 @@
  * have not been yet received by downstream and that aren't priority-ordered
  * after the optional @event passed as argument.
  *
- * Must be called with pad LOCK. */
+ * Must be called with pad LOCK, but can drop the lock while it pushes events 
*/
 static inline GstFlowReturn
 check_sticky (GstPad * pad, GstEvent * event)
 {
-  PushStickyData data = { GST_FLOW_OK, FALSE, event };
+  do {
+    PushStickyData data = { GST_FLOW_OK, FALSE, event, pad->priv->peer_cookie 
};
+
+    if (G_LIKELY (!GST_PAD_HAS_PENDING_EVENTS (pad))) {
+      return GST_FLOW_OK;
+    }
 
-  if (G_UNLIKELY (GST_PAD_HAS_PENDING_EVENTS (pad))) {
     GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
 
     GST_DEBUG_OBJECT (pad, "pushing all sticky events");
@@ -4222,12 +4255,24 @@
 
         /* the event could have been dropped. Because this can only
          * happen if the user asked for it, it's not an error */
-        if (data.ret == GST_FLOW_CUSTOM_SUCCESS)
+        if (data.ret == GST_FLOW_PROBE_DROPPED)
           data.ret = GST_FLOW_OK;
       }
     }
-  }
-  return data.ret;
+
+    if (data.ret == GST_FLOW_PROBE_INTERRUPTED) {
+      GST_DEBUG_OBJECT (pad,
+          "Pad was re-linked during sticky event sending. Restarting");
+
+      GstPad *sinkpad = GST_PAD_PEER (pad);
+      if (sinkpad != NULL) {
+        schedule_events (pad, sinkpad);
+      }
+      /* Fall through and loop */
+    } else {
+      return data.ret;
+    }
+  } while (TRUE);
 }
 
 
@@ -4360,7 +4405,7 @@
 
     /* if a probe dropped without handling, we don't sent it further but assume
      * that the probe did not answer the query and return FALSE */
-    if (ret != GST_FLOW_CUSTOM_SUCCESS_1)
+    if (ret != GST_FLOW_PROBE_HANDLED)
       res = FALSE;
     else
       res = TRUE;
@@ -4477,7 +4522,7 @@
 
     /* if a probe dropped without handling, we don't sent it further but
      * assume that the probe did not answer the query and return FALSE */
-    if (ret != GST_FLOW_CUSTOM_SUCCESS_1)
+    if (ret != GST_FLOW_PROBE_HANDLED)
       res = FALSE;
     else
       res = TRUE;
@@ -4519,7 +4564,7 @@
     goto wrong_mode;
 
 #ifdef GST_ENABLE_EXTRA_CHECKS
-  if (G_UNLIKELY (pad->priv->last_cookie != pad->priv->events_cookie)) {
+  if (G_UNLIKELY (pad->priv->last_events_cookie != pad->priv->events_cookie)) {
     if (!find_event_by_type (pad, GST_EVENT_STREAM_START, 0)) {
       g_warning (G_STRLOC
           ":%s:<%s:%s> Got data flow before stream-start event",
@@ -4530,7 +4575,7 @@
           ":%s:<%s:%s> Got data flow before segment event",
           G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
     }
-    pad->priv->last_cookie = pad->priv->events_cookie;
+    pad->priv->last_events_cookie = pad->priv->events_cookie;
   }
 #endif
 
@@ -4632,13 +4677,13 @@
   /* PASSTHROUGH */
 probe_stopped:
   {
-    /* We unref the buffer, except if the probe handled it (CUSTOM_SUCCESS_1) 
*/
+    /* We unref the buffer, except if the probe handled it 
(GST_FLOW_PROBE_HANDLED) */
     if (data && !handled)
       gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
 
     switch (ret) {
-      case GST_FLOW_CUSTOM_SUCCESS:
-      case GST_FLOW_CUSTOM_SUCCESS_1:
+      case GST_FLOW_PROBE_DROPPED:
+      case GST_FLOW_PROBE_HANDLED:
         GST_DEBUG_OBJECT (pad, "dropped or handled buffer");
         ret = GST_FLOW_OK;
         break;
@@ -4809,7 +4854,7 @@
     goto wrong_mode;
 
 #ifdef GST_ENABLE_EXTRA_CHECKS
-  if (G_UNLIKELY (pad->priv->last_cookie != pad->priv->events_cookie)) {
+  if (G_UNLIKELY (pad->priv->last_events_cookie != pad->priv->events_cookie)) {
     if (!find_event_by_type (pad, GST_EVENT_STREAM_START, 0)) {
       g_warning (G_STRLOC
           ":%s:<%s:%s> Got data flow before stream-start event",
@@ -4820,7 +4865,7 @@
           ":%s:<%s:%s> Got data flow before segment event",
           G_STRFUNC, GST_DEBUG_PAD_NAME (pad));
     }
-    pad->priv->last_cookie = pad->priv->events_cookie;
+    pad->priv->last_events_cookie = pad->priv->events_cookie;
   }
 #endif
 
@@ -4914,8 +4959,8 @@
       gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
 
     switch (ret) {
-      case GST_FLOW_CUSTOM_SUCCESS:
-      case GST_FLOW_CUSTOM_SUCCESS_1:
+      case GST_FLOW_PROBE_DROPPED:
+      case GST_FLOW_PROBE_HANDLED:
         GST_DEBUG_OBJECT (pad, "dropped or handled buffer");
         ret = GST_FLOW_OK;
         break;
@@ -5131,7 +5176,7 @@
   {
     GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
         "probe returned %s", gst_flow_get_name (ret));
-    if (ret == GST_FLOW_CUSTOM_SUCCESS) {
+    if (ret == GST_FLOW_PROBE_DROPPED) {
       if (res_buf) {
         /* the probe filled the buffer and asks us to not call the getrange
          * anymore, we continue with the post probes then. */
@@ -5155,7 +5200,7 @@
     GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
         "probe returned %s", gst_flow_get_name (ret));
     /* if we drop here, it signals EOS */
-    if (ret == GST_FLOW_CUSTOM_SUCCESS)
+    if (ret == GST_FLOW_PROBE_DROPPED)
       ret = GST_FLOW_EOS;
     pad->ABI.abi.last_flowret = ret;
     GST_OBJECT_UNLOCK (pad);
@@ -5356,7 +5401,7 @@
   {
     GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "pre probe returned %s",
         gst_flow_get_name (ret));
-    if (ret == GST_FLOW_CUSTOM_SUCCESS) {
+    if (ret == GST_FLOW_PROBE_DROPPED) {
       if (res_buf) {
         /* the probe filled the buffer and asks us to not forward to the peer
          * anymore, we continue with the post probes then */
@@ -5397,7 +5442,7 @@
         "post probe returned %s", gst_flow_get_name (ret));
 
     /* if we drop here, it signals EOS */
-    if (ret == GST_FLOW_CUSTOM_SUCCESS)
+    if (ret == GST_FLOW_PROBE_DROPPED)
       ret = GST_FLOW_EOS;
 
     pad->ABI.abi.last_flowret = ret;
@@ -5584,10 +5629,29 @@
 
   /* Forward all sticky events before our current one that are pending */
   if (ev->event != data->event
-      && ev->sticky_order < _to_sticky_order (GST_EVENT_TYPE (data->event)))
+      && ev->sticky_order < _to_sticky_order (GST_EVENT_TYPE (data->event))) {
     return push_sticky (pad, ev, data);
+  }
 
-  return TRUE;
+  return FALSE;
+}
+
+/* Helper to push all changed sticky events that precede the passed event
+ * in sticky-order. Called with the OBJECT_LOCK held, but may release it
+ * while pushing an event. Loops in the case that the pad is re-linked
+ * during the event pushing */
+static void
+push_changed_sticky_events_before (GstPad * pad, GstEvent * event)
+{
+  PushStickyData data = { GST_FLOW_OK, FALSE, event, pad->priv->peer_cookie };
+  GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+
+  /* Push all sticky events before our current one
+   * that have changed */
+  do {
+    events_foreach (pad, sticky_changed, &data);
+  } while (data.ret == GST_FLOW_PROBE_INTERRUPTED
+      && GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLAG_PENDING_EVENTS));
 }
 
 /* should be called with pad LOCK */
@@ -5656,12 +5720,7 @@
       /* recheck sticky events because the probe might have cause a relink */
       if (GST_PAD_HAS_PENDING_EVENTS (pad) && GST_PAD_IS_SRC (pad)
           && (GST_EVENT_IS_SERIALIZED (event))) {
-        PushStickyData data = { GST_FLOW_OK, FALSE, event };
-        GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-
-        /* Push all sticky events before our current one
-         * that have changed */
-        events_foreach (pad, sticky_changed, &data);
+        push_changed_sticky_events_before (pad, event);
       }
       break;
     }
@@ -5677,12 +5736,7 @@
   if (GST_PAD_HAS_PENDING_EVENTS (pad) && GST_PAD_IS_SRC (pad)
       && (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);
-
-    /* Push all sticky events before our current one
-     * that have changed */
-    events_foreach (pad, sticky_changed, &data);
+    push_changed_sticky_events_before (pad, event);
   }
 
   /* the pad offset might've been changed by any of the probes above. It
@@ -5742,14 +5796,14 @@
 probe_stopped:
   {
     GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
-    if (event && ret != GST_FLOW_CUSTOM_SUCCESS_1)
+    if (event && ret != GST_FLOW_PROBE_HANDLED)
       gst_event_unref (event);
 
     switch (ret) {
-      case GST_FLOW_CUSTOM_SUCCESS_1:
+      case GST_FLOW_PROBE_HANDLED:
         GST_DEBUG_OBJECT (pad, "handled event");
         break;
-      case GST_FLOW_CUSTOM_SUCCESS:
+      case GST_FLOW_PROBE_DROPPED:
         GST_DEBUG_OBJECT (pad, "dropped event");
         break;
       default:
@@ -5855,8 +5909,8 @@
     /* non-serialized and non-sticky events are pushed right away. */
     ret = gst_pad_push_event_unchecked (pad, event, type);
     /* dropped events by a probe are not an error */
-    res = (ret == GST_FLOW_OK || ret == GST_FLOW_CUSTOM_SUCCESS
-        || ret == GST_FLOW_CUSTOM_SUCCESS_1);
+    res = (ret == GST_FLOW_OK || ret == GST_FLOW_PROBE_DROPPED
+        || ret == GST_FLOW_PROBE_HANDLED);
   } else {
     /* Errors in sticky event pushing are no problem and ignored here
      * as they will cause more meaningful errors during data flow.
@@ -6192,12 +6246,12 @@
     if (need_unlock)
       GST_PAD_STREAM_UNLOCK (pad);
     /* Only unref if unhandled */
-    if (event && ret != GST_FLOW_CUSTOM_SUCCESS_1)
+    if (event && ret != GST_FLOW_PROBE_HANDLED)
       gst_event_unref (event);
 
     switch (ret) {
-      case GST_FLOW_CUSTOM_SUCCESS_1:
-      case GST_FLOW_CUSTOM_SUCCESS:
+      case GST_FLOW_PROBE_HANDLED:
+      case GST_FLOW_PROBE_DROPPED:
         GST_DEBUG_OBJECT (pad, "dropped or handled event");
         ret = GST_FLOW_OK;
         break;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/gstreamer.doap 
new/gstreamer-1.28.5/gstreamer.doap
--- old/gstreamer-1.28.4/gstreamer.doap 2026-06-12 14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/gstreamer.doap 2026-07-08 23:42:39.000000000 +0200
@@ -40,6 +40,16 @@
 
  <release>
   <Version>
+   <revision>1.28.5</revision>
+   <branch>1.28</branch>
+   <name></name>
+   <created>2026-07-08</created>
+   <file-release 
rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer/gstreamer-1.28.5.tar.xz";
 />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
    <revision>1.28.4</revision>
    <branch>1.28</branch>
    <name></name>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/libs/gst/base/gsttypefindhelper.c 
new/gstreamer-1.28.5/libs/gst/base/gsttypefindhelper.c
--- old/gstreamer-1.28.4/libs/gst/base/gsttypefindhelper.c      2026-06-12 
14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/libs/gst/base/gsttypefindhelper.c      2026-07-08 
23:42:39.000000000 +0200
@@ -964,10 +964,6 @@
 
     factory = GST_TYPE_FIND_FACTORY (l->data);
 
-    /* we only want to check those factories without a function */
-    if (gst_type_find_factory_has_function (factory))
-      continue;
-
     /* get the extension that this typefind factory can handle */
     ext = gst_type_find_factory_get_extensions (factory);
     if (ext == NULL)
@@ -1030,10 +1026,6 @@
 
     factory = GST_TYPE_FIND_FACTORY (l->data);
 
-    /* We only want to check those factories without a function */
-    if (gst_type_find_factory_has_function (factory))
-      continue;
-
     /* Get the caps that this typefind factory can handle */
     factory_caps = gst_type_find_factory_get_caps (factory);
     if (!factory_caps)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/libs/gst/helpers/ptp/args.rs 
new/gstreamer-1.28.5/libs/gst/helpers/ptp/args.rs
--- old/gstreamer-1.28.4/libs/gst/helpers/ptp/args.rs   2026-06-12 
14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/libs/gst/helpers/ptp/args.rs   2026-07-08 
23:42:39.000000000 +0200
@@ -17,11 +17,18 @@
 
 /// Parsed command-line arguments.
 #[derive(Debug)]
+#[allow(dead_code)]
 pub struct Args {
     pub interfaces: Vec<String>,
     pub verbose: bool,
     pub clock_id: u64,
     pub ttl: u32,
+    /// Named pipe path for stdin replacement (Windows named pipe IPC).
+    pub pipe_in: Option<String>,
+    /// Named pipe path for stdout replacement (Windows named pipe IPC).
+    pub pipe_out: Option<String>,
+    /// Named pipe path for stderr replacement (Windows named pipe IPC).
+    pub pipe_err: Option<String>,
 }
 
 /// Parse the command-line arguments.
@@ -30,6 +37,9 @@
     let mut verbose = false;
     let mut clock_id = 0;
     let mut ttl = 1;
+    let mut pipe_in = None;
+    let mut pipe_out = None;
+    let mut pipe_err = None;
 
     let mut args = env::args();
     // Skip executable name
@@ -56,6 +66,15 @@
                 let ttl_arg = args.next().context("No TTL following --ttl")?;
                 ttl = ttl_arg.parse::<u32>().context("Invalid TTL value")?;
             }
+            "--pipe-in" => {
+                pipe_in = Some(args.next().context("No pipe path following 
--pipe-in")?);
+            }
+            "--pipe-out" => {
+                pipe_out = Some(args.next().context("No pipe path following 
--pipe-out")?);
+            }
+            "--pipe-err" => {
+                pipe_err = Some(args.next().context("No pipe path following 
--pipe-err")?);
+            }
 
             arg => {
                 bail!("Unknown command-line argument {}", arg);
@@ -68,6 +87,9 @@
         verbose,
         clock_id,
         ttl,
+        pipe_in,
+        pipe_out,
+        pipe_err,
     };
 
     info!("Running with arguments {:#?}", args);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/libs/gst/helpers/ptp/ffi.rs 
new/gstreamer-1.28.5/libs/gst/helpers/ptp/ffi.rs
--- old/gstreamer-1.28.4/libs/gst/helpers/ptp/ffi.rs    2026-06-12 
14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/libs/gst/helpers/ptp/ffi.rs    2026-07-08 
23:42:39.000000000 +0200
@@ -868,8 +868,23 @@
 
         pub fn QueryPerformanceFrequency(lpfrequence: *mut i64) -> i32;
         pub fn QueryPerformanceCounter(lpperformancecount: *mut i64) -> i32;
+
+        pub fn CreateFileA(
+            lpfilename: *const u8,
+            dwdesiredaccess: u32,
+            dwsharemode: u32,
+            lpsecurityattributes: *const c_void,
+            dwcreationdisposition: u32,
+            dwflagsandattributes: u32,
+            htemplatefile: HANDLE,
+        ) -> HANDLE;
     }
 
+    pub const GENERIC_READ: u32 = 0x80000000;
+    pub const GENERIC_WRITE: u32 = 0x40000000;
+    pub const OPEN_EXISTING: u32 = 3;
+    pub const FILE_ATTRIBUTE_NORMAL: u32 = 0x80;
+
     pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
 
     #[link(name = "bcrypt")]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/libs/gst/helpers/ptp/io.rs 
new/gstreamer-1.28.5/libs/gst/helpers/ptp/io.rs
--- old/gstreamer-1.28.4/libs/gst/helpers/ptp/io.rs     2026-06-12 
14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/libs/gst/helpers/ptp/io.rs     2026-07-08 
23:42:39.000000000 +0200
@@ -469,7 +469,7 @@
         net::UdpSocket,
         os::windows::{io::AsRawSocket, raw::HANDLE},
         ptr,
-        sync::{Arc, Condvar, Mutex},
+        sync::{Arc, Condvar, Mutex, OnceLock},
         thread,
     };
 
@@ -688,6 +688,24 @@
             Self::new_internal(sockets, stdin, stdout)
         }
 
+        /// Create a new `Poll` instance using named pipes for stdin/stdout.
+        ///
+        /// This is used on Windows to communicate with the parent process via 
named
+        /// pipes instead of inherited anonymous pipes, which is required for 
running
+        /// in Session 0 (Windows services).
+        pub fn new_with_named_pipes(
+            sockets: Vec<(UdpSocket, UdpSocket)>,
+            pipe_in: &str,
+            pipe_out: &str,
+        ) -> Result<Self, Error> {
+            let stdin =
+                Stdin::open_named_pipe(pipe_in).context("Failed opening named 
pipe for stdin")?;
+            let stdout = Stdout::open_named_pipe(pipe_out)
+                .context("Failed opening named pipe for stdout")?;
+
+            Self::new_internal(sockets, stdin, stdout)
+        }
+
         #[cfg(test)]
         /// Create a new `Poll` instance for testing purposes.
         ///
@@ -1017,6 +1035,38 @@
             }
         }
 
+        /// Open a named pipe for reading (as a stdin replacement).
+        ///
+        /// This is used on Windows to communicate with the parent process via 
named
+        /// pipes instead of inherited anonymous pipes, which is required for 
running
+        /// in Session 0 (Windows services).
+        pub fn open_named_pipe(path: &str) -> Result<Self, Error> {
+            let path_cstr =
+                std::ffi::CString::new(path).context("Invalid named pipe path 
for stdin")?;
+            // SAFETY: CreateFileA with a valid null-terminated path returns a 
handle or
+            // INVALID_HANDLE_VALUE on error.
+            let handle = unsafe {
+                let h = CreateFileA(
+                    path_cstr.as_ptr() as *const u8,
+                    GENERIC_READ,
+                    0,
+                    ptr::null(),
+                    OPEN_EXISTING,
+                    FILE_ATTRIBUTE_NORMAL,
+                    ptr::null_mut(),
+                );
+                if h == INVALID_HANDLE_VALUE {
+                    bail!(
+                        source: io::Error::last_os_error(),
+                        "Failed to open named pipe for reading: {}",
+                        path
+                    );
+                }
+                h
+            };
+            Self::from_handle(handle)
+        }
+
         /// Thread function to signal readiness of stdin.
         ///
         /// This thread tries to read a single byte and buffers it, then 
signals an event
@@ -1178,6 +1228,38 @@
 
             Ok(Stdout(handle))
         }
+
+        /// Open a named pipe for writing (as a stdout replacement).
+        ///
+        /// This is used on Windows to communicate with the parent process via 
named
+        /// pipes instead of inherited anonymous pipes, which is required for 
running
+        /// in Session 0 (Windows services).
+        pub fn open_named_pipe(path: &str) -> Result<Self, Error> {
+            let path_cstr =
+                std::ffi::CString::new(path).context("Invalid named pipe path 
for stdout")?;
+            // SAFETY: CreateFileA with a valid null-terminated path returns a 
handle or
+            // INVALID_HANDLE_VALUE on error.
+            let handle = unsafe {
+                let h = CreateFileA(
+                    path_cstr.as_ptr() as *const u8,
+                    GENERIC_WRITE,
+                    0,
+                    ptr::null(),
+                    OPEN_EXISTING,
+                    FILE_ATTRIBUTE_NORMAL,
+                    ptr::null_mut(),
+                );
+                if h == INVALID_HANDLE_VALUE {
+                    bail!(
+                        source: io::Error::last_os_error(),
+                        "Failed to open named pipe for writing: {}",
+                        path
+                    );
+                }
+                h
+            };
+            Self::from_handle(handle)
+        }
     }
 
     impl Write for Stdout {
@@ -1227,29 +1309,60 @@
     /// cause interleaved output.
     pub struct Stderr(HANDLE);
 
+    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 {}
+
+    /// Lazily-initialized stderr handle. Set once, either by 
`init_named_pipe` (before any
+    /// logging) or on first `acquire()` call via the inherited standard error 
handle.
+    static STDERR_HANDLE: OnceLock<SyncHandle> = OnceLock::new();
+
     impl Stderr {
+        /// Open a named pipe for writing and use it as the stderr handle.
+        ///
+        /// This must be called before any logging so that the `OnceLock` is
+        /// populated with the named-pipe handle rather than the inherited one.
+        pub fn init_named_pipe(path: &str) -> Result<(), Error> {
+            let path_cstr =
+                std::ffi::CString::new(path).context("Invalid named pipe path 
for stderr")?;
+            // SAFETY: CreateFileA with a valid null-terminated path returns a 
handle or
+            // INVALID_HANDLE_VALUE on error.
+            let handle = unsafe {
+                let h = CreateFileA(
+                    path_cstr.as_ptr() as *const u8,
+                    GENERIC_WRITE,
+                    0,
+                    ptr::null(),
+                    OPEN_EXISTING,
+                    FILE_ATTRIBUTE_NORMAL,
+                    ptr::null_mut(),
+                );
+                if h == INVALID_HANDLE_VALUE {
+                    bail!(
+                        source: io::Error::last_os_error(),
+                        "Failed to open named pipe for stderr: {}",
+                        path
+                    );
+                }
+                h
+            };
+            let _ = STDERR_HANDLE.set(SyncHandle(handle));
+            Ok(())
+        }
+
         #[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(|| {
+            let sync_handle = STDERR_HANDLE.get_or_init(|| {
                 // 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;
+                        return SyncHandle(INVALID_HANDLE_VALUE);
                     } else if handle == INVALID_HANDLE_VALUE {
-                        return;
+                        return SyncHandle(INVALID_HANDLE_VALUE);
                     }
 
                     handle
@@ -1268,19 +1381,13 @@
                         let _ = SetConsoleMode(handle, 0);
                     }
                 } else if type_ != FILE_TYPE_PIPE {
-                    return;
+                    return SyncHandle(INVALID_HANDLE_VALUE);
                 }
 
-                // SAFETY: Only accessed in this function and multiple mutable 
accesses are
-                // prevented by the `Once`.
-                unsafe {
-                    STDERR.0 = handle;
-                }
+                SyncHandle(handle)
             });
 
-            // SAFETY: Only accesses immutably here and all mutable accesses 
are serialized above
-            // by the `Once`.
-            Stderr(unsafe { STDERR.0 })
+            Stderr(sync_handle.0)
         }
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/libs/gst/helpers/ptp/main.rs 
new/gstreamer-1.28.5/libs/gst/helpers/ptp/main.rs
--- old/gstreamer-1.28.4/libs/gst/helpers/ptp/main.rs   2026-06-12 
14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/libs/gst/helpers/ptp/main.rs   2026-07-08 
23:42:39.000000000 +0200
@@ -119,6 +119,11 @@
 fn run() -> Result<(), Error> {
     let args = args::parse_args().context("Failed parsing commandline 
parameters")?;
 
+    #[cfg(windows)]
+    if let Some(ref pipe_err) = args.pipe_err {
+        io::Stderr::init_named_pipe(pipe_err).context("Failed initializing 
stderr named pipe")?;
+    }
+
     let ifaces = list_interfaces(&args).context("Failed listing interfaces")?;
 
     let mut sockets = vec![];
@@ -158,6 +163,15 @@
 
     privileges::drop().context("Failed dropping privileges")?;
 
+    #[cfg(windows)]
+    let mut poll = if let (Some(ref pipe_in), Some(ref pipe_out)) = 
(&args.pipe_in, &args.pipe_out)
+    {
+        io::Poll::new_with_named_pipes(sockets, pipe_in, pipe_out)
+            .context("Failed creating poller with named pipes")?
+    } else {
+        io::Poll::new(sockets).context("Failed creating poller")?
+    };
+    #[cfg(not(windows))]
     let mut poll = io::Poll::new(sockets).context("Failed creating poller")?;
 
     // Write clock ID first
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/libs/gst/net/gstptpclock.c 
new/gstreamer-1.28.5/libs/gst/net/gstptpclock.c
--- old/gstreamer-1.28.4/libs/gst/net/gstptpclock.c     2026-06-12 
14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/libs/gst/net/gstptpclock.c     2026-07-08 
23:42:39.000000000 +0200
@@ -66,6 +66,8 @@
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <processthreadsapi.h>  /* GetCurrentProcessId */
+#include <gio/gwin32inputstream.h>
+#include <gio/gwin32outputstream.h>
 #endif
 
 #ifdef HAVE_UNISTD_H
@@ -2477,10 +2479,12 @@
       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);
+  if (stderr_pipe) {
+    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);
@@ -2769,6 +2773,11 @@
   gst_structure_get_uint (config, "ttl", &ttl);
   argc += 2;
 
+#ifdef G_OS_WIN32
+  /* --pipe-in <name> --pipe-out <name> --pipe-err <name> for named pipe IPC */
+  argc += 6;
+#endif
+
   // 3 for: executable, -v and NULL
   argv = g_new0 (gchar *, argc + 3);
   argc_c = 0;
@@ -2858,6 +2867,252 @@
     argv[argc_c++] = g_strdup ("-v");
   }
 
+#ifdef G_OS_WIN32
+  /* On Windows, use named pipes instead of inherited anonymous pipes for
+   * stdin/stdout communication with the helper process. This avoids depending
+   * on handle inheritance via CreateProcess(bInheritHandles=TRUE) which is
+   * unreliable in Session 0 (Windows services). */
+  {
+    HANDLE h_stdin_wr = INVALID_HANDLE_VALUE;
+    HANDLE h_stdout_rd = INVALID_HANDLE_VALUE;
+    HANDLE h_stderr_rd = INVALID_HANDLE_VALUE;
+    gchar *pipe_name_in = NULL;
+    gchar *pipe_name_out = NULL;
+    gchar *pipe_name_err = NULL;
+    guint32 pipe_id;
+    /* Timeout for the helper to connect to the named pipes */
+    const DWORD connect_timeout_ms = 30000;
+
+    pipe_id = g_random_int ();
+
+    /* Create named pipe for stdin (parent writes, child reads).
+     * Use FILE_FLAG_OVERLAPPED so ConnectNamedPipe can be awaited
+     * with a timeout instead of blocking indefinitely. */
+    pipe_name_in = g_strdup_printf ("\\\\.\\pipe\\gst-ptp-%lu-%08x-in",
+        (gulong) GetCurrentProcessId (), pipe_id);
+    h_stdin_wr = CreateNamedPipeA (pipe_name_in,
+        PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
+        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+        1, 4096, 4096, 5000, NULL);
+    if (h_stdin_wr == INVALID_HANDLE_VALUE) {
+      guint last_err = GetLastError ();
+      gchar *msg = g_win32_error_message (last_err);
+      GST_ERROR ("Failed to create named pipe for stdin: 0x%x (%s)",
+          last_err, msg);
+      g_free (msg);
+      g_free (pipe_name_in);
+      ret = FALSE;
+      supported = FALSE;
+      goto done;
+    }
+
+    /* Create named pipe for stdout (child writes, parent reads) */
+    pipe_name_out = g_strdup_printf ("\\\\.\\pipe\\gst-ptp-%lu-%08x-out",
+        (gulong) GetCurrentProcessId (), pipe_id);
+    h_stdout_rd = CreateNamedPipeA (pipe_name_out,
+        PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+        1, 4096, 4096, 5000, NULL);
+    if (h_stdout_rd == INVALID_HANDLE_VALUE) {
+      guint last_err = GetLastError ();
+      gchar *msg = g_win32_error_message (last_err);
+      GST_ERROR ("Failed to create named pipe for stdout: 0x%x (%s)",
+          last_err, msg);
+      g_free (msg);
+      g_free (pipe_name_out);
+      g_free (pipe_name_in);
+      CloseHandle (h_stdin_wr);
+      ret = FALSE;
+      supported = FALSE;
+      goto done;
+    }
+
+    /* Create named pipe for stderr (child writes, parent reads) */
+    pipe_name_err = g_strdup_printf ("\\\\.\\pipe\\gst-ptp-%lu-%08x-err",
+        (gulong) GetCurrentProcessId (), pipe_id);
+    h_stderr_rd = CreateNamedPipeA (pipe_name_err,
+        PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+        1, 4096, 4096, 5000, NULL);
+    if (h_stderr_rd == INVALID_HANDLE_VALUE) {
+      guint last_err = GetLastError ();
+      gchar *msg = g_win32_error_message (last_err);
+      GST_ERROR ("Failed to create named pipe for stderr: 0x%x (%s)",
+          last_err, msg);
+      g_free (msg);
+      g_free (pipe_name_err);
+      g_free (pipe_name_out);
+      g_free (pipe_name_in);
+      CloseHandle (h_stdout_rd);
+      CloseHandle (h_stdin_wr);
+      ret = FALSE;
+      supported = FALSE;
+      goto done;
+    }
+
+    argv[argc_c++] = g_strdup ("--pipe-in");
+    argv[argc_c++] = pipe_name_in;      /* ownership transferred to argv */
+    argv[argc_c++] = g_strdup ("--pipe-out");
+    argv[argc_c++] = pipe_name_out;     /* ownership transferred to argv */
+    argv[argc_c++] = g_strdup ("--pipe-err");
+    argv[argc_c++] = pipe_name_err;     /* ownership transferred to argv */
+
+    ptp_helper_process =
+        g_subprocess_newv ((const gchar * const *) argv,
+        G_SUBPROCESS_FLAGS_NONE, &err);
+    if (!ptp_helper_process) {
+      GST_ERROR ("Failed to start ptp helper process: %s", err->message);
+      g_clear_error (&err);
+      CloseHandle (h_stdin_wr);
+      CloseHandle (h_stdout_rd);
+      CloseHandle (h_stderr_rd);
+      ret = FALSE;
+      supported = FALSE;
+      goto done;
+    }
+
+    /* Wait for the child to connect to the named pipes using overlapped I/O
+     * with a timeout, so we don't block indefinitely if the helper never
+     * connects. */
+    {
+      OVERLAPPED ov_in = { 0, };
+      OVERLAPPED ov_out = { 0, };
+      OVERLAPPED ov_err = { 0, };
+      gboolean stdin_connected = FALSE;
+      gboolean stdout_connected = FALSE;
+      gboolean stderr_connected = FALSE;
+      DWORD wait_ret;
+
+      ov_in.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+      ov_out.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+      ov_err.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+
+      /* Start async connect for stdin pipe */
+      if (ConnectNamedPipe (h_stdin_wr, &ov_in)) {
+        stdin_connected = TRUE;
+      } else {
+        guint last_err = GetLastError ();
+        if (last_err == ERROR_PIPE_CONNECTED) {
+          stdin_connected = TRUE;
+        } else if (last_err != ERROR_IO_PENDING) {
+          gchar *msg = g_win32_error_message (last_err);
+          GST_ERROR ("ConnectNamedPipe (stdin) failed: 0x%x (%s)",
+              last_err, msg);
+          g_free (msg);
+          CloseHandle (ov_in.hEvent);
+          CloseHandle (ov_out.hEvent);
+          CloseHandle (ov_err.hEvent);
+          CloseHandle (h_stdin_wr);
+          CloseHandle (h_stdout_rd);
+          CloseHandle (h_stderr_rd);
+          ret = FALSE;
+          supported = FALSE;
+          goto done;
+        }
+      }
+
+      /* Start async connect for stdout pipe */
+      if (ConnectNamedPipe (h_stdout_rd, &ov_out)) {
+        stdout_connected = TRUE;
+      } else {
+        guint last_err = GetLastError ();
+        if (last_err == ERROR_PIPE_CONNECTED) {
+          stdout_connected = TRUE;
+        } else if (last_err != ERROR_IO_PENDING) {
+          gchar *msg = g_win32_error_message (last_err);
+          GST_ERROR ("ConnectNamedPipe (stdout) failed: 0x%x (%s)",
+              last_err, msg);
+          g_free (msg);
+          if (!stdin_connected)
+            CancelIo (h_stdin_wr);
+          CloseHandle (ov_in.hEvent);
+          CloseHandle (ov_out.hEvent);
+          CloseHandle (ov_err.hEvent);
+          CloseHandle (h_stdin_wr);
+          CloseHandle (h_stdout_rd);
+          CloseHandle (h_stderr_rd);
+          ret = FALSE;
+          supported = FALSE;
+          goto done;
+        }
+      }
+
+      /* Start async connect for stderr pipe */
+      if (ConnectNamedPipe (h_stderr_rd, &ov_err)) {
+        stderr_connected = TRUE;
+      } else {
+        guint last_err = GetLastError ();
+        if (last_err == ERROR_PIPE_CONNECTED) {
+          stderr_connected = TRUE;
+        } else if (last_err != ERROR_IO_PENDING) {
+          gchar *msg = g_win32_error_message (last_err);
+          GST_ERROR ("ConnectNamedPipe (stderr) failed: 0x%x (%s)",
+              last_err, msg);
+          g_free (msg);
+          if (!stdin_connected)
+            CancelIo (h_stdin_wr);
+          if (!stdout_connected)
+            CancelIo (h_stdout_rd);
+          CloseHandle (ov_in.hEvent);
+          CloseHandle (ov_out.hEvent);
+          CloseHandle (ov_err.hEvent);
+          CloseHandle (h_stdin_wr);
+          CloseHandle (h_stdout_rd);
+          CloseHandle (h_stderr_rd);
+          ret = FALSE;
+          supported = FALSE;
+          goto done;
+        }
+      }
+
+      /* Wait for all pending connects */
+      {
+        HANDLE wait_events[3];
+        DWORD wait_count = 0;
+
+        if (!stdin_connected)
+          wait_events[wait_count++] = ov_in.hEvent;
+        if (!stdout_connected)
+          wait_events[wait_count++] = ov_out.hEvent;
+        if (!stderr_connected)
+          wait_events[wait_count++] = ov_err.hEvent;
+
+        if (wait_count > 0) {
+          wait_ret = WaitForMultipleObjects (wait_count, wait_events,
+              TRUE, connect_timeout_ms);
+          if (wait_ret == WAIT_TIMEOUT || wait_ret == WAIT_FAILED) {
+            GST_ERROR ("Timed out waiting for helper to connect to pipes");
+            if (!stdin_connected)
+              CancelIo (h_stdin_wr);
+            if (!stdout_connected)
+              CancelIo (h_stdout_rd);
+            if (!stderr_connected)
+              CancelIo (h_stderr_rd);
+            CloseHandle (ov_in.hEvent);
+            CloseHandle (ov_out.hEvent);
+            CloseHandle (ov_err.hEvent);
+            CloseHandle (h_stdin_wr);
+            CloseHandle (h_stdout_rd);
+            CloseHandle (h_stderr_rd);
+            ret = FALSE;
+            supported = FALSE;
+            goto done;
+          }
+        }
+      }
+
+      CloseHandle (ov_in.hEvent);
+      CloseHandle (ov_out.hEvent);
+      CloseHandle (ov_err.hEvent);
+    }
+
+    /* Create GIO streams from the named pipe handles.
+     * The streams take ownership of the handles (close_handle=TRUE). */
+    stdin_pipe = G_OUTPUT_STREAM (g_win32_output_stream_new (h_stdin_wr, 
TRUE));
+    stdout_pipe = G_INPUT_STREAM (g_win32_input_stream_new (h_stdout_rd, 
TRUE));
+    stderr_pipe = G_INPUT_STREAM (g_win32_input_stream_new (h_stderr_rd, 
TRUE));
+  }
+#else
   ptp_helper_process =
       g_subprocess_newv ((const gchar * const *) argv,
       G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE |
@@ -2885,6 +3140,7 @@
     supported = FALSE;
     goto done;
   }
+#endif
 
   delay_req_rand = g_rand_new ();
   observation_system_clock =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gstreamer-1.28.4/meson.build 
new/gstreamer-1.28.5/meson.build
--- old/gstreamer-1.28.4/meson.build    2026-06-12 14:19:43.000000000 +0200
+++ new/gstreamer-1.28.5/meson.build    2026-07-08 23:42:39.000000000 +0200
@@ -1,5 +1,5 @@
 project('gstreamer', 'c',
-  version : '1.28.4',
+  version : '1.28.5',
   meson_version : '>= 1.4',
   default_options : [ 'warning_level=1',
                       'buildtype=debugoptimized',
@@ -569,7 +569,8 @@
 gobject_dep = dependency('gobject-2.0')
 gmodule_dep = dependency('gmodule-no-export-2.0')
 if host_system == 'windows'
-    gio_dep = dependency('gio-2.0')
+    gio_dep = [dependency('gio-2.0'),
+               dependency('gio-windows-2.0')]
 else
     gio_dep = [dependency('gio-2.0'),
                dependency('gio-unix-2.0')]

++++++ gstreamer.obsinfo ++++++
--- /var/tmp/diff_new_pack.gDyL00/_old  2026-07-12 16:21:09.464003734 +0200
+++ /var/tmp/diff_new_pack.gDyL00/_new  2026-07-12 16:21:09.472004007 +0200
@@ -1,5 +1,5 @@
 name: gstreamer
-version: 1.28.4
-mtime: 1781266783
-commit: b46f881eaa8126eddfd21b5ae5512f8d4ff36255
+version: 1.28.5
+mtime: 1783546959
+commit: 727ceb91886862d200f423baf36cde2bb7ce5b4d
 

Reply via email to