basetsmux: Support for caps changes
authorVivia Nikolaidou <vivia@ahiru.eu>
Fri, 30 Oct 2020 14:02:22 +0000 (16:02 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Mon, 18 Oct 2021 15:37:41 +0000 (15:37 +0000)
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/981>

subprojects/gst-plugins-bad/gst/mpegtsmux/gstbasetsmux.c

index ba899d1..e312ff0 100644 (file)
@@ -370,9 +370,9 @@ release_buffer_cb (guint8 * data, void *user_data)
 }
 
 static GstFlowReturn
-gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
+gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
+    GstBaseTsMuxPad * ts_pad, GstCaps * caps)
 {
-  GstCaps *caps;
   GstStructure *s;
   guint st = TSMUX_ST_RESERVED;
   const gchar *mt;
@@ -386,15 +386,9 @@ gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
   const gchar *stream_format = NULL;
   const char *interlace_mode = NULL;
 
-  caps = gst_pad_get_current_caps (GST_PAD (ts_pad));
-  if (caps == NULL) {
-    GST_DEBUG_OBJECT (ts_pad, "Sink pad caps were not set before pushing");
-    return GST_FLOW_NOT_NEGOTIATED;
-  }
-
   GST_DEBUG_OBJECT (ts_pad,
-      "Creating stream with PID 0x%04x for caps %" GST_PTR_FORMAT,
-      ts_pad->pid, caps);
+      "%s stream with PID 0x%04x for caps %" GST_PTR_FORMAT,
+      ts_pad->stream ? "Recreating" : "Creating", ts_pad->pid, caps);
 
   s = gst_caps_get_structure (caps, 0);
 
@@ -403,6 +397,9 @@ gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
   if (value != NULL)
     codec_data = gst_value_get_buffer (value);
 
+  g_clear_pointer (&ts_pad->codec_data, gst_buffer_unref);
+  ts_pad->prepare_func = NULL;
+
   stream_format = gst_structure_get_string (s, "stream-format");
 
   if (strcmp (mt, "video/x-dirac") == 0) {
@@ -470,6 +467,10 @@ gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
             GST_ERROR_OBJECT (mux, "Need codec_data for raw MPEG-4 AAC");
             goto not_negotiated;
           }
+        } else if (codec_data) {
+          ts_pad->codec_data = gst_buffer_ref (codec_data);
+        } else {
+          ts_pad->codec_data = NULL;
         }
         break;
       }
@@ -675,10 +676,19 @@ gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
     goto error;
   }
 
-  ts_pad->stream =
-      tsmux_create_stream (mux->tsmux, st, ts_pad->pid, ts_pad->language);
-  if (ts_pad->stream == NULL)
+  if (ts_pad->stream && st != ts_pad->stream->stream_type) {
+    GST_ELEMENT_ERROR (mux, STREAM, MUX,
+        ("Stream type change from %02x to %02x not supported",
+            ts_pad->stream->stream_type, st), NULL);
     goto error;
+  }
+
+  if (ts_pad->stream == NULL) {
+    ts_pad->stream =
+        tsmux_create_stream (mux->tsmux, st, ts_pad->pid, ts_pad->language);
+    if (ts_pad->stream == NULL)
+      goto error;
+  }
 
   interlace_mode = gst_structure_get_string (s, "interlace-mode");
   gst_structure_get_int (s, "rate", &ts_pad->stream->audio_sampling);
@@ -707,18 +717,14 @@ gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
   ts_pad->stream->opus_channel_config_code = opus_channel_config_code;
 
   tsmux_stream_set_buffer_release_func (ts_pad->stream, release_buffer_cb);
-  tsmux_program_add_stream (ts_pad->prog, ts_pad->stream);
 
-  gst_caps_unref (caps);
   return GST_FLOW_OK;
 
   /* ERRORS */
 not_negotiated:
-  gst_caps_unref (caps);
   return GST_FLOW_NOT_NEGOTIATED;
 
 error:
-  gst_caps_unref (caps);
   return GST_FLOW_ERROR;
 }
 
@@ -731,6 +737,27 @@ is_valid_pmt_pid (guint16 pmt_pid)
 }
 
 static GstFlowReturn
+gst_base_ts_mux_create_stream (GstBaseTsMux * mux, GstBaseTsMuxPad * ts_pad)
+{
+  GstCaps *caps = gst_pad_get_current_caps (GST_PAD (ts_pad));
+  GstFlowReturn ret;
+
+  if (caps == NULL) {
+    GST_DEBUG_OBJECT (ts_pad, "Sink pad caps were not set before pushing");
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
+  ret = gst_base_ts_mux_create_or_update_stream (mux, ts_pad, caps);
+  gst_caps_unref (caps);
+
+  if (ret == GST_FLOW_OK) {
+    tsmux_program_add_stream (ts_pad->prog, ts_pad->stream);
+  }
+
+  return ret;
+}
+
+static GstFlowReturn
 gst_base_ts_mux_create_pad_stream (GstBaseTsMux * mux, GstPad * pad)
 {
   GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (pad);
@@ -1863,6 +1890,41 @@ gst_base_ts_mux_sink_event (GstAggregator * agg, GstAggregatorPad * agg_pad,
   gboolean forward = TRUE;
 
   switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+      GstFlowReturn ret;
+      GList *cur;
+
+      if (ts_pad->stream == NULL)
+        break;
+
+      forward = FALSE;
+
+      gst_event_parse_caps (event, &caps);
+      if (!caps || !gst_caps_is_fixed (caps))
+        break;
+
+      ret = gst_base_ts_mux_create_or_update_stream (mux, ts_pad, caps);
+      if (ret != GST_FLOW_OK)
+        break;
+
+      mux->tsmux->pat_changed = TRUE;
+      mux->tsmux->si_changed = TRUE;
+      tsmux_resend_pat (mux->tsmux);
+      tsmux_resend_si (mux->tsmux);
+
+      /* output PMT for each program */
+      for (cur = mux->tsmux->programs; cur; cur = cur->next) {
+        TsMuxProgram *program = (TsMuxProgram *) cur->data;
+
+        program->pmt_changed = TRUE;
+        tsmux_resend_pmt (program);
+      }
+
+      res = TRUE;
+      break;
+    }
     case GST_EVENT_CUSTOM_DOWNSTREAM:
     {
       GstClockTime timestamp, stream_time, running_time;