tsdemux: Expose send-scte35-events property

When enabled, SCTE 35 sections (eg ad placement opportunities)
are forwarded as events donwstream.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/913>
This commit is contained in:
Mathieu Duponchelle 2021-04-06 00:36:43 +02:00 committed by GStreamer Marge Bot
parent b2718ed6cf
commit 1ca08bff57
3 changed files with 128 additions and 0 deletions

View file

@ -210818,6 +210818,18 @@
"readable": true,
"type": "gint",
"writable": true
},
"send-scte35-events": {
"blurb": "Whether SCTE 35 sections should be forwarded as events",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "false",
"mutable": "null",
"readable": true,
"type": "gboolean",
"writable": true
}
},
"rank": "primary",

View file

@ -297,6 +297,7 @@ enum
PROP_PROGRAM_NUMBER,
PROP_EMIT_STATS,
PROP_LATENCY,
PROP_SEND_SCTE35_EVENTS,
/* FILL ME */
};
@ -340,6 +341,7 @@ static gboolean push_event (MpegTSBase * base, GstEvent * event);
static gboolean sink_query (MpegTSBase * base, GstQuery * query);
static void gst_ts_demux_check_and_sync_streams (GstTSDemux * demux,
GstClockTime time);
static void handle_psi (MpegTSBase * base, GstMpegtsSection * section);
static void
_extra_init (void)
@ -395,6 +397,22 @@ gst_ts_demux_class_init (GstTSDemuxClass * klass)
"Emit messages for every pcr/opcr/pts/dts", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* mpegtsdemux:send-scte35-events:
*
* Whether SCTE 35 sections should be forwarded as events.
*
* When forwarding those, potential splice times are converted
* to running time, and can be used by a downstream muxer to reinject
* the sections.
*
* Since: 1.20
*/
g_object_class_install_property (gobject_class, PROP_SEND_SCTE35_EVENTS,
g_param_spec_boolean ("send-scte35-events", "Send SCTE 35 events",
"Whether SCTE 35 sections should be forwarded as events", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LATENCY,
g_param_spec_int ("latency", "Latency",
"Latency to add for smooth demuxing (in ms)", -1,
@ -422,6 +440,7 @@ gst_ts_demux_class_init (GstTSDemuxClass * klass)
ts_class->reset = GST_DEBUG_FUNCPTR (gst_ts_demux_reset);
ts_class->push = GST_DEBUG_FUNCPTR (gst_ts_demux_push);
ts_class->push_event = GST_DEBUG_FUNCPTR (push_event);
ts_class->handle_psi = GST_DEBUG_FUNCPTR (handle_psi);
ts_class->sink_query = GST_DEBUG_FUNCPTR (sink_query);
ts_class->program_started = GST_DEBUG_FUNCPTR (gst_ts_demux_program_started);
ts_class->program_stopped = GST_DEBUG_FUNCPTR (gst_ts_demux_program_stopped);
@ -495,6 +514,9 @@ gst_ts_demux_set_property (GObject * object, guint prop_id,
case PROP_EMIT_STATS:
demux->emit_statistics = g_value_get_boolean (value);
break;
case PROP_SEND_SCTE35_EVENTS:
demux->send_scte35_events = g_value_get_boolean (value);
break;
case PROP_LATENCY:
demux->latency = g_value_get_int (value);
break;
@ -516,6 +538,9 @@ gst_ts_demux_get_property (GObject * object, guint prop_id,
case PROP_EMIT_STATS:
g_value_set_boolean (value, demux->emit_statistics);
break;
case PROP_SEND_SCTE35_EVENTS:
g_value_set_boolean (value, demux->send_scte35_events);
break;
case PROP_LATENCY:
g_value_set_int (value, demux->latency);
break;
@ -1055,6 +1080,96 @@ push_event (MpegTSBase * base, GstEvent * event)
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
handle_psi (MpegTSBase * base, GstMpegtsSection * section)
{
GstTSDemux *demux = (GstTSDemux *) base;
if (section->section_type == GST_MPEGTS_SECTION_SCTE_SIT) {
GList *tmp;
gboolean forward = FALSE;
if (demux->send_scte35_events) {
for (tmp = demux->program->stream_list; tmp; tmp = tmp->next) {
TSDemuxStream *stream = (TSDemuxStream *) tmp->data;
if (stream->stream.pid == section->pid) {
forward = TRUE;
break;
}
}
}
/* Create a new section to travel through the pipeline, with splice
* times translated from local time to running time */
if (forward) {
GstEvent *event;
GstClockTime pts;
guint i = 0;
const GstMpegtsSCTESIT *sit = gst_mpegts_section_get_scte_sit (section);
GstMpegtsSCTESIT *sit_copy = deep_copy_sit (sit);
GstMpegtsSection *new_section;
if (sit_copy->splice_time_specified) {
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++) {
GstMpegtsSCTESpliceEvent *sevent =
g_ptr_array_index (sit_copy->splices, i);
if (sevent->program_splice_time_specified) {
pts =
mpegts_packetizer_pts_to_ts (base->packetizer,
MPEGTIME_TO_GSTTIME (sevent->program_splice_time),
demux->program->pcr_pid);
sevent->program_splice_time =
gst_segment_to_running_time (&base->out_segment, GST_FORMAT_TIME,
pts);
if (sevent->duration_flag) {
sevent->break_duration =
MPEGTIME_TO_GSTTIME (sevent->break_duration);
}
}
}
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);
gst_mpegts_section_unref (new_section);
push_event (base, event);
}
}
}
static gboolean
sink_query (MpegTSBase * base, GstQuery * query)
{

View file

@ -76,6 +76,7 @@ struct _GstTSDemux
gint requested_program_number; /* Required program number (ignore:-1) */
guint program_number;
gboolean emit_statistics;
gboolean send_scte35_events;
gint latency; /* latency in ms */
/*< private >*/