mpegtsdemux: Handle private section streams

Until now we simply ignored those streams (since we couldn't do anything
with it anyway). Now that we have the mpegts library and we offload the
section handling to the application side we can properly identify and
extract them.

By default it is disabled for tsparse and enabled for tsdemux, but there is
a property to change that.

This should open the way to properly handle all private section streams,
including:
* DSM-CC
* MHEG
* Carousel data
* Metadata streams (though I haven't seen any of those in the wild)
* ... And all other specs/protocols making use of those

Partially fixes #560631
This commit is contained in:
Edward Hervey 2013-07-06 14:50:52 +02:00
parent 057d24811d
commit 1c96c79b88
3 changed files with 103 additions and 28 deletions

View file

@ -64,12 +64,18 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
enum
{
ARG_0,
PROP_0,
PROP_PARSE_PRIVATE_SECTIONS,
/* FILL ME */
};
static void mpegts_base_dispose (GObject * object);
static void mpegts_base_finalize (GObject * object);
static void mpegts_base_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void mpegts_base_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void mpegts_base_free_program (MpegTSBaseProgram * program);
static gboolean mpegts_base_sink_activate (GstPad * pad, GstObject * parent);
static gboolean mpegts_base_sink_activate_mode (GstPad * pad,
@ -115,8 +121,47 @@ mpegts_base_class_init (MpegTSBaseClass * klass)
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = mpegts_base_dispose;
gobject_class->finalize = mpegts_base_finalize;
gobject_class->set_property = mpegts_base_set_property;
gobject_class->get_property = mpegts_base_get_property;
g_object_class_install_property (gobject_class, PROP_PARSE_PRIVATE_SECTIONS,
g_param_spec_boolean ("parse-private-sections", "Parse private sections",
"Parse private sections", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
mpegts_base_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
MpegTSBase *base = GST_MPEGTS_BASE (object);
switch (prop_id) {
case PROP_PARSE_PRIVATE_SECTIONS:
base->parse_private_sections = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
mpegts_base_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
MpegTSBase *base = GST_MPEGTS_BASE (object);
switch (prop_id) {
case PROP_PARSE_PRIVATE_SECTIONS:
g_value_set_boolean (value, base->parse_private_sections);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
mpegts_base_reset (MpegTSBase * base)
{
@ -185,6 +230,7 @@ mpegts_base_init (MpegTSBase * base)
base->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) mpegts_base_free_program);
base->parse_private_sections = FALSE;
base->is_pes = g_new0 (guint8, 1024);
base->known_psi = g_new0 (guint8, 1024);
base->program_size = sizeof (MpegTSBaseProgram);
@ -544,10 +590,28 @@ mpegts_base_deactivate_program (MpegTSBase * base, MpegTSBaseProgram * program)
mpegts_base_program_remove_stream (base, program, stream->pid);
/* Only unset the is_pes bit if the PID isn't used in any other active
/* Only unset the is_pes/known_psi bit if the PID isn't used in any other active
* program */
if (!mpegts_pid_in_active_programs (base, stream->pid))
MPEGTS_BIT_UNSET (base->is_pes, stream->pid);
if (!mpegts_pid_in_active_programs (base, stream->pid)) {
switch (stream->stream_type) {
case GST_MPEG_TS_STREAM_TYPE_PRIVATE_SECTIONS:
case GST_MPEG_TS_STREAM_TYPE_MHEG:
case GST_MPEG_TS_STREAM_TYPE_DSM_CC:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_A:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_B:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_C:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_D:
case GST_MPEG_TS_STREAM_TYPE_SL_FLEXMUX_SECTIONS:
case GST_MPEG_TS_STREAM_TYPE_METADATA_SECTIONS:
/* Set known PSI streams */
if (base->parse_private_sections)
MPEGTS_BIT_UNSET (base->known_psi, stream->pid);
break;
default:
MPEGTS_BIT_UNSET (base->is_pes, stream->pid);
break;
}
}
}
/* remove pcr stream */
@ -595,17 +659,35 @@ mpegts_base_activate_program (MpegTSBase * base, MpegTSBaseProgram * program,
for (i = 0; i < pmt->streams->len; ++i) {
GstMpegTsPMTStream *stream = g_ptr_array_index (pmt->streams, i);
if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->is_pes, stream->pid)))
GST_FIXME ("Refcounting issue. Setting twice a PID (0x%04x) as known PES",
stream->pid);
if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, stream->pid))) {
GST_FIXME
("Refcounting issue. Setting a known PSI PID (0x%04x) as known PES",
stream->pid);
MPEGTS_BIT_UNSET (base->known_psi, stream->pid);
}
switch (stream->stream_type) {
case GST_MPEG_TS_STREAM_TYPE_PRIVATE_SECTIONS:
case GST_MPEG_TS_STREAM_TYPE_MHEG:
case GST_MPEG_TS_STREAM_TYPE_DSM_CC:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_A:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_B:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_C:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_D:
case GST_MPEG_TS_STREAM_TYPE_SL_FLEXMUX_SECTIONS:
case GST_MPEG_TS_STREAM_TYPE_METADATA_SECTIONS:
/* Set known PSI streams */
if (base->parse_private_sections)
MPEGTS_BIT_SET (base->known_psi, stream->pid);
break;
default:
if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->is_pes, stream->pid)))
GST_FIXME
("Refcounting issue. Setting twice a PID (0x%04x) as known PES",
stream->pid);
if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, stream->pid))) {
GST_FIXME
("Refcounting issue. Setting a known PSI PID (0x%04x) as known PES",
stream->pid);
MPEGTS_BIT_UNSET (base->known_psi, stream->pid);
}
MPEGTS_BIT_SET (base->is_pes, stream->pid);
MPEGTS_BIT_SET (base->is_pes, stream->pid);
break;
}
mpegts_base_program_add_stream (base, program,
stream->pid, stream->stream_type, stream);

View file

@ -148,6 +148,9 @@ struct _MpegTSBase {
/* Upstream segment */
GstSegment segment;
/* Whether to parse private section or not */
gboolean parse_private_sections;
};
struct _MpegTSBaseClass {

View file

@ -335,9 +335,11 @@ gst_ts_demux_reset (MpegTSBase * base)
static void
gst_ts_demux_init (GstTSDemux * demux)
{
GST_MPEGTS_BASE (demux)->stream_size = sizeof (TSDemuxStream);
MpegTSBase *base = (MpegTSBase *) demux;
gst_ts_demux_reset ((MpegTSBase *) demux);
base->stream_size = sizeof (TSDemuxStream);
base->parse_private_sections = TRUE;
gst_ts_demux_reset (base);
}
@ -861,18 +863,6 @@ create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
/* name = g_strdup_printf ("private_%04x", bstream->pid); */
/* caps = gst_caps_new_simple ("hdv/aux-a", NULL); */
break;
case GST_MPEG_TS_STREAM_TYPE_PRIVATE_SECTIONS:
case GST_MPEG_TS_STREAM_TYPE_MHEG:
case GST_MPEG_TS_STREAM_TYPE_DSM_CC:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_A:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_B:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_C:
case GST_MPEG_TS_STREAM_TYPE_DSMCC_D:
/* FIXME: Unsetting them from the PES table makes sense since they
* are sections .. but then why don't we set them as know PSI ?
* Also: shouldn't this be handled in mpegtsbase ? */
MPEGTS_BIT_UNSET (base->is_pes, bstream->pid);
break;
case GST_MPEG_TS_STREAM_TYPE_AUDIO_AAC_ADTS:
template = gst_static_pad_template_get (&audio_template);
name = g_strdup_printf ("audio_%04x", bstream->pid);