tsdemux: switch SCTE 35 sections handling to a passthrough model

Instead of modifying the splice times in the incoming sections
to running time and expecting eg mpegtsmux to convert those back
to its local PES time domain, which might be impossible when
those splice times are encrypted or the specification is extended,
transmit the needed information to the muxer as separate fields in
the event:

* A pts offset field can be used by the muxer in order to calculate
  a final pts_adjustment

* A rtime_map can be used by the muxer to determine the correct
  running times at which it should request keyframes

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/913>
This commit is contained in:
Mathieu Duponchelle 2021-04-23 01:15:08 +02:00 committed by GStreamer Marge Bot
parent 1477d76b7d
commit 4af003bc02
2 changed files with 52 additions and 47 deletions

View file

@ -479,6 +479,8 @@ gst_ts_demux_reset (MpegTSBase * base)
demux->last_seek_offset = -1; demux->last_seek_offset = -1;
demux->program_generation = 0; demux->program_generation = 0;
demux->mpeg_pts_offset = 0;
} }
static void static void
@ -1080,25 +1082,6 @@ push_event (MpegTSBase * base, GstEvent * event)
return TRUE; return TRUE;
} }
static GstMpegtsSCTESpliceEvent *
copy_splice (GstMpegtsSCTESpliceEvent * splice)
{
return g_boxed_copy (GST_TYPE_MPEGTS_SCTE_SPLICE_EVENT, splice);
}
static GstMpegtsSCTESIT *
deep_copy_sit (const GstMpegtsSCTESIT * sit)
{
GstMpegtsSCTESIT *sit_copy = g_boxed_copy (GST_TYPE_MPEGTS_SCTE_SIT, sit);
GPtrArray *splices_copy =
g_ptr_array_copy (sit_copy->splices, (GCopyFunc) copy_splice, NULL);
g_ptr_array_unref (sit_copy->splices);
sit_copy->splices = splices_copy;
return sit_copy;
}
static void static void
handle_psi (MpegTSBase * base, GstMpegtsSection * section) handle_psi (MpegTSBase * base, GstMpegtsSection * section)
{ {
@ -1123,48 +1106,58 @@ handle_psi (MpegTSBase * base, GstMpegtsSection * section)
* times translated from local time to running time */ * times translated from local time to running time */
if (forward) { if (forward) {
GstEvent *event; GstEvent *event;
GstStructure *s;
GstStructure *rtime_map;
GstClockTime pts; GstClockTime pts;
guint i = 0; guint i = 0;
const GstMpegtsSCTESIT *sit = gst_mpegts_section_get_scte_sit (section); GstMpegtsSection *new_section =
GstMpegtsSCTESIT *sit_copy = deep_copy_sit (sit); (GstMpegtsSection *) gst_mini_object_copy ((GstMiniObject *) section);
GstMpegtsSection *new_section; GstMpegtsSCTESIT *sit =
(GstMpegtsSCTESIT *) gst_mpegts_section_get_scte_sit (new_section);
if (sit_copy->splice_time_specified) { rtime_map = gst_structure_new_empty ("running-time-map");
pts =
mpegts_packetizer_pts_to_ts (base->packetizer,
MPEGTIME_TO_GSTTIME (sit_copy->splice_time +
sit_copy->pts_adjustment), demux->program->pcr_pid);
sit_copy->splice_time =
gst_segment_to_running_time (&base->out_segment, GST_FORMAT_TIME,
pts);
}
for (i = 0; i < sit_copy->splices->len; i++) { if (sit->fully_parsed) {
GstMpegtsSCTESpliceEvent *sevent = if (sit->splice_time_specified) {
g_ptr_array_index (sit_copy->splices, i);
if (sevent->program_splice_time_specified) {
pts = pts =
mpegts_packetizer_pts_to_ts (base->packetizer, mpegts_packetizer_pts_to_ts (base->packetizer,
MPEGTIME_TO_GSTTIME (sevent->program_splice_time), MPEGTIME_TO_GSTTIME (sit->splice_time +
demux->program->pcr_pid); sit->pts_adjustment), demux->program->pcr_pid);
sevent->program_splice_time = gst_structure_set (rtime_map, "splice-time", G_TYPE_UINT64,
gst_segment_to_running_time (&base->out_segment, GST_FORMAT_TIME, gst_segment_to_running_time (&base->out_segment, GST_FORMAT_TIME,
pts); pts), NULL);
if (sevent->duration_flag) { }
sevent->break_duration =
MPEGTIME_TO_GSTTIME (sevent->break_duration); for (i = 0; i < sit->splices->len; i++) {
gchar *field_name;
GstMpegtsSCTESpliceEvent *sevent =
g_ptr_array_index (sit->splices, i);
if (sevent->program_splice_time_specified) {
pts =
mpegts_packetizer_pts_to_ts (base->packetizer,
MPEGTIME_TO_GSTTIME (sevent->program_splice_time +
sit->pts_adjustment), demux->program->pcr_pid);
field_name =
g_strdup_printf ("event-%u-splice-time",
sevent->splice_event_id);
gst_structure_set (rtime_map, field_name, G_TYPE_UINT64,
gst_segment_to_running_time (&base->out_segment,
GST_FORMAT_TIME, pts), NULL);
g_free (field_name);
} }
} }
} }
sit_copy->pts_adjustment = 0;
new_section = gst_mpegts_section_from_scte_sit (sit_copy, section->pid);
event = gst_event_new_mpegts_section (new_section); event = gst_event_new_mpegts_section (new_section);
gst_mpegts_section_unref (new_section); gst_mpegts_section_unref (new_section);
s = gst_event_writable_structure (event);
gst_structure_set (s, "mpeg-pts-offset", G_TYPE_UINT64,
demux->mpeg_pts_offset, "running-time-map", GST_TYPE_STRUCTURE,
rtime_map, NULL);
gst_structure_free (rtime_map);
push_event (base, event); push_event (base, event);
} }
} }
@ -2304,6 +2297,7 @@ gst_ts_demux_record_pts (GstTSDemux * demux, TSDemuxStream * stream,
guint64 pts, guint64 offset) guint64 pts, guint64 offset)
{ {
MpegTSBaseStream *bs = (MpegTSBaseStream *) stream; MpegTSBaseStream *bs = (MpegTSBaseStream *) stream;
MpegTSBase *base = GST_MPEGTS_BASE (demux);
stream->raw_pts = pts; stream->raw_pts = pts;
if (pts == -1) { if (pts == -1) {
@ -2319,6 +2313,12 @@ gst_ts_demux_record_pts (GstTSDemux * demux, TSDemuxStream * stream,
mpegts_packetizer_pts_to_ts (MPEG_TS_BASE_PACKETIZER (demux), mpegts_packetizer_pts_to_ts (MPEG_TS_BASE_PACKETIZER (demux),
MPEGTIME_TO_GSTTIME (pts), demux->program->pcr_pid); MPEGTIME_TO_GSTTIME (pts), demux->program->pcr_pid);
if (base->out_segment.format == GST_FORMAT_TIME) {
demux->mpeg_pts_offset =
(GSTTIME_TO_MPEGTIME (gst_segment_to_running_time (&base->out_segment,
GST_FORMAT_TIME, stream->pts)) - pts) & 0x1ffffffff;
}
GST_LOG ("pid 0x%04x Stored PTS %" G_GUINT64_FORMAT, bs->pid, stream->pts); GST_LOG ("pid 0x%04x Stored PTS %" G_GUINT64_FORMAT, bs->pid, stream->pts);
if (G_UNLIKELY (demux->emit_statistics)) { if (G_UNLIKELY (demux->emit_statistics)) {

View file

@ -102,6 +102,11 @@ struct _GstTSDemux
/* Used when seeking for a keyframe to go backward in the stream */ /* Used when seeking for a keyframe to go backward in the stream */
guint64 last_seek_offset; guint64 last_seek_offset;
/* The current difference between PES PTSs and our output running times,
* in the MPEG time domain. This is used for potentially updating
* SCTE 35 sections' pts_adjustment further down the line (eg mpegtsmux) */
guint64 mpeg_pts_offset;
}; };
struct _GstTSDemuxClass struct _GstTSDemuxClass