tsmux: finalize PCR timing for complete accuracy
authorMathieu Duponchelle <mathieu@centricular.com>
Thu, 11 Mar 2021 17:21:11 +0000 (18:21 +0100)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Thu, 18 Mar 2021 13:57:27 +0000 (13:57 +0000)
In order to always insert a PCR packet right on time, we need to
check whether one is needed when outputting any packet, not only
a packet for the PCR stream. Most of the PCR packets will remain
data-carrying packets, but as a last resort we may insert stuffing
packets on the PCR stream.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2073>

gst/mpegtsmux/tsmux/tsmux.c

index 5a13106091df7689964b956812770de2da8f8e0b..186b660d564e21cc54d6b225156155af3637ae1d 100644 (file)
 static gboolean tsmux_write_pat (TsMux * mux);
 static gboolean tsmux_write_pmt (TsMux * mux, TsMuxProgram * program);
 static gboolean tsmux_write_scte_null (TsMux * mux, TsMuxProgram * program);
+static gint64 get_next_pcr (TsMux * mux, gint64 cur_ts);
+static gint64 get_current_pcr (TsMux * mux, gint64 cur_ts);
+static gint64 write_new_pcr (TsMux * mux, TsMuxStream * stream, gint64 cur_pcr,
+    gint64 next_pcr);
+static gboolean tsmux_write_ts_header (TsMux * mux, guint8 * buf,
+    TsMuxPacketInfo * pi, guint * payload_len_out, guint * payload_offset_out,
+    guint stream_avail);
+
 static void
 tsmux_section_free (TsMuxSection * section)
 {
@@ -808,9 +816,44 @@ tsmux_packet_out (TsMux * mux, GstBuffer * buf, gint64 pcr)
     GST_BUFFER_PTS (buf) =
         gst_util_uint64_scale (mux->n_bytes * 8, GST_SECOND, mux->bitrate);
 
+  if (mux->bitrate && mux->first_pcr_ts != G_MININT64) {
+    GList *cur;
+
+    for (cur = mux->programs; cur; cur = cur->next) {
+      TsMuxProgram *program = (TsMuxProgram *) cur->data;
+      TsMuxStream *stream = program->pcr_stream;
+      gint64 cur_pcr = get_current_pcr (mux, 0);
+      gint64 next_pcr = get_next_pcr (mux, 0);
+
+      gint64 new_pcr = write_new_pcr (mux, stream, cur_pcr, next_pcr);
+
+      if (new_pcr != -1) {
+        GstBuffer *buf = NULL;
+        GstMapInfo map;
+        guint payload_len, payload_offs;
+
+        if (!tsmux_get_buffer (mux, &buf)) {
+          goto error;
+        }
+
+        gst_buffer_map (buf, &map, GST_MAP_READ);
+        tsmux_write_ts_header (mux, map.data, &stream->pi, &payload_len,
+            &payload_offs, 0);
+        gst_buffer_unmap (buf, &map);
+
+        stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
+        if (!tsmux_packet_out (mux, buf, new_pcr))
+          goto error;
+      }
+    }
+  }
+
   mux->n_bytes += gst_buffer_get_size (buf);
 
   return mux->write_func (buf, mux->write_func_data, pcr);
+
+error:
+  return FALSE;
 }
 
 /*