#include "config.h"
#endif
-/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
- * with newer GLib versions (>= 2.31.0) */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
-
#include <stdlib.h>
#include <string.h>
/* FILL ME */
};
-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_dispose (GObject * object);
static void mpegts_base_finalize (GObject * object);
static void mpegts_base_free_program (MpegTSBaseProgram * program);
-static void mpegts_base_free_stream (MpegTSBaseStream * ptream);
static gboolean mpegts_base_sink_activate (GstPad * pad, GstObject * parent);
static gboolean mpegts_base_sink_activate_mode (GstPad * pad,
GstObject * parent, GstPadMode mode, gboolean active);
GstEvent * event);
static GstStateChangeReturn mpegts_base_change_state (GstElement * element,
GstStateChange transition);
-static void mpegts_base_get_tags_from_sdt (MpegTSBase * base,
- GstStructure * sdt_info);
-static void mpegts_base_get_tags_from_eit (MpegTSBase * base,
- GstStructure * eit_info);
-static gboolean
-remove_each_program (gpointer key, MpegTSBaseProgram * program,
+static gboolean mpegts_base_get_tags_from_eit (MpegTSBase * base,
+ GstMpegTSSection * section);
+static gboolean remove_each_program (gpointer key, MpegTSBaseProgram * program,
MpegTSBase * base);
static void
G_DEFINE_TYPE_WITH_CODE (MpegTSBase, mpegts_base, GST_TYPE_ELEMENT,
_extra_init ());
-static const guint32 crc_tab[256] = {
- 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
- 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
- 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
- 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
- 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
- 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
- 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
- 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
- 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
- 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
- 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
- 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
- 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
- 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
- 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
- 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
- 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
- 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
- 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
- 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
- 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
- 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
- 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
- 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
- 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
- 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
- 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
- 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
- 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
- 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
- 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
- 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
- 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
- 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
- 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
- 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
- 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
- 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
- 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
- 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
- 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
- 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
- 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
-};
-
-/* relicenced to LGPL from fluendo ts demuxer */
-static guint32
-mpegts_base_calc_crc32 (guint8 * data, guint datalen)
-{
- gint i;
- guint32 crc = 0xffffffff;
-
- for (i = 0; i < datalen; i++) {
- crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
- }
- return crc;
-}
-
static void
mpegts_base_class_init (MpegTSBaseClass * klass)
{
gst_static_pad_template_get (&sink_template));
gobject_class = G_OBJECT_CLASS (klass);
- gobject_class->set_property = mpegts_base_set_property;
- gobject_class->get_property = mpegts_base_get_property;
gobject_class->dispose = mpegts_base_dispose;
gobject_class->finalize = mpegts_base_finalize;
-
}
static void
memset (base->is_pes, 0, 1024);
memset (base->known_psi, 0, 1024);
+ /* FIXME : Actually these are not *always* know SI streams
+ * depending on the variant of mpeg-ts being used. */
+
/* Known PIDs : PAT, TSDT, IPMP CIT */
MPEGTS_BIT_SET (base->known_psi, 0);
MPEGTS_BIT_SET (base->known_psi, 2);
/* network synchronization */
MPEGTS_BIT_SET (base->known_psi, 0x15);
+ /* ATSC */
+ MPEGTS_BIT_SET (base->known_psi, 0x1ffb);
+
/* FIXME : Commenting the Following lines is to be in sync with the following
* commit
*
MpegTSBase *base = GST_MPEGTS_BASE (object);
if (base->pat) {
- gst_structure_free (base->pat);
+ g_array_unref (base->pat);
base->pat = NULL;
}
g_hash_table_destroy (base->programs);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-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) {
- 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) {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
/* returns NULL if no matching descriptor found *
* otherwise returns a descriptor that needs to *
* be freed */
-guint8 *
+/* FIXME : Return the GstMpegTSDescriptor */
+const guint8 *
mpegts_get_descriptor_from_stream (MpegTSBaseStream * stream, guint8 tag)
{
- GValueArray *descriptors = NULL;
- GstStructure *stream_info = stream->stream_info;
- guint8 *retval = NULL;
- int i;
-
- if (!gst_structure_has_field_typed (stream_info, "descriptors",
- G_TYPE_VALUE_ARRAY))
- goto beach;
-
- gst_structure_get (stream_info, "descriptors", G_TYPE_VALUE_ARRAY,
- &descriptors, NULL);
+ const GstMpegTSDescriptor *desc;
+ GstMpegTSPMTStream *pmt = stream->stream;
- for (i = 0; i < descriptors->n_values; i++) {
- GValue *value = g_value_array_get_nth (descriptors, i);
- GString *desc = g_value_dup_boxed (value);
- if (DESC_TAG (desc->str) == tag && !retval) {
- retval = (guint8 *) desc->str;
- g_string_free (desc, FALSE);
- break;
- } else {
- g_string_free (desc, TRUE);
- }
- }
- g_value_array_free (descriptors);
+ GST_DEBUG ("Searching for tag 0x%02x in stream 0x%04x (stream_type 0x%02x)",
+ tag, stream->pid, stream->stream_type);
-beach:
- return retval;
+ desc = gst_mpegts_find_descriptor (pmt->descriptors, tag);
+ if (desc)
+ return desc->descriptor_data;
+ return NULL;
}
typedef struct
/* returns NULL if no matching descriptor found *
* otherwise returns a descriptor that needs to *
* be freed */
-guint8 *
+/* FIXME : Return the GstMpegTSDescriptor */
+const guint8 *
mpegts_get_descriptor_from_program (MpegTSBaseProgram * program, guint8 tag)
{
- GValueArray *descriptors = NULL;
- GstStructure *program_info;
- guint8 *retval = NULL;
- int i;
-
- if (G_UNLIKELY (program == NULL))
- goto beach;
-
- program_info = program->pmt_info;
- if (!gst_structure_has_field_typed (program_info, "descriptors",
- G_TYPE_VALUE_ARRAY))
- goto beach;
-
- gst_structure_get (program_info, "descriptors", G_TYPE_VALUE_ARRAY,
- &descriptors, NULL);
+ const GstMpegTSDescriptor *descriptor;
+ const GstMpegTSPMT *pmt = program->pmt;
- for (i = 0; i < descriptors->n_values; i++) {
- GValue *value = g_value_array_get_nth (descriptors, i);
- GString *desc = g_value_dup_boxed (value);
- if (DESC_TAG (desc->str) == tag && !retval) {
- retval = (guint8 *) desc->str;
- g_string_free (desc, FALSE);
- break;
- } else
- g_string_free (desc, TRUE);
- }
- g_value_array_free (descriptors);
+ descriptor = gst_mpegts_find_descriptor (pmt->descriptors, tag);
+ if (descriptor)
+ return descriptor->descriptor_data;
-beach:
- return retval;
+ return NULL;
}
static MpegTSBaseProgram *
program = mpegts_base_new_program (base, program_number, pmt_pid);
/* Mark the PMT PID as being a known PSI PID */
+ if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, pmt_pid))) {
+ GST_FIXME ("Refcounting. Setting twice a PID (0x%04x) as known PSI",
+ pmt_pid);
+ }
MPEGTS_BIT_SET (base->known_psi, pmt_pid);
g_hash_table_insert (base->programs,
{
GList *tmp;
- if (program->pmt_info)
- gst_structure_free (program->pmt_info);
+ if (program->pmt) {
+ gst_mpegts_section_unref (program->section);
+ program->pmt = NULL;
+ }
for (tmp = program->stream_list; tmp; tmp = tmp->next)
- mpegts_base_free_stream ((MpegTSBaseStream *) tmp->data);
+ g_free (tmp->data);
if (program->stream_list)
g_list_free (program->stream_list);
static MpegTSBaseStream *
mpegts_base_program_add_stream (MpegTSBase * base,
MpegTSBaseProgram * program, guint16 pid, guint8 stream_type,
- GstStructure * stream_info)
+ GstMpegTSPMTStream * stream)
{
MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
- MpegTSBaseStream *stream;
+ MpegTSBaseStream *bstream;
- GST_DEBUG ("pid:0x%04x, stream_type:0x%03x, stream_info:%" GST_PTR_FORMAT,
- pid, stream_type, stream_info);
+ GST_DEBUG ("pid:0x%04x, stream_type:0x%03x", pid, stream_type);
if (G_UNLIKELY (program->streams[pid])) {
if (stream_type != 0xff)
return NULL;
}
- stream = g_malloc0 (base->stream_size);
- stream->pid = pid;
- stream->stream_type = stream_type;
- stream->stream_info = stream_info;
+ bstream = g_malloc0 (base->stream_size);
+ bstream->pid = pid;
+ bstream->stream_type = stream_type;
+ bstream->stream = stream;
- program->streams[pid] = stream;
- program->stream_list = g_list_append (program->stream_list, stream);
+ program->streams[pid] = bstream;
+ program->stream_list = g_list_append (program->stream_list, bstream);
if (klass->stream_added)
- klass->stream_added (base, stream, program);
+ klass->stream_added (base, bstream, program);
- return stream;
-}
-
-static void
-mpegts_base_free_stream (MpegTSBaseStream * stream)
-{
- g_free (stream);
+ return bstream;
}
void
klass->stream_removed (base, stream);
program->stream_list = g_list_remove_all (program->stream_list, stream);
- mpegts_base_free_stream (stream);
+ g_free (stream);
program->streams[pid] = NULL;
}
/* Return TRUE if programs are equal */
static gboolean
mpegts_base_is_same_program (MpegTSBase * base, MpegTSBaseProgram * oldprogram,
- guint16 new_pmt_pid, GstStructure * new_pmt_info)
+ guint16 new_pmt_pid, const GstMpegTSPMT * new_pmt)
{
guint i, nbstreams;
- guint pcr_pid;
- guint pid;
- guint stream_type;
- GstStructure *stream;
MpegTSBaseStream *oldstream;
gboolean sawpcrpid = FALSE;
- const GValue *new_streams;
- const GValue *value;
if (oldprogram->pmt_pid != new_pmt_pid) {
GST_DEBUG ("Different pmt_pid (new:0x%04x, old:0x%04x)", new_pmt_pid,
return FALSE;
}
- gst_structure_id_get (new_pmt_info, QUARK_PCR_PID, G_TYPE_UINT, &pcr_pid,
- NULL);
- if (oldprogram->pcr_pid != pcr_pid) {
+ if (oldprogram->pcr_pid != new_pmt->pcr_pid) {
GST_DEBUG ("Different pcr_pid (new:0x%04x, old:0x%04x)",
- pcr_pid, oldprogram->pcr_pid);
+ new_pmt->pcr_pid, oldprogram->pcr_pid);
return FALSE;
}
/* Check the streams */
- new_streams = gst_structure_id_get_value (new_pmt_info, QUARK_STREAMS);
- nbstreams = gst_value_list_get_size (new_streams);
-
+ nbstreams = new_pmt->streams->len;
for (i = 0; i < nbstreams; ++i) {
- value = gst_value_list_get_value (new_streams, i);
- stream = g_value_get_boxed (value);
+ GstMpegTSPMTStream *stream = g_ptr_array_index (new_pmt->streams, i);
- gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid,
- QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL);
- oldstream = oldprogram->streams[pid];
+ oldstream = oldprogram->streams[stream->pid];
if (!oldstream) {
- GST_DEBUG ("New stream 0x%04x not present in old program", pid);
+ GST_DEBUG ("New stream 0x%04x not present in old program", stream->pid);
return FALSE;
}
- if (oldstream->stream_type != stream_type) {
+ if (oldstream->stream_type != stream->stream_type) {
GST_DEBUG
("New stream 0x%04x has a different stream type (new:%d, old:%d)",
- pid, stream_type, oldstream->stream_type);
+ stream->pid, stream->stream_type, oldstream->stream_type);
return FALSE;
}
- if (pid == oldprogram->pcr_pid)
+ if (stream->pid == oldprogram->pcr_pid)
sawpcrpid = TRUE;
}
static void
mpegts_base_deactivate_program (MpegTSBase * base, MpegTSBaseProgram * program)
{
- gint i, nbstreams;
- guint pid;
- GstStructure *stream;
- const GValue *streams;
- const GValue *value;
+ gint i;
MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
if (G_UNLIKELY (program->active == FALSE))
program->active = FALSE;
- if (program->pmt_info) {
- streams = gst_structure_id_get_value (program->pmt_info, QUARK_STREAMS);
- nbstreams = gst_value_list_get_size (streams);
-
- for (i = 0; i < nbstreams; ++i) {
- value = gst_value_list_get_value (streams, i);
- stream = g_value_get_boxed (value);
+ if (program->pmt) {
+ for (i = 0; i < program->pmt->streams->len; ++i) {
+ GstMpegTSPMTStream *stream = g_ptr_array_index (program->pmt->streams, i);
- gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid, NULL);
- mpegts_base_program_remove_stream (base, program, (guint16) pid);
+ 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
* program */
- if (!mpegts_pid_in_active_programs (base, pid))
- MPEGTS_BIT_UNSET (base->is_pes, pid);
+ if (!mpegts_pid_in_active_programs (base, stream->pid))
+ MPEGTS_BIT_UNSET (base->is_pes, stream->pid);
}
/* remove pcr stream */
static void
mpegts_base_activate_program (MpegTSBase * base, MpegTSBaseProgram * program,
- guint16 pmt_pid, GstStructure * pmt_info, gboolean initial_program)
+ guint16 pmt_pid, GstMpegTSSection * section, const GstMpegTSPMT * pmt,
+ gboolean initial_program)
{
- guint i, nbstreams;
- guint pcr_pid;
- guint pid;
- guint stream_type;
- GstStructure *stream;
- const GValue *new_streams;
- const GValue *value;
+ guint i;
MpegTSBaseClass *klass;
if (G_UNLIKELY (program->active))
GST_DEBUG ("Activating program %d", program->program_number);
- gst_structure_id_get (pmt_info, QUARK_PCR_PID, G_TYPE_UINT, &pcr_pid, NULL);
-
/* activate new pmt */
- if (program->pmt_info)
- gst_structure_free (program->pmt_info);
+ if (program->section)
+ gst_mpegts_section_unref (program->section);
+ program->section = gst_mpegts_section_ref (section);
- program->pmt_info = pmt_info;
+ program->pmt = pmt;
program->pmt_pid = pmt_pid;
- program->pcr_pid = pcr_pid;
-
- new_streams = gst_structure_id_get_value (pmt_info, QUARK_STREAMS);
- nbstreams = gst_value_list_get_size (new_streams);
-
- for (i = 0; i < nbstreams; ++i) {
- value = gst_value_list_get_value (new_streams, i);
- stream = g_value_get_boxed (value);
+ program->pcr_pid = pmt->pcr_pid;
+
+ 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);
+ }
- gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid,
- QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL);
- MPEGTS_BIT_SET (base->is_pes, pid);
+ MPEGTS_BIT_SET (base->is_pes, stream->pid);
mpegts_base_program_add_stream (base, program,
- (guint16) pid, (guint8) stream_type, stream);
+ stream->pid, stream->stream_type, stream);
}
/* We add the PCR pid last. If that PID is already used by one of the media
* streams above, no new stream will be created */
- mpegts_base_program_add_stream (base, program, (guint16) pcr_pid, -1, NULL);
- MPEGTS_BIT_SET (base->is_pes, pcr_pid);
+ mpegts_base_program_add_stream (base, program, pmt->pcr_pid, -1, NULL);
+ MPEGTS_BIT_SET (base->is_pes, pmt->pcr_pid);
program->active = TRUE;
program->initial_program = initial_program;
if (klass->program_started != NULL)
klass->program_started (base, program);
- GST_DEBUG_OBJECT (base, "new pmt %" GST_PTR_FORMAT, pmt_info);
+ GST_DEBUG_OBJECT (base, "new pmt activated");
}
+/* FIXME : This method is fundamentally wrong (and potentially expensive)
+ * A packet is only a PSI if it's from a known PSI stream.
+ *
+ * The proper fix is to ensure the rest of mpegtsbase properly ensures
+ * that PSI streams are properly detected.
+ *
+ * This requires:
+ * * Initially setting all PSI PID which are generic accross formats
+ * * When we know the "variant" of the stream (Bluray, DVB, ATSC, ISDB,...)
+ * we properly set the expected PSI
+ * * Properly unsetting expected know-PSI PID the moment we see a program
+ * using that PID for PES (it's not uncommon for example for ATSC streams
+ * to use 0x0010 as a PES PID).
+ **/
static inline gboolean
mpegts_base_is_psi (MpegTSBase * base, MpegTSPacketizerPacket * packet)
{
gboolean retval = FALSE;
- guint8 *data, table_id = TABLE_ID_UNSET, pointer;
+ guint8 *data, table_id = GST_MTS_TABLE_ID_UNSET, pointer;
int i;
static const guint8 si_tables[] =
0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65,
0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7E, 0x7F,
- TABLE_ID_UNSET
+ GST_MTS_TABLE_ID_UNSET
};
/* check if it is a pes pid */
base->packetizer->streams[packet->pid];
if (stream)
- table_id = stream->section_table_id;
+ table_id = stream->table_id;
}
- if (G_UNLIKELY (table_id == TABLE_ID_UNSET))
+ if (G_UNLIKELY (table_id == GST_MTS_TABLE_ID_UNSET))
goto beach;
- for (i = 0; si_tables[i] != TABLE_ID_UNSET; i++) {
+ for (i = 0; si_tables[i] != GST_MTS_TABLE_ID_UNSET; i++) {
if (G_UNLIKELY (si_tables[i] == table_id)) {
retval = TRUE;
break;
return FALSE;
}
-static void
-mpegts_base_apply_pat (MpegTSBase * base, GstStructure * pat_info)
+static gboolean
+mpegts_base_apply_pat (MpegTSBase * base, GstMpegTSSection * section)
{
- const GValue *value;
- GstStructure *old_pat;
- GstStructure *program_info;
- guint program_number;
- guint pid;
+ GArray *pat = gst_mpegts_section_get_pat (section);
+ GArray *old_pat;
MpegTSBaseProgram *program;
- gint i, nbprograms;
- const GValue *programs;
+ gint i;
- GST_INFO_OBJECT (base, "PAT %" GST_PTR_FORMAT, pat_info);
+ if (G_UNLIKELY (pat == NULL))
+ return FALSE;
+
+ GST_INFO_OBJECT (base, "PAT");
/* Applying a new PAT does two things:
* * It adds the new programs to the list of programs this element handles
*/
old_pat = base->pat;
- base->pat = pat_info;
-
- gst_element_post_message (GST_ELEMENT_CAST (base),
- gst_message_new_element (GST_OBJECT (base),
- gst_structure_copy (pat_info)));
-
+ base->pat = pat;
GST_LOG ("Activating new Program Association Table");
/* activate the new table */
- programs = gst_structure_id_get_value (pat_info, QUARK_PROGRAMS);
- nbprograms = gst_value_list_get_size (programs);
- for (i = 0; i < nbprograms; ++i) {
- value = gst_value_list_get_value (programs, i);
-
- program_info = g_value_get_boxed (value);
- gst_structure_id_get (program_info, QUARK_PROGRAM_NUMBER, G_TYPE_UINT,
- &program_number, QUARK_PID, G_TYPE_UINT, &pid, NULL);
+ for (i = 0; i < pat->len; ++i) {
+ GstMpegTSPatProgram *patp = &g_array_index (pat, GstMpegTSPatProgram, i);
- program = mpegts_base_get_program (base, program_number);
+ program = mpegts_base_get_program (base, patp->program_number);
if (program) {
/* IF the program already existed, just check if the PMT PID changed */
- if (program->pmt_pid != pid) {
+ if (program->pmt_pid != patp->network_or_program_map_PID) {
if (program->pmt_pid != G_MAXUINT16) {
/* pmt pid changed */
/* FIXME: when this happens it may still be pmt pid of another
MPEGTS_BIT_UNSET (base->known_psi, program->pmt_pid);
}
- program->pmt_pid = pid;
- MPEGTS_BIT_SET (base->known_psi, pid);
+ program->pmt_pid = patp->network_or_program_map_PID;
+ if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, program->pmt_pid)))
+ GST_FIXME
+ ("Refcounting issue. Setting twice a PMT PID (0x%04x) as know PSI",
+ program->pmt_pid);
+ MPEGTS_BIT_SET (base->known_psi, patp->network_or_program_map_PID);
}
} else {
/* Create a new program */
- program = mpegts_base_add_program (base, program_number, pid);
+ program =
+ mpegts_base_add_program (base, patp->program_number,
+ patp->network_or_program_map_PID);
}
/* We mark this program as being referenced by one PAT */
program->patcount += 1;
/* deactivate the old table */
GST_LOG ("Deactivating old Program Association Table");
- programs = gst_structure_id_get_value (old_pat, QUARK_PROGRAMS);
- nbprograms = gst_value_list_get_size (programs);
- for (i = 0; i < nbprograms; ++i) {
- value = gst_value_list_get_value (programs, i);
+ for (i = 0; i < old_pat->len; ++i) {
+ GstMpegTSPatProgram *patp =
+ &g_array_index (old_pat, GstMpegTSPatProgram, i);
- program_info = g_value_get_boxed (value);
- gst_structure_id_get (program_info,
- QUARK_PROGRAM_NUMBER, G_TYPE_UINT, &program_number,
- QUARK_PID, G_TYPE_UINT, &pid, NULL);
-
- program = mpegts_base_get_program (base, program_number);
+ program = mpegts_base_get_program (base, patp->program_number);
if (G_UNLIKELY (program == NULL)) {
GST_DEBUG_OBJECT (base, "broken PAT, duplicated entry for program %d",
- program_number);
+ patp->program_number);
continue;
}
/* the program has been referenced by the new pat, keep it */
continue;
- GST_INFO_OBJECT (base, "PAT removing program %" GST_PTR_FORMAT,
- program_info);
+ GST_INFO_OBJECT (base, "PAT removing program 0x%04x 0x%04x",
+ patp->program_number, patp->network_or_program_map_PID);
mpegts_base_deactivate_program (base, program);
- mpegts_base_remove_program (base, program_number);
+ mpegts_base_remove_program (base, patp->program_number);
/* FIXME: when this happens it may still be pmt pid of another
* program, so setting to False may make it go through expensive
* path in is_psi unnecessarily */
- MPEGTS_BIT_SET (base->known_psi, pid);
- mpegts_packetizer_remove_stream (base->packetizer, pid);
+ if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi,
+ patp->network_or_program_map_PID))) {
+ GST_FIXME
+ ("Program refcounting : Setting twice a pid (0x%04x) as known PSI",
+ patp->network_or_program_map_PID);
+ }
+ MPEGTS_BIT_SET (base->known_psi, patp->network_or_program_map_PID);
+ mpegts_packetizer_remove_stream (base->packetizer,
+ patp->network_or_program_map_PID);
}
- gst_structure_free (old_pat);
+ g_array_unref (old_pat);
}
+
+ return TRUE;
}
-static void
-mpegts_base_apply_pmt (MpegTSBase * base,
- guint16 pmt_pid, GstStructure * pmt_info)
+static gboolean
+mpegts_base_apply_pmt (MpegTSBase * base, GstMpegTSSection * section)
{
+ const GstMpegTSPMT *pmt;
MpegTSBaseProgram *program, *old_program;
guint program_number;
gboolean initial_program = TRUE;
+ pmt = gst_mpegts_section_get_pmt (section);
+ if (G_UNLIKELY (pmt == NULL)) {
+ GST_ERROR ("Could not get PMT (corrupted ?)");
+ return FALSE;
+ }
+
/* FIXME : not so sure this is valid anymore */
if (G_UNLIKELY (base->seen_pat == FALSE)) {
GST_WARNING ("Got pmt without pat first. Returning");
/* remove the stream since we won't get another PMT otherwise */
- mpegts_packetizer_remove_stream (base->packetizer, pmt_pid);
- return;
+ mpegts_packetizer_remove_stream (base->packetizer, section->pid);
+ return TRUE;
}
- gst_structure_id_get (pmt_info, QUARK_PROGRAM_NUMBER, G_TYPE_UINT,
- &program_number, NULL);
-
+ program_number = section->subtable_extension;
GST_DEBUG ("Applying PMT (program_number:%d, pid:0x%04x)",
- program_number, pmt_pid);
+ program_number, section->pid);
/* In order for stream switching to happen properly in decodebin(2),
* we need to first add the new pads (i.e. activate the new program)
if (G_UNLIKELY (old_program == NULL))
goto no_program;
- if (G_UNLIKELY (mpegts_base_is_same_program (base, old_program, pmt_pid,
- pmt_info)))
+ if (G_UNLIKELY (mpegts_base_is_same_program (base, old_program, section->pid,
+ pmt)))
goto same_program;
/* If the current program is active, this means we have a new program */
if (old_program->active) {
old_program = mpegts_base_steal_program (base, program_number);
- program = mpegts_base_new_program (base, program_number, pmt_pid);
+ program = mpegts_base_new_program (base, program_number, section->pid);
g_hash_table_insert (base->programs,
GINT_TO_POINTER (program_number), program);
/* activate program */
/* Ownership of pmt_info is given to the program */
- mpegts_base_activate_program (base, program, pmt_pid, pmt_info,
+ mpegts_base_activate_program (base, program, section->pid, section, pmt,
initial_program);
- gst_element_post_message (GST_ELEMENT_CAST (base),
- gst_message_new_element (GST_OBJECT (base),
- gst_structure_copy (pmt_info)));
-
- return;
+ return TRUE;
no_program:
{
GST_ERROR ("Attempted to apply a PMT on a program that wasn't created");
- gst_structure_free (pmt_info);
- return;
+ return TRUE;
}
same_program:
{
GST_DEBUG ("Not applying identical program");
- gst_structure_free (pmt_info);
- return;
+ return TRUE;
}
}
static void
-mpegts_base_apply_cat (MpegTSBase * base, GstStructure * cat_info)
-{
- GST_DEBUG_OBJECT (base, "CAT %" GST_PTR_FORMAT, cat_info);
-
- gst_element_post_message (GST_ELEMENT_CAST (base),
- gst_message_new_element (GST_OBJECT (base), cat_info));
-}
-
-static void
-mpegts_base_apply_nit (MpegTSBase * base,
- guint16 pmt_pid, GstStructure * nit_info)
+mpegts_base_handle_psi (MpegTSBase * base, GstMpegTSSection * section)
{
- GST_DEBUG_OBJECT (base, "NIT %" GST_PTR_FORMAT, nit_info);
-
- gst_element_post_message (GST_ELEMENT_CAST (base),
- gst_message_new_element (GST_OBJECT (base), nit_info));
-}
-
-static void
-mpegts_base_apply_sdt (MpegTSBase * base,
- guint16 pmt_pid, GstStructure * sdt_info)
-{
- GST_DEBUG_OBJECT (base, "SDT %" GST_PTR_FORMAT, sdt_info);
-
- mpegts_base_get_tags_from_sdt (base, sdt_info);
-
- gst_element_post_message (GST_ELEMENT_CAST (base),
- gst_message_new_element (GST_OBJECT (base), sdt_info));
-}
-
-static void
-mpegts_base_apply_eit (MpegTSBase * base,
- guint16 pmt_pid, GstStructure * eit_info)
-{
- GST_DEBUG_OBJECT (base, "EIT %" GST_PTR_FORMAT, eit_info);
-
- mpegts_base_get_tags_from_eit (base, eit_info);
-
- gst_element_post_message (GST_ELEMENT_CAST (base),
- gst_message_new_element (GST_OBJECT (base), eit_info));
-}
-
-static void
-mpegts_base_apply_tdt (MpegTSBase * base,
- guint16 tdt_pid, GstStructure * tdt_info)
-{
- gst_element_post_message (GST_ELEMENT_CAST (base),
- gst_message_new_element (GST_OBJECT (base),
- gst_structure_copy (tdt_info)));
-
- GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base,
- gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, tdt_info));
-}
-
-
-gboolean
-mpegts_base_handle_psi (MpegTSBase * base, MpegTSPacketizerSection * section)
-{
- gboolean res = TRUE;
- GstStructure *structure = NULL;
-
- /* table ids 0x70 - 0x73 do not have a crc (EN 300 468) */
- /* table ids 0x75 - 0x77 do not have a crc (TS 102 323) */
- /* table id 0x7e does not have a crc (EN 300 468) */
- /* table ids 0x80 - 0x8f do not have a crc (CA_message section ETR 289) */
- if (G_LIKELY ((section->table_id < 0x70 || section->table_id > 0x73)
- && (section->table_id < 0x75 || section->table_id > 0x77)
- && (section->table_id < 0x80 || section->table_id > 0x8f)
- && (section->table_id != 0x7e))) {
- if (G_UNLIKELY (mpegts_base_calc_crc32 (section->data,
- section->section_length) != 0)) {
- GST_WARNING_OBJECT (base, "bad crc in psi pid 0x%04x (table_id:0x%02x)",
- section->pid, section->table_id);
- return FALSE;
- }
- }
+ gboolean post_message = TRUE;
GST_DEBUG ("Handling PSI (pid: 0x%04x , table_id: 0x%02x)",
section->pid, section->table_id);
- switch (section->table_id) {
- case TABLE_ID_PROGRAM_ASSOCIATION:
- /* PAT */
- structure = mpegts_packetizer_parse_pat (base->packetizer, section);
- if (G_LIKELY (structure)) {
- mpegts_base_apply_pat (base, structure);
- if (base->seen_pat == FALSE) {
- base->seen_pat = TRUE;
- GST_DEBUG ("First PAT offset: %" G_GUINT64_FORMAT, section->offset);
- mpegts_packetizer_set_reference_offset (base->packetizer,
- section->offset);
- }
-
- } else
- res = FALSE;
-
- break;
- case TABLE_ID_CONDITIONAL_ACCESS:
- /* CAT */
- structure = mpegts_packetizer_parse_cat (base->packetizer, section);
- if (structure)
- mpegts_base_apply_cat (base, structure);
- else
- res = FALSE;
- break;
- case TABLE_ID_TS_PROGRAM_MAP:
- /* PMT */
- structure = mpegts_packetizer_parse_pmt (base->packetizer, section);
- if (G_LIKELY (structure))
- mpegts_base_apply_pmt (base, section->pid, structure);
- else
- res = FALSE;
-
- break;
- case TABLE_ID_NETWORK_INFORMATION_ACTUAL_NETWORK:
- /* NIT, actual network */
- case TABLE_ID_NETWORK_INFORMATION_OTHER_NETWORK:
- /* NIT, other network */
- structure = mpegts_packetizer_parse_nit (base->packetizer, section);
- if (G_LIKELY (structure))
- mpegts_base_apply_nit (base, section->pid, structure);
- else
- res = FALSE;
-
- break;
- case TABLE_ID_SERVICE_DESCRIPTION_ACTUAL_TS:
- case TABLE_ID_SERVICE_DESCRIPTION_OTHER_TS:
- structure = mpegts_packetizer_parse_sdt (base->packetizer, section);
- if (G_LIKELY (structure))
- mpegts_base_apply_sdt (base, section->pid, structure);
- else
- res = FALSE;
- break;
- case 0x4E:
- case 0x4F:
- /* EIT, present/following */
- case 0x50:
- case 0x51:
- case 0x52:
- case 0x53:
- case 0x54:
- case 0x55:
- case 0x56:
- case 0x57:
- case 0x58:
- case 0x59:
- case 0x5A:
- case 0x5B:
- case 0x5C:
- case 0x5D:
- case 0x5E:
- case 0x5F:
- case 0x60:
- case 0x61:
- case 0x62:
- case 0x63:
- case 0x64:
- case 0x65:
- case 0x66:
- case 0x67:
- case 0x68:
- case 0x69:
- case 0x6A:
- case 0x6B:
- case 0x6C:
- case 0x6D:
- case 0x6E:
- case 0x6F:
- /* EIT, schedule */
- /* FIXME : Can take up to 50% of total mpeg-ts demuxing cpu usage ! */
- structure = mpegts_packetizer_parse_eit (base->packetizer, section);
- if (G_LIKELY (structure))
- mpegts_base_apply_eit (base, section->pid, structure);
- else
- res = FALSE;
- break;
- case TABLE_ID_TIME_DATE:
- /* TDT (Time and Date table) */
- structure = mpegts_packetizer_parse_tdt (base->packetizer, section);
- if (G_LIKELY (structure))
- mpegts_base_apply_tdt (base, section->pid, structure);
- else
- res = FALSE;
+ switch (section->section_type) {
+ case GST_MPEGTS_SECTION_PAT:
+ post_message = mpegts_base_apply_pat (base, section);
+ if (base->seen_pat == FALSE) {
+ base->seen_pat = TRUE;
+ GST_DEBUG ("First PAT offset: %" G_GUINT64_FORMAT, section->offset);
+ mpegts_packetizer_set_reference_offset (base->packetizer,
+ section->offset);
+ break;
+ }
+ case GST_MPEGTS_SECTION_PMT:
+ post_message = mpegts_base_apply_pmt (base, section);
break;
- case TABLE_ID_TIME_OFFSET:
- /* TOT (Time Offset table) */
- structure = mpegts_packetizer_parse_tot (base->packetizer, section);
- if (G_LIKELY (structure))
- mpegts_base_apply_tdt (base, section->pid, structure);
- else
- res = FALSE;
+ case GST_MPEGTS_SECTION_EIT:
+ /* some tag xtraction + posting */
+ post_message = mpegts_base_get_tags_from_eit (base, section);
break;
default:
- GST_WARNING ("Unhandled or unknown section type (table_id 0x%02x)",
- section->table_id);
break;
}
- return res;
+ /* Finally post message (if it wasn't corrupted) */
+ if (post_message)
+ gst_element_post_message (GST_ELEMENT_CAST (base),
+ gst_message_new_mpegts_section (GST_OBJECT (base), section));
+ gst_mpegts_section_unref (section);
}
-static void
-mpegts_base_get_tags_from_sdt (MpegTSBase * base, GstStructure * sdt_info)
-{
- const GValue *services;
- guint i;
- services = gst_structure_get_value (sdt_info, "services");
-
- for (i = 0; i < gst_value_list_get_size (services); i++) {
- const GstStructure *service;
- const gchar *sid_str;
- gchar *tmp;
- gint program_number;
- MpegTSBaseProgram *program;
-
- service = gst_value_get_structure (gst_value_list_get_value (services, i));
-
- /* get program_number from structure name
- * which looks like service-%d */
- sid_str = gst_structure_get_name (service);
- tmp = g_strstr_len (sid_str, -1, "-");
- if (!tmp)
- continue;
- program_number = atoi (++tmp);
-
- program = mpegts_base_get_program (base, program_number);
- if (program && !program->tags) {
- program->tags = gst_tag_list_new (GST_TAG_ARTIST,
- gst_structure_get_string (service, "name"), NULL);
- }
- }
-}
-
-static void
-mpegts_base_get_tags_from_eit (MpegTSBase * base, GstStructure * eit_info)
+static gboolean
+mpegts_base_get_tags_from_eit (MpegTSBase * base, GstMpegTSSection * section)
{
- const GValue *events;
+ const GstMpegTSEIT *eit;
guint i;
- guint program_number;
MpegTSBaseProgram *program;
- gboolean present_following;
-
- gst_structure_get_uint (eit_info, "service-id", &program_number);
- program = mpegts_base_get_program (base, program_number);
-
- gst_structure_get_boolean (eit_info, "present-following", &present_following);
-
- if (program && present_following) {
- events = gst_structure_get_value (eit_info, "events");
-
- for (i = 0; i < gst_value_list_get_size (events); i++) {
- const GstStructure *event;
- const gchar *title;
- guint status;
- guint event_id;
- guint duration;
- event = gst_value_get_structure (gst_value_list_get_value (events, i));
+ /* Early exit if it's not from the present/following table_id */
+ if (section->table_id != GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_PRESENT
+ || section->table_id !=
+ GST_MTS_TABLE_ID_EVENT_INFORMATION_OTHER_TS_PRESENT)
+ return TRUE;
- title = gst_structure_get_string (event, "name");
- gst_structure_get_uint (event, "event-id", &event_id);
- gst_structure_get_uint (event, "running-status", &status);
-
- if (title && event_id != program->event_id
- && status == RUNNING_STATUS_RUNNING) {
- gst_structure_get_uint (event, "duration", &duration);
+ eit = gst_mpegts_section_get_eit (section);
+ if (G_UNLIKELY (eit == NULL))
+ return FALSE;
- program->event_id = event_id;
- program->tags = gst_tag_list_new (GST_TAG_TITLE,
- title, GST_TAG_DURATION, duration * GST_SECOND, NULL);
+ program = mpegts_base_get_program (base, section->subtable_extension);
+
+ GST_DEBUG
+ ("program_id:0x%04x, table_id:0x%02x, actual_stream:%d, present_following:%d, program:%p",
+ section->subtable_extension, section->table_id, eit->actual_stream,
+ eit->present_following, program);
+
+ if (program && eit->present_following) {
+ for (i = 0; i < eit->events->len; i++) {
+ GstMpegTSEITEvent *event = g_ptr_array_index (eit->events, i);
+ const GstMpegTSDescriptor *desc;
+
+ if (event->running_status == RUNNING_STATUS_RUNNING) {
+ program->event_id = event->event_id;
+ if ((desc =
+ gst_mpegts_find_descriptor (event->descriptors,
+ GST_MTS_DESC_DVB_SHORT_EVENT))) {
+ gchar *name;
+ if (gst_mpegts_descriptor_parse_dvb_short_event (desc, NULL, &name,
+ NULL)) {
+ /* FIXME : Is it correct to post an event duration as a GST_TAG_DURATION ??? */
+ program->tags =
+ gst_tag_list_new (GST_TAG_TITLE, name, GST_TAG_DURATION,
+ event->duration * GST_SECOND, NULL);
+ return TRUE;
+ }
+ }
}
}
}
+
+ return TRUE;
}
static gboolean
{
GstFlowReturn res = GST_FLOW_OK;
MpegTSBase *base;
- gboolean based;
MpegTSPacketizerPacketReturn pret;
MpegTSPacketizer2 *packetizer;
MpegTSPacketizerPacket packet;
goto next;
}
- /* FIXME : Handle the case where we have multiple sections in one
- * packet !
- * See bug #677443
- */
/* base PSI data */
if (packet.payload != NULL && mpegts_base_is_psi (base, &packet)) {
- MpegTSPacketizerSection section;
- based = mpegts_packetizer_push_section (packetizer, &packet, §ion);
- if (G_UNLIKELY (!based))
- /* bad section data */
- goto next;
-
- if (G_LIKELY (section.complete)) {
- /* section complete */
- based = mpegts_base_handle_psi (base, §ion);
-
- if (G_UNLIKELY (!based)) {
- /* bad PSI table */
- goto next;
- }
- }
+ GstMpegTSSection *section;
+
+ section = mpegts_packetizer_push_section (packetizer, &packet);
+ if (section)
+ mpegts_base_handle_psi (base, section);
+
/* we need to push section packet downstream */
- res = klass->push (base, &packet, §ion);
+ res = klass->push (base, &packet, section);
} else if (MPEGTS_BIT_IS_SET (base->is_pes, packet.pid)) {
/* push the packet downstream */
GST_DEBUG_CATEGORY_INIT (mpegts_base_debug, "mpegtsbase", 0,
"MPEG transport stream base class");
- gst_mpegtsdesc_init_debug ();
-
return TRUE;
}
*/
#include <string.h>
-
-/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
- * with newer GLib versions (>= 2.31.0) */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
+#include <stdlib.h>
/* Skew calculation pameters */
#define MAX_TIME (2 * GST_SECOND)
GST_DEBUG_CATEGORY_STATIC (mpegts_packetizer_debug);
#define GST_CAT_DEFAULT mpegts_packetizer_debug
-static GQuark QUARK_PAT;
-static GQuark QUARK_TRANSPORT_STREAM_ID;
-static GQuark QUARK_PROGRAM_NUMBER;
-static GQuark QUARK_PID;
-static GQuark QUARK_PROGRAMS;
-
-static GQuark QUARK_CAT;
-
-static GQuark QUARK_PMT;
-static GQuark QUARK_PCR_PID;
-static GQuark QUARK_VERSION_NUMBER;
-static GQuark QUARK_DESCRIPTORS;
-static GQuark QUARK_STREAM_TYPE;
-static GQuark QUARK_STREAMS;
-
-static GQuark QUARK_NIT;
-static GQuark QUARK_NETWORK_ID;
-static GQuark QUARK_CURRENT_NEXT_INDICATOR;
-static GQuark QUARK_ACTUAL_NETWORK;
-static GQuark QUARK_NETWORK_NAME;
-static GQuark QUARK_ORIGINAL_NETWORK_ID;
-static GQuark QUARK_TRANSPORTS;
-static GQuark QUARK_TERRESTRIAL;
-static GQuark QUARK_CABLE;
-static GQuark QUARK_FREQUENCY;
-static GQuark QUARK_MODULATION;
-static GQuark QUARK_BANDWIDTH;
-static GQuark QUARK_CONSTELLATION;
-static GQuark QUARK_HIERARCHY;
-static GQuark QUARK_CODE_RATE_HP;
-static GQuark QUARK_CODE_RATE_LP;
-static GQuark QUARK_GUARD_INTERVAL;
-static GQuark QUARK_TRANSMISSION_MODE;
-static GQuark QUARK_OTHER_FREQUENCY;
-static GQuark QUARK_SYMBOL_RATE;
-static GQuark QUARK_INNER_FEC;
-static GQuark QUARK_DELIVERY;
-static GQuark QUARK_CHANNELS;
-static GQuark QUARK_LOGICAL_CHANNEL_NUMBER;
-
-static GQuark QUARK_SDT;
-static GQuark QUARK_ACTUAL_TRANSPORT_STREAM;
-static GQuark QUARK_SERVICES;
-
-static GQuark QUARK_EIT;
-static GQuark QUARK_SERVICE_ID;
-static GQuark QUARK_PRESENT_FOLLOWING;
-static GQuark QUARK_SEGMENT_LAST_SECTION_NUMBER;
-static GQuark QUARK_LAST_TABLE_ID;
-static GQuark QUARK_EVENTS;
-static GQuark QUARK_NAME;
-static GQuark QUARK_DESCRIPTION;
-static GQuark QUARK_EXTENDED_ITEM;
-static GQuark QUARK_EXTENDED_ITEMS;
-static GQuark QUARK_TEXT;
-static GQuark QUARK_EXTENDED_TEXT;
-static GQuark QUARK_EVENT_ID;
-static GQuark QUARK_YEAR;
-static GQuark QUARK_MONTH;
-static GQuark QUARK_DAY;
-static GQuark QUARK_HOUR;
-static GQuark QUARK_MINUTE;
-static GQuark QUARK_SECOND;
-static GQuark QUARK_DURATION;
-static GQuark QUARK_RUNNING_STATUS;
-static GQuark QUARK_FREE_CA_MODE;
-
-static GQuark QUARK_TDT;
-static GQuark QUARK_TOT;
-
-#define MAX_KNOWN_ICONV 25
-/* All these conversions will be to UTF8 */
-typedef enum
-{
- _ICONV_UNKNOWN = -1,
- _ICONV_ISO8859_1,
- _ICONV_ISO8859_2,
- _ICONV_ISO8859_3,
- _ICONV_ISO8859_4,
- _ICONV_ISO8859_5,
- _ICONV_ISO8859_6,
- _ICONV_ISO8859_7,
- _ICONV_ISO8859_8,
- _ICONV_ISO8859_9,
- _ICONV_ISO8859_10,
- _ICONV_ISO8859_11,
- _ICONV_ISO8859_12,
- _ICONV_ISO8859_13,
- _ICONV_ISO8859_14,
- _ICONV_ISO8859_15,
- _ICONV_ISO10646_UC2,
- _ICONV_EUC_KR,
- _ICONV_GB2312,
- _ICONV_UTF_16BE,
- _ICONV_ISO10646_UTF8,
- _ICONV_ISO6937,
- /* Insert more here if needed */
- _ICONV_MAX
-} LocalIconvCode;
-
-static const gchar *iconvtablename[] = {
- "iso-8859-1",
- "iso-8859-2",
- "iso-8859-3",
- "iso-8859-4",
- "iso-8859-5",
- "iso-8859-6",
- "iso-8859-7",
- "iso-8859-8",
- "iso-8859-9",
- "iso-8859-10",
- "iso-8859-11",
- "iso-8859-12",
- "iso-8859-13",
- "iso-8859-14",
- "iso-8859-15",
- "ISO-10646/UCS2",
- "EUC-KR",
- "GB2312",
- "UTF-16BE",
- "ISO-10646/UTF8",
- "iso6937"
- /* Insert more here if needed */
-};
-
#define MPEGTS_PACKETIZER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_MPEGTS_PACKETIZER, MpegTSPacketizerPrivate))
guint8 pcrtablelut[0x2000];
MpegTSPCR *observations[MAX_PCR_OBS_CHANNELS];
guint8 lastobsid;
-
- /* Conversion tables */
- GIConv iconvs[_ICONV_MAX];
};
static void mpegts_packetizer_dispose (GObject * object);
static void mpegts_packetizer_finalize (GObject * object);
-static gchar *get_encoding_and_convert (MpegTSPacketizer2 * packetizer,
- const gchar * text, guint length);
static GstClockTime calculate_skew (MpegTSPCR * pcr, guint64 pcrtime,
GstClockTime time);
static void record_pcr (MpegTSPacketizer2 * packetizer, MpegTSPCR * pcrtable,
guint64 pcr, guint64 offset);
#define CONTINUITY_UNSET 255
-#define MAX_CONTINUITY 15
#define VERSION_NUMBER_UNSET 255
#define TABLE_ID_UNSET 0xFF
#define PACKET_SYNC_BYTE 0x47
-static MpegTSPCR *
+static inline MpegTSPCR *
get_pcr_table (MpegTSPacketizer2 * packetizer, guint16 pid)
{
MpegTSPacketizerPrivate *priv = packetizer->priv;
{
GSList *tmp;
+ /* FIXME: Make this an array ! */
for (tmp = subtables; tmp; tmp = tmp->next) {
MpegTSPacketizerStreamSubtable *sub =
(MpegTSPacketizerStreamSubtable *) tmp->data;
}
static gboolean
-saw_subtable_crc (GList * list, guint32 crc)
+seen_section_before (MpegTSPacketizerStream * stream, guint8 table_id,
+ guint16 subtable_extension, guint8 version_number, guint8 section_number,
+ guint8 last_section_number)
{
- GList *tmp;
-
- for (tmp = list; tmp; tmp = tmp->next)
- if (GPOINTER_TO_UINT (tmp->data) == crc)
- return TRUE;
+ MpegTSPacketizerStreamSubtable *subtable;
- return FALSE;
+ /* Check if we've seen this table_id/subtable_extension first */
+ subtable = find_subtable (stream->subtables, table_id, subtable_extension);
+ if (!subtable) {
+ GST_DEBUG ("Haven't seen subtale");
+ return FALSE;
+ }
+ /* If we have, check it has the same version_number */
+ if (subtable->version_number != version_number) {
+ GST_DEBUG ("Different version number");
+ return FALSE;
+ }
+ /* Did the number of sections change ? */
+ if (subtable->last_section_number != last_section_number) {
+ GST_DEBUG ("Different last_section_number");
+ return FALSE;
+ }
+ /* Finally return whether we saw that section or not */
+ return MPEGTS_BIT_IS_SET (subtable->seen_section, section_number);
}
static MpegTSPacketizerStreamSubtable *
mpegts_packetizer_stream_subtable_new (guint8 table_id,
- guint16 subtable_extension)
+ guint16 subtable_extension, guint8 last_section_number)
{
MpegTSPacketizerStreamSubtable *subtable;
subtable->version_number = VERSION_NUMBER_UNSET;
subtable->table_id = table_id;
subtable->subtable_extension = subtable_extension;
- subtable->crc = NULL;
+ subtable->last_section_number = last_section_number;
return subtable;
}
static MpegTSPacketizerStream *
-mpegts_packetizer_stream_new (void)
+mpegts_packetizer_stream_new (guint16 pid)
{
MpegTSPacketizerStream *stream;
stream = (MpegTSPacketizerStream *) g_new0 (MpegTSPacketizerStream, 1);
stream->continuity_counter = CONTINUITY_UNSET;
stream->subtables = NULL;
- stream->section_table_id = TABLE_ID_UNSET;
+ stream->table_id = TABLE_ID_UNSET;
+ stream->pid = pid;
return stream;
}
stream->continuity_counter = CONTINUITY_UNSET;
stream->section_length = 0;
stream->section_offset = 0;
- stream->section_table_id = TABLE_ID_UNSET;
+ stream->table_id = TABLE_ID_UNSET;
+ if (stream->section_data)
+ g_free (stream->section_data);
+ stream->section_data = NULL;
}
static void
mpegts_packetizer_stream_subtable_free (MpegTSPacketizerStreamSubtable *
subtable)
{
- g_list_free (subtable->crc);
g_free (subtable);
}
mpegts_packetizer_init (MpegTSPacketizer2 * packetizer)
{
MpegTSPacketizerPrivate *priv;
- guint i;
priv = packetizer->priv = MPEGTS_PACKETIZER_GET_PRIVATE (packetizer);
packetizer->adapter = gst_adapter_new ();
memset (priv->pcrtablelut, 0xff, 0x200);
memset (priv->observations, 0x0, sizeof (priv->observations));
- for (i = 0; i < _ICONV_MAX; i++)
- priv->iconvs[i] = (GIConv) - 1;
-
priv->lastobsid = 0;
priv->nb_seen_offsets = 0;
mpegts_packetizer_dispose (GObject * object)
{
MpegTSPacketizer2 *packetizer = GST_MPEGTS_PACKETIZER (object);
- guint i;
if (!packetizer->disposed) {
if (packetizer->know_packet_size && packetizer->caps != NULL) {
packetizer->offset = 0;
packetizer->empty = TRUE;
- for (i = 0; i < _ICONV_MAX; i++)
- if (packetizer->priv->iconvs[i] != (GIConv) - 1)
- g_iconv_close (packetizer->priv->iconvs[i]);
-
flush_observations (packetizer);
}
return TRUE;
}
- if (packet->adaptation_field_control == 0x20) {
+ if (FLAGS_HAS_AFC (packet->scram_afc_cc)) {
/* no payload, adaptation field of 183 bytes */
if (length != 183) {
- GST_DEBUG ("PID %d afc == 0x%x and length %d != 183",
- packet->pid, packet->adaptation_field_control, length);
+ GST_DEBUG ("PID %d afc == 0x%02x and length %d != 183",
+ packet->pid, packet->scram_afc_cc & 0x30, length);
}
} else if (length > 182) {
- GST_DEBUG ("PID %d afc == 0x%01x and length %d > 182",
- packet->pid, packet->adaptation_field_control, length);
+ GST_DEBUG ("PID %d afc == 0x%02x and length %d > 182",
+ packet->pid, packet->scram_afc_cc & 0x30, length);
}
if (packet->data + length > packet->data_end) {
packet->pid = GST_READ_UINT16_BE (data) & 0x1FFF;
data += 2;
- tmp = *data;
+ packet->scram_afc_cc = tmp = *data++;
/* transport_scrambling_control 2 */
if (G_UNLIKELY (tmp & 0xc0))
return PACKET_BAD;
- /* adaptation_field_control 2 */
- packet->adaptation_field_control = tmp & 0x30;
-
- /* continuity_counter 4 */
- packet->continuity_counter = tmp & 0x0F;
- data += 1;
-
packet->data = data;
- if (packet->adaptation_field_control & 0x20)
+ if (FLAGS_HAS_AFC (tmp))
if (!mpegts_packetizer_parse_adaptation_field_control (packetizer, packet))
return FALSE;
- if (packet->adaptation_field_control & 0x10)
+ if (FLAGS_HAS_PAYLOAD (tmp))
packet->payload = packet->data;
else
packet->payload = NULL;
return PACKET_OK;
}
-static gboolean
+static GstMpegTSSection *
mpegts_packetizer_parse_section_header (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerStream * stream, MpegTSPacketizerSection * section)
+ MpegTSPacketizerStream * stream)
{
- guint8 tmp;
- guint8 *data, *crc_data;
MpegTSPacketizerStreamSubtable *subtable;
-
- section->complete = TRUE;
- /* get the section buffer, ownership stays with the stream */
- data = section->data = stream->section_data;
- section->offset = stream->offset;
-
- GST_MEMDUMP ("section header", data, stream->section_length);
-
- /* table_id : 8 bits
- * NOTE : Already parsed/stored in _push_section()
- */
- section->table_id = stream->section_table_id;
- data += 1;
-
- /* section_syntax_indicator : 1 bit
- * private_indicator : 1 bit
- * RESERVED : 2 bit
- * private_section_length : 12 bit
- */
- /* if table_id is 0 (pat) then ignore the subtable extension */
- if ((data[0] & 0x80) == 0 || section->table_id == 0)
- section->subtable_extension = 0;
- else
- section->subtable_extension = GST_READ_UINT16_BE (data + 2);
+ GstMpegTSSection *res;
subtable =
- find_subtable (stream->subtables, section->table_id,
- section->subtable_extension);
+ find_subtable (stream->subtables, stream->table_id,
+ stream->subtable_extension);
if (subtable) {
- GST_DEBUG ("Found previous subtable_extension:%d",
- section->subtable_extension);
+ GST_DEBUG ("Found previous subtable_extension:0x%04x",
+ stream->subtable_extension);
+ if (G_UNLIKELY (stream->version_number != subtable->version_number)) {
+ /* If the version number changed, reset the subtable */
+ subtable->version_number = stream->version_number;
+ subtable->last_section_number = stream->last_section_number;
+ memset (subtable->seen_section, 0, 32);
+ }
} else {
- GST_DEBUG ("Appending new subtable_extension:%d",
- section->subtable_extension);
- subtable = mpegts_packetizer_stream_subtable_new (section->table_id,
- section->subtable_extension);
-
+ GST_DEBUG ("Appending new subtable_extension: 0x%04x",
+ stream->subtable_extension);
+ subtable = mpegts_packetizer_stream_subtable_new (stream->table_id,
+ stream->subtable_extension, stream->last_section_number);
+ subtable->version_number = stream->version_number;
stream->subtables = g_slist_prepend (stream->subtables, subtable);
}
- /* private_section_length : 12 bit
- * NOTE : Already parsed/stored in _push_section()
- * NOTE : Same as private_section_length mentionned above
- */
- section->section_length = stream->section_length;
- data += 2;
-
- /* transport_stream_id : 16 bit */
- /* skip to the version byte */
- data += 2;
-
- /* Reserved : 2 bits
- * version_number : 5 bits
- * current_next_indicator : 1 bit*/
- tmp = *data++;
- section->version_number = (tmp >> 1) & 0x1F;
- section->current_next_indicator = tmp & 0x01;
-
- if (!section->current_next_indicator)
- goto not_applicable;
-
- /* CRC is at the end of the section */
- crc_data = section->data + section->section_length - 4;
- section->crc = GST_READ_UINT32_BE (crc_data);
-
- /* If the section version number hasn't changed and we have
- * already seen this exact section before, don't process further
- */
- if (section->version_number == subtable->version_number &&
- saw_subtable_crc (subtable->crc, section->crc))
- goto no_changes;
-
- /* If the version number changed, reset our observations */
- if (section->version_number != subtable->version_number)
- g_list_free (subtable->crc);
-
- GST_DEBUG
- ("section changed. pid 0x%04x table_id 0x%03x subtable_extension %d version number:%d (previous%d) crc 0x%x",
- section->pid, section->table_id, section->subtable_extension,
- section->version_number, subtable->version_number, section->crc);
-
- subtable->version_number = section->version_number;
- subtable->crc =
- g_list_prepend (subtable->crc, GUINT_TO_POINTER (section->crc));
- stream->section_table_id = section->table_id;
-
- return TRUE;
+ GST_MEMDUMP ("Full section data", stream->section_data,
+ stream->section_length);
+ /* TODO ? : Replace this by an efficient version (where we provide all
+ * pre-parsed header data) */
+ res =
+ gst_mpegts_section_new (stream->pid, stream->section_data,
+ stream->section_allocated);
+ stream->section_data = NULL;
-no_changes:
- GST_LOG
- ("no changes. pid 0x%04x table_id 0x%02x subtable_extension %d, current_next %d version %d, crc 0x%x",
- section->pid, section->table_id, section->subtable_extension,
- section->current_next_indicator, section->version_number, section->crc);
- section->complete = FALSE;
- return TRUE;
+ if (res) {
+ /* NOTE : Due to the new mpegts-si system, There is a insanely low probability
+ * that we might have gotten a section that was corrupted (i.e. wrong crc)
+ * and that we consider it as seen.
+ *
+ * The reason why we consider this as acceptable is because all the previous
+ * checks were already done:
+ * * transport layer checks (DVB)
+ * * 0x47 validation
+ * * continuity counter validation
+ * * subtable validation
+ * * section_number validation
+ * * section_length validation
+ *
+ * The probability of this happening vs the overhead of doing CRC checks
+ * on all sections (including those we would not use) is just not worth it.
+ * */
+ MPEGTS_BIT_SET (subtable->seen_section, stream->section_number);
+ res->offset = stream->offset;
+ }
-not_applicable:
- GST_LOG
- ("not applicable pid 0x%04x table_id 0x%02x subtable_extension %d, current_next %d version %d, crc 0x%x",
- section->pid, section->table_id, section->subtable_extension,
- section->current_next_indicator, section->version_number, section->crc);
- section->complete = FALSE;
- return TRUE;
+ return res;
}
-static inline void
-set_descriptors_array_on_structure (GstStructure * structure, GQuark quark,
- GValueArray * descriptors)
+void
+mpegts_packetizer_clear (MpegTSPacketizer2 * packetizer)
{
- GValue value = { 0 };
+ if (packetizer->know_packet_size) {
+ packetizer->know_packet_size = FALSE;
+ packetizer->packet_size = 0;
+ if (packetizer->caps != NULL) {
+ gst_caps_unref (packetizer->caps);
+ packetizer->caps = NULL;
+ }
+ }
+ if (packetizer->streams) {
+ int i;
+ for (i = 0; i < 8192; i++) {
+ if (packetizer->streams[i]) {
+ mpegts_packetizer_stream_free (packetizer->streams[i]);
+ }
+ }
+ memset (packetizer->streams, 0, 8192 * sizeof (MpegTSPacketizerStream *));
+ }
- g_value_init (&value, G_TYPE_VALUE_ARRAY);
- g_value_take_boxed (&value, descriptors);
- gst_structure_id_take_value (structure, quark, &value);
+ gst_adapter_clear (packetizer->adapter);
+ packetizer->offset = 0;
+ packetizer->empty = TRUE;
+ packetizer->priv->available = 0;
+ packetizer->priv->mapped = NULL;
+ packetizer->priv->mapped_size = 0;
+ packetizer->priv->offset = 0;
+ packetizer->priv->last_in_time = GST_CLOCK_TIME_NONE;
}
-static GValueArray *
-mpegts_packetizer_parse_descriptors (MpegTSPacketizer2 * packetizer,
- guint8 ** buffer, guint8 * buffer_end)
+void
+mpegts_packetizer_flush (MpegTSPacketizer2 * packetizer, gboolean hard)
{
- GValueArray *descriptors = NULL;
- guint8 length;
- guint8 *data;
- GString *desc;
- guint i, nb_desc = 0;
-
- data = *buffer;
-
- while (data < buffer_end) {
- data++; /* skip tag */
- length = *data++;
+ GST_DEBUG ("Flushing");
- if (data + length > buffer_end) {
- GST_WARNING ("invalid descriptor length %d now at %d max %d", length,
- (gint) (data - *buffer), (gint) (buffer_end - *buffer));
- goto error;
+ if (packetizer->streams) {
+ int i;
+ for (i = 0; i < 8192; i++) {
+ if (packetizer->streams[i]) {
+ mpegts_packetizer_clear_section (packetizer->streams[i]);
+ }
}
-
- data += length;
- nb_desc++;
}
+ gst_adapter_clear (packetizer->adapter);
- if (data != buffer_end) {
- GST_WARNING ("descriptors size %d expected %d", (gint) (data - *buffer),
- (gint) (buffer_end - *buffer));
- goto error;
+ packetizer->offset = 0;
+ packetizer->empty = TRUE;
+ packetizer->priv->available = 0;
+ packetizer->priv->mapped = NULL;
+ packetizer->priv->offset = 0;
+ packetizer->priv->mapped_size = 0;
+ packetizer->priv->last_in_time = GST_CLOCK_TIME_NONE;
+ if (hard) {
+ /* For pull mode seeks in tsdemux the observation must be preserved */
+ flush_observations (packetizer);
}
+}
- data = *buffer;
- descriptors = g_value_array_new (nb_desc);
-
- for (i = 0; i < nb_desc; i++) {
- GValue *value = &(descriptors->values[i]);
- data++; /* skip tag */
- length = *data++;
-
- /* include length */
- desc = g_string_new_len ((gchar *) data - 2, length + 2);
- data += length;
- /* G_TYPE_GSTRING is a GBoxed type and is used so properly marshalled from python */
- g_value_init (value, G_TYPE_GSTRING);
- g_value_take_boxed (value, desc);
+void
+mpegts_packetizer_remove_stream (MpegTSPacketizer2 * packetizer, gint16 pid)
+{
+ MpegTSPacketizerStream *stream = packetizer->streams[pid];
+ if (stream) {
+ GST_INFO ("Removing stream for PID %d", pid);
+ mpegts_packetizer_stream_free (stream);
+ packetizer->streams[pid] = NULL;
}
-
- descriptors->n_values = nb_desc;
-
- *buffer = data;
-
- return descriptors;
-
-error:
- return NULL;
}
-GstStructure *
-mpegts_packetizer_parse_cat (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerSection * section)
+MpegTSPacketizer2 *
+mpegts_packetizer_new (void)
{
- GstStructure *cat_info = NULL;
- guint8 *data;
- guint8 tmp;
- GValueArray *descriptors;
- GstMPEGDescriptor desc;
- guint desc_len;
-
- /* Skip parts already parsed */
- data = section->data + 3;
-
- /* reserved : 18bits */
- data += 2;
-
- /* version_number : 5 bits
- * current_next_indicator : 1 bit */
- tmp = *data++;
- section->version_number = (tmp >> 1) & 0x1F;
- section->current_next_indicator = tmp & 0x01;
+ MpegTSPacketizer2 *packetizer;
- /* skip already handled section_number and last_section_number */
- data += 2;
+ packetizer =
+ GST_MPEGTS_PACKETIZER (g_object_new (GST_TYPE_MPEGTS_PACKETIZER, NULL));
- cat_info = gst_structure_new_id_empty (QUARK_CAT);
-
- /* descriptors */
- desc_len = section->section_length - 4 - 8;
- gst_mpeg_descriptor_parse (&desc, data, desc_len);
- descriptors =
- mpegts_packetizer_parse_descriptors (packetizer, &data, data + desc_len);
- if (descriptors == NULL)
- goto error;
- set_descriptors_array_on_structure (cat_info, QUARK_DESCRIPTORS, descriptors);
-
- return cat_info;
-error:
- if (cat_info)
- gst_structure_free (cat_info);
- return NULL;
+ return packetizer;
}
-GstStructure *
-mpegts_packetizer_parse_pat (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerSection * section)
+void
+mpegts_packetizer_push (MpegTSPacketizer2 * packetizer, GstBuffer * buffer)
{
- GstStructure *pat_info = NULL;
- guint8 *data, *end;
- guint transport_stream_id;
- guint8 tmp;
- guint program_number;
- guint pmt_pid;
- GValue entries = { 0 };
- GValue value = { 0 };
- GstStructure *entry = NULL;
- gchar *struct_name;
-
- data = section->data;
-
- data += 3;
+ if (G_UNLIKELY (packetizer->empty)) {
+ packetizer->empty = FALSE;
+ packetizer->offset = GST_BUFFER_OFFSET (buffer);
+ }
- transport_stream_id = GST_READ_UINT16_BE (data);
- data += 2;
+ GST_DEBUG ("Pushing %" G_GSIZE_FORMAT " byte from offset %"
+ G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
+ GST_BUFFER_OFFSET (buffer));
+ gst_adapter_push (packetizer->adapter, buffer);
+ packetizer->priv->available += gst_buffer_get_size (buffer);
+ /* If buffer timestamp is valid, store it */
+ if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)))
+ packetizer->priv->last_in_time = GST_BUFFER_TIMESTAMP (buffer);
+}
- tmp = *data++;
- section->version_number = (tmp >> 1) & 0x1F;
- section->current_next_indicator = tmp & 0x01;
+static gboolean
+mpegts_try_discover_packet_size (MpegTSPacketizer2 * packetizer)
+{
+ guint8 *dest;
+ int i, pos = -1, j;
+ static const guint psizes[] = {
+ MPEGTS_NORMAL_PACKETSIZE,
+ MPEGTS_M2TS_PACKETSIZE,
+ MPEGTS_DVB_ASI_PACKETSIZE,
+ MPEGTS_ATSC_PACKETSIZE
+ };
- /* skip section_number and last_section_number */
- data += 2;
- pat_info = gst_structure_new_id (QUARK_PAT,
- QUARK_TRANSPORT_STREAM_ID, G_TYPE_UINT, transport_stream_id, NULL);
- g_value_init (&entries, GST_TYPE_LIST);
- /* stop at the CRC */
- end = section->data + section->section_length;
- while (data < end - 4) {
- program_number = GST_READ_UINT16_BE (data);
- data += 2;
+ dest = g_malloc (MPEGTS_MAX_PACKETSIZE * 4);
+ /* wait for 3 sync bytes */
+ while (packetizer->priv->available >= MPEGTS_MAX_PACKETSIZE * 4) {
- pmt_pid = GST_READ_UINT16_BE (data) & 0x1FFF;
- data += 2;
+ /* check for sync bytes */
+ gst_adapter_copy (packetizer->adapter, dest, 0, MPEGTS_MAX_PACKETSIZE * 4);
+ /* find first sync byte */
+ pos = -1;
+ for (i = 0; i < MPEGTS_MAX_PACKETSIZE; i++) {
+ if (dest[i] == PACKET_SYNC_BYTE) {
+ for (j = 0; j < 4; j++) {
+ guint packetsize = psizes[j];
+ /* check each of the packet size possibilities in turn */
+ if (dest[i] == PACKET_SYNC_BYTE
+ && dest[i + packetsize] == PACKET_SYNC_BYTE
+ && dest[i + packetsize * 2] == PACKET_SYNC_BYTE
+ && dest[i + packetsize * 3] == PACKET_SYNC_BYTE) {
+ packetizer->know_packet_size = TRUE;
+ packetizer->packet_size = packetsize;
+ packetizer->caps = gst_caps_new_simple ("video/mpegts",
+ "systemstream", G_TYPE_BOOLEAN, TRUE,
+ "packetsize", G_TYPE_INT, packetsize, NULL);
+ if (packetsize == MPEGTS_M2TS_PACKETSIZE)
+ pos = i - 4;
+ else
+ pos = i;
+ break;
+ }
+ }
+ break;
+ }
+ }
- struct_name = g_strdup_printf ("program-%d", program_number);
- entry = gst_structure_new_empty (struct_name);
- g_free (struct_name);
- gst_structure_id_set (entry, QUARK_PROGRAM_NUMBER, G_TYPE_UINT,
- program_number, QUARK_PID, G_TYPE_UINT, pmt_pid, NULL);
+ if (packetizer->know_packet_size)
+ break;
- g_value_init (&value, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&value, entry);
- gst_value_list_append_and_take_value (&entries, &value);
+ /* Skip MPEGTS_MAX_PACKETSIZE */
+ gst_adapter_flush (packetizer->adapter, MPEGTS_MAX_PACKETSIZE);
+ packetizer->priv->available -= MPEGTS_MAX_PACKETSIZE;
+ packetizer->offset += MPEGTS_MAX_PACKETSIZE;
}
- gst_structure_id_take_value (pat_info, QUARK_PROGRAMS, &entries);
-
- if (data != end - 4) {
- /* FIXME: check the CRC before parsing the packet */
- GST_ERROR ("at the end of PAT data != end - 4");
- gst_structure_free (pat_info);
+ g_free (dest);
- return NULL;
+ if (packetizer->know_packet_size) {
+ GST_DEBUG ("have packetsize detected: %d of %u bytes",
+ packetizer->know_packet_size, packetizer->packet_size);
+ /* flush to sync byte */
+ if (pos > 0) {
+ GST_DEBUG ("Flushing out %d bytes", pos);
+ gst_adapter_flush (packetizer->adapter, pos);
+ packetizer->offset += pos;
+ packetizer->priv->available -= MPEGTS_MAX_PACKETSIZE;
+ }
+ } else {
+ /* drop invalid data and move to the next possible packets */
+ GST_DEBUG ("Could not determine packet size");
}
- return pat_info;
+ return packetizer->know_packet_size;
}
-GstStructure *
-mpegts_packetizer_parse_pmt (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerSection * section)
+gboolean
+mpegts_packetizer_has_packets (MpegTSPacketizer2 * packetizer)
{
- GstStructure *pmt = NULL;
- guint8 *data, *end;
- guint16 program_number;
- guint8 tmp;
- guint pcr_pid;
- guint program_info_length;
- guint8 stream_type;
- guint16 pid;
- guint stream_info_length;
- GValueArray *descriptors;
- GValue stream_value = { 0 };
- GValue programs = { 0 };
- GstStructure *stream_info = NULL;
- gchar *struct_name;
-
- /* fixed header + CRC == 16 */
- if (section->section_length < 16) {
- GST_WARNING ("PID %d invalid PMT size %d",
- section->pid, section->section_length);
- goto error;
+ if (G_UNLIKELY (packetizer->know_packet_size == FALSE)) {
+ if (!mpegts_try_discover_packet_size (packetizer))
+ return FALSE;
}
+ return packetizer->priv->available >= packetizer->packet_size;
+}
- data = section->data;
- end = data + section->section_length;
-
- data += 3;
-
- program_number = GST_READ_UINT16_BE (data);
- data += 2;
-
- GST_DEBUG ("Parsing %d Program Map Table", program_number);
-
- tmp = *data++;
- section->version_number = (tmp >> 1) & 0x1F;
- section->current_next_indicator = tmp & 0x01;
-
- /* skip section_number and last_section_number */
- data += 2;
-
- pcr_pid = GST_READ_UINT16_BE (data) & 0x1FFF;
- data += 2;
+MpegTSPacketizerPacketReturn
+mpegts_packetizer_next_packet (MpegTSPacketizer2 * packetizer,
+ MpegTSPacketizerPacket * packet)
+{
+ MpegTSPacketizerPrivate *priv = packetizer->priv;
+ guint skip;
+ guint sync_offset;
- program_info_length = GST_READ_UINT16_BE (data) & 0x0FFF;
- data += 2;
+ if (G_UNLIKELY (!packetizer->know_packet_size)) {
+ if (!mpegts_try_discover_packet_size (packetizer))
+ return PACKET_NEED_MORE;
+ }
- pmt = gst_structure_new_id (QUARK_PMT,
- QUARK_PROGRAM_NUMBER, G_TYPE_UINT, program_number,
- QUARK_PCR_PID, G_TYPE_UINT, pcr_pid,
- QUARK_VERSION_NUMBER, G_TYPE_UINT, section->version_number, NULL);
-
- if (program_info_length) {
- /* check that the buffer is large enough to contain at least
- * program_info_length bytes + CRC */
- if (data + program_info_length + 4 > end) {
- GST_WARNING ("PID %d invalid program info length %d left %d",
- section->pid, program_info_length, (gint) (end - data));
- goto error;
+ while (priv->available >= packetizer->packet_size) {
+ if (priv->mapped == NULL) {
+ priv->mapped_size = priv->available;
+ priv->mapped =
+ (guint8 *) gst_adapter_map (packetizer->adapter, priv->mapped_size);
+ priv->offset = 0;
}
- descriptors =
- mpegts_packetizer_parse_descriptors (packetizer, &data,
- data + program_info_length);
- if (descriptors == NULL)
- goto error;
-
- set_descriptors_array_on_structure (pmt, QUARK_DESCRIPTORS, descriptors);
- }
-
- g_value_init (&programs, GST_TYPE_LIST);
- /* parse entries, cycle until there's space for another entry (at least 5
- * bytes) plus the CRC */
- while (data <= end - 4 - 5) {
- stream_type = *data++;
- GST_DEBUG ("Stream type 0x%02x found", stream_type);
-
- pid = GST_READ_UINT16_BE (data) & 0x1FFF;
- data += 2;
-
- stream_info_length = GST_READ_UINT16_BE (data) & 0x0FFF;
- data += 2;
-
- if (data + stream_info_length + 4 > end) {
- GST_WARNING ("PID %d invalid stream info length %d left %d", section->pid,
- stream_info_length, (gint) (end - data));
- g_value_unset (&programs);
- goto error;
- }
-
- struct_name = g_strdup_printf ("pid-%d", pid);
- stream_info = gst_structure_new_empty (struct_name);
- g_free (struct_name);
- gst_structure_id_set (stream_info,
- QUARK_PID, G_TYPE_UINT, pid, QUARK_STREAM_TYPE, G_TYPE_UINT,
- stream_type, NULL);
-
- if (stream_info_length) {
- /* check for AC3 descriptor */
- GstMPEGDescriptor desc;
-
- if (gst_mpeg_descriptor_parse (&desc, data, stream_info_length)) {
- /* DVB AC3 */
- guint8 *desc_data;
- if (gst_mpeg_descriptor_find (&desc, DESC_DVB_AC3)) {
- gst_structure_set (stream_info, "has-ac3", G_TYPE_BOOLEAN, TRUE,
- NULL);
- }
-
- /* DATA BROADCAST ID */
- desc_data =
- gst_mpeg_descriptor_find (&desc, DESC_DVB_DATA_BROADCAST_ID);
- if (desc_data) {
- guint16 data_broadcast_id;
- data_broadcast_id =
- DESC_DVB_DATA_BROADCAST_ID_data_broadcast_id (desc_data);
- gst_structure_set (stream_info, "data-broadcast-id", G_TYPE_UINT,
- data_broadcast_id, NULL);
- }
-
- /* DATA BROADCAST */
- desc_data = gst_mpeg_descriptor_find (&desc, DESC_DVB_DATA_BROADCAST);
- if (desc_data) {
- GstStructure *databroadcast_info;
- guint16 data_broadcast_id;
- guint8 component_tag;
- data_broadcast_id =
- DESC_DVB_DATA_BROADCAST_data_broadcast_id (desc_data);
- component_tag = DESC_DVB_DATA_BROADCAST_component_tag (desc_data);
- databroadcast_info = gst_structure_new ("data-broadcast", "id",
- G_TYPE_UINT, data_broadcast_id, "component-tag", component_tag,
- NULL);
- gst_structure_set (stream_info, "data-broadcast", GST_TYPE_STRUCTURE,
- databroadcast_info, NULL);
- }
-
- /* DVB CAROUSEL IDENTIFIER */
- desc_data =
- gst_mpeg_descriptor_find (&desc, DESC_DVB_CAROUSEL_IDENTIFIER);
- if (desc_data) {
- guint32 carousel_id;
- carousel_id = DESC_DVB_CAROUSEL_IDENTIFIER_carousel_id (desc_data);
- gst_structure_set (stream_info, "carousel-id", G_TYPE_UINT,
- carousel_id, NULL);
- }
-
- /* DVB STREAM IDENTIFIER */
- desc_data =
- gst_mpeg_descriptor_find (&desc, DESC_DVB_STREAM_IDENTIFIER);
- if (desc_data) {
- guint8 component_tag;
- component_tag = DESC_DVB_STREAM_IDENTIFIER_component_tag (desc_data);
- gst_structure_set (stream_info, "component-tag", G_TYPE_UINT,
- component_tag, NULL);
- }
-
- /* ISO 639 LANGUAGE */
- desc_data = gst_mpeg_descriptor_find (&desc, DESC_ISO_639_LANGUAGE);
- if (!desc_data) {
- desc_data = gst_mpeg_descriptor_find (&desc, DESC_DVB_SUBTITLING);
- }
- if (desc_data && DESC_ISO_639_LANGUAGE_codes_n (desc_data)) {
- gchar *lang_code;
- gchar *language_n = (gchar *)
- DESC_ISO_639_LANGUAGE_language_code_nth (desc_data, 0);
- lang_code = g_strndup (language_n, 3);
- gst_structure_set (stream_info, "lang-code", G_TYPE_STRING,
- lang_code, NULL);
- g_free (lang_code);
- }
-
- descriptors =
- mpegts_packetizer_parse_descriptors (packetizer, &data,
- data + stream_info_length);
- if (descriptors == NULL) {
- g_value_unset (&programs);
- gst_structure_free (stream_info);
- goto error;
- }
-
- set_descriptors_array_on_structure (stream_info, QUARK_DESCRIPTORS,
- descriptors);
- }
- }
-
- g_value_init (&stream_value, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&stream_value, stream_info);
- gst_value_list_append_and_take_value (&programs, &stream_value);
- }
-
- gst_structure_id_take_value (pmt, QUARK_STREAMS, &programs);
-
- g_assert (data == end - 4);
-
- return pmt;
-
-error:
- if (pmt)
- gst_structure_free (pmt);
-
- return NULL;
-}
-
-GstStructure *
-mpegts_packetizer_parse_nit (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerSection * section)
-{
- GstStructure *nit = NULL, *transport = NULL, *delivery_structure = NULL;
- guint8 *data, *end, *entry_begin;
- guint16 network_id, transport_stream_id, original_network_id;
- guint tmp;
- guint16 descriptors_loop_length, transport_stream_loop_length;
- GValue transports = { 0 };
- GValue transport_value = { 0 };
- GValue tmpval = G_VALUE_INIT;
- GValueArray *descriptors = NULL;
-
- GST_DEBUG ("NIT");
-
- /* fixed header + CRC == 16 */
- if (section->section_length < 23) {
- GST_WARNING ("PID %d invalid NIT size %d",
- section->pid, section->section_length);
- goto error;
- }
-
- data = section->data;
- end = data + section->section_length;
-
- data += 3;
-
- network_id = GST_READ_UINT16_BE (data);
- data += 2;
-
- tmp = *data++;
- section->version_number = (tmp >> 1) & 0x1F;
- section->current_next_indicator = tmp & 0x01;
-
- /* skip section_number and last_section_number */
- data += 2;
-
- descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
- data += 2;
-
- nit = gst_structure_new_id (QUARK_NIT,
- QUARK_NETWORK_ID, G_TYPE_UINT, network_id,
- QUARK_VERSION_NUMBER, G_TYPE_UINT, section->version_number,
- QUARK_CURRENT_NEXT_INDICATOR, G_TYPE_UINT,
- section->current_next_indicator, QUARK_ACTUAL_NETWORK, G_TYPE_BOOLEAN,
- section->table_id == 0x40, NULL);
-
- /* see if the buffer is large enough */
- if (descriptors_loop_length) {
- guint8 *networkname_descriptor;
- GstMPEGDescriptor mpegdescriptor;
-
- if (data + descriptors_loop_length > end - 4) {
- GST_WARNING ("PID %d invalid NIT descriptors loop length %d",
- section->pid, descriptors_loop_length);
- gst_structure_free (nit);
- goto error;
- }
- if (gst_mpeg_descriptor_parse (&mpegdescriptor, data,
- descriptors_loop_length)) {
- networkname_descriptor =
- gst_mpeg_descriptor_find (&mpegdescriptor, DESC_DVB_NETWORK_NAME);
- if (networkname_descriptor != NULL) {
- gchar *networkname_tmp;
-
- /* No need to bounds check this value as it comes from the descriptor length itself */
- guint8 networkname_length =
- DESC_DVB_NETWORK_NAME_length (networkname_descriptor);
- gchar *networkname =
- (gchar *) DESC_DVB_NETWORK_NAME_text (networkname_descriptor);
-
- networkname_tmp =
- get_encoding_and_convert (packetizer, networkname,
- networkname_length);
- gst_structure_id_set (nit, QUARK_NETWORK_NAME, G_TYPE_STRING,
- networkname_tmp, NULL);
- g_free (networkname_tmp);
- }
-
- descriptors =
- mpegts_packetizer_parse_descriptors (packetizer, &data,
- data + descriptors_loop_length);
- if (!descriptors) {
- gst_structure_free (nit);
- goto error;
- }
- set_descriptors_array_on_structure (nit, QUARK_DESCRIPTORS, descriptors);
- }
- }
-
- transport_stream_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
- data += 2;
-
- g_value_init (&transports, GST_TYPE_LIST);
- /* read up to the CRC */
- while (transport_stream_loop_length - 4 > 0) {
- gchar *transport_name;
-
- entry_begin = data;
-
- if (transport_stream_loop_length < 10) {
- /* each entry must be at least 6 bytes (+ 4bytes CRC) */
- GST_WARNING ("PID %d invalid NIT entry size %d",
- section->pid, transport_stream_loop_length);
- goto error;
- }
-
- transport_stream_id = GST_READ_UINT16_BE (data);
- data += 2;
-
- original_network_id = GST_READ_UINT16_BE (data);
- data += 2;
-
- descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
- data += 2;
-
- transport_name = g_strdup_printf ("transport-%d", transport_stream_id);
- transport = gst_structure_new_empty (transport_name);
- g_free (transport_name);
- gst_structure_id_set (transport,
- QUARK_TRANSPORT_STREAM_ID, G_TYPE_UINT, transport_stream_id,
- QUARK_ORIGINAL_NETWORK_ID, G_TYPE_UINT, original_network_id, NULL);
-
- if (descriptors_loop_length) {
- GstMPEGDescriptor mpegdescriptor;
- guint8 *delivery;
-
- if (data + descriptors_loop_length > end - 4) {
- GST_WARNING ("PID %d invalid NIT entry %d descriptors loop length %d",
- section->pid, transport_stream_id, descriptors_loop_length);
- gst_structure_free (transport);
- goto error;
- }
- gst_mpeg_descriptor_parse (&mpegdescriptor, data,
- descriptors_loop_length);
-
- if ((delivery = gst_mpeg_descriptor_find (&mpegdescriptor,
- DESC_DVB_SATELLITE_DELIVERY_SYSTEM))) {
-
- guint8 *frequency_bcd =
- DESC_DVB_SATELLITE_DELIVERY_SYSTEM_frequency (delivery);
- guint32 frequency =
- 10 * ((frequency_bcd[3] & 0x0F) +
- 10 * ((frequency_bcd[3] & 0xF0) >> 4) +
- 100 * (frequency_bcd[2] & 0x0F) +
- 1000 * ((frequency_bcd[2] & 0xF0) >> 4) +
- 10000 * (frequency_bcd[1] & 0x0F) +
- 100000 * ((frequency_bcd[1] & 0xF0) >> 4) +
- 1000000 * (frequency_bcd[0] & 0x0F) +
- 10000000 * ((frequency_bcd[0] & 0xF0) >> 4));
- guint8 *orbital_bcd =
- DESC_DVB_SATELLITE_DELIVERY_SYSTEM_orbital_position (delivery);
- gfloat orbital =
- (orbital_bcd[1] & 0x0F) / 10. + ((orbital_bcd[1] & 0xF0) >> 4) +
- 10 * (orbital_bcd[0] & 0x0F) + 100 * ((orbital_bcd[0] & 0xF0) >> 4);
- gboolean east =
- DESC_DVB_SATELLITE_DELIVERY_SYSTEM_west_east_flag (delivery);
- guint8 polarization =
- DESC_DVB_SATELLITE_DELIVERY_SYSTEM_polarization (delivery);
- const gchar *polarization_str;
- guint8 modulation =
- DESC_DVB_SATELLITE_DELIVERY_SYSTEM_modulation (delivery);
- const gchar *modulation_str;
- guint8 *symbol_rate_bcd =
- DESC_DVB_SATELLITE_DELIVERY_SYSTEM_symbol_rate (delivery);
- guint32 symbol_rate =
- (symbol_rate_bcd[2] & 0x0F) +
- 10 * ((symbol_rate_bcd[2] & 0xF0) >> 4) +
- 100 * (symbol_rate_bcd[1] & 0x0F) +
- 1000 * ((symbol_rate_bcd[1] & 0xF0) >> 4) +
- 10000 * (symbol_rate_bcd[0] & 0x0F) +
- 100000 * ((symbol_rate_bcd[0] & 0xF0) >> 4);
- guint8 fec_inner =
- DESC_DVB_SATELLITE_DELIVERY_SYSTEM_fec_inner (delivery);
- const gchar *fec_inner_str;
-
- switch (polarization) {
- case 0:
- polarization_str = "horizontal";
- break;
- case 1:
- polarization_str = "vertical";
- break;
- case 2:
- polarization_str = "left";
- break;
- case 3:
- polarization_str = "right";
- break;
- default:
- polarization_str = "";
- }
- switch (fec_inner) {
- case 0:
- fec_inner_str = "undefined";
- break;
- case 1:
- fec_inner_str = "1/2";
- break;
- case 2:
- fec_inner_str = "2/3";
- break;
- case 3:
- fec_inner_str = "3/4";
- break;
- case 4:
- fec_inner_str = "5/6";
- break;
- case 5:
- fec_inner_str = "7/8";
- break;
- case 6:
- fec_inner_str = "8/9";
- break;
- case 0xF:
- fec_inner_str = "none";
- break;
- default:
- fec_inner_str = "reserved";
- }
- switch (modulation) {
- case 0x00:
- modulation_str = "auto";
- break;
- case 0x01:
- modulation_str = "QPSK";
- break;
- case 0x02:
- modulation_str = "8PSK";
- break;
- case 0x03:
- modulation_str = "QAM16";
- break;
- default:
- modulation_str = "";
- break;
- }
- delivery_structure = gst_structure_new ("satellite",
- "orbital", G_TYPE_FLOAT, orbital,
- "east-or-west", G_TYPE_STRING, east ? "east" : "west",
- "modulation", G_TYPE_STRING, modulation_str,
- "frequency", G_TYPE_UINT, frequency,
- "polarization", G_TYPE_STRING, polarization_str,
- "symbol-rate", G_TYPE_UINT, symbol_rate,
- "inner-fec", G_TYPE_STRING, fec_inner_str, NULL);
- g_value_init (&tmpval, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&tmpval, delivery_structure);
- gst_structure_id_take_value (transport, QUARK_DELIVERY, &tmpval);
- } else if ((delivery = gst_mpeg_descriptor_find (&mpegdescriptor,
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM))) {
-
- guint32 frequency =
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_frequency (delivery) * 10;
- guint8 bandwidth =
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_bandwidth (delivery);
- guint8 constellation =
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_constellation (delivery);
- guint8 hierarchy =
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_hierarchy (delivery);
- guint8 code_rate_hp =
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_code_rate_hp (delivery);
- guint8 code_rate_lp =
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_code_rate_lp (delivery);
- guint8 guard_interval =
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_guard_interval (delivery);
- guint8 transmission_mode =
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_transmission_mode (delivery);
- gboolean other_frequency =
- DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM_other_frequency (delivery);
- const gchar *constellation_str, *code_rate_hp_str, *code_rate_lp_str,
- *transmission_mode_str;
- /* do the stuff */
- /* bandwidth is 8 if 0, 7 if 1, 6 if 2, reserved otherwise */
- if (bandwidth <= 2)
- bandwidth = 8 - bandwidth;
- else
- bandwidth = 0;
- switch (constellation) {
- case 0:
- constellation_str = "QPSK";
- break;
- case 1:
- constellation_str = "QAM16";
- break;
- case 2:
- constellation_str = "QAM64";
- break;
- default:
- constellation_str = "reserved";
- }
- /* hierarchy is 4 if 3, 2 if 2, 1 if 1, 0 if 0, reserved if > 3 */
- if (hierarchy <= 3) {
- if (hierarchy == 3)
- hierarchy = 4;
- } else {
- hierarchy = 0;
- }
-
- switch (code_rate_hp) {
- case 0:
- code_rate_hp_str = "1/2";
- break;
- case 1:
- code_rate_hp_str = "2/3";
- break;
- case 2:
- code_rate_hp_str = "3/4";
- break;
- case 3:
- code_rate_hp_str = "5/6";
- break;
- case 4:
- code_rate_hp_str = "7/8";
- break;
- default:
- code_rate_hp_str = "reserved";
- }
-
- switch (code_rate_lp) {
- case 0:
- code_rate_lp_str = "1/2";
- break;
- case 1:
- code_rate_lp_str = "2/3";
- break;
- case 2:
- code_rate_lp_str = "3/4";
- break;
- case 3:
- code_rate_lp_str = "5/6";
- break;
- case 4:
- code_rate_lp_str = "7/8";
- break;
- default:
- code_rate_lp_str = "reserved";
- }
- /* guard is 32 if 0, 16 if 1, 8 if 2, 4 if 3 */
- switch (guard_interval) {
- case 0:
- guard_interval = 32;
- break;
- case 1:
- guard_interval = 16;
- break;
- case 2:
- guard_interval = 8;
- break;
- case 3:
- guard_interval = 4;
- break;
- default: /* make it default to 32 */
- guard_interval = 32;
- }
- switch (transmission_mode) {
- case 0:
- transmission_mode_str = "2k";
- break;
- case 1:
- transmission_mode_str = "8k";
- break;
- default:
- transmission_mode_str = "reserved";
- }
- delivery_structure = gst_structure_new_id (QUARK_TERRESTRIAL,
- QUARK_FREQUENCY, G_TYPE_UINT, frequency,
- QUARK_BANDWIDTH, G_TYPE_UINT, bandwidth,
- QUARK_CONSTELLATION, G_TYPE_STRING, constellation_str,
- QUARK_HIERARCHY, G_TYPE_UINT, hierarchy,
- QUARK_CODE_RATE_HP, G_TYPE_STRING, code_rate_hp_str,
- QUARK_CODE_RATE_LP, G_TYPE_STRING, code_rate_lp_str,
- QUARK_GUARD_INTERVAL, G_TYPE_UINT, guard_interval,
- QUARK_TRANSMISSION_MODE, G_TYPE_STRING, transmission_mode_str,
- QUARK_OTHER_FREQUENCY, G_TYPE_BOOLEAN, other_frequency, NULL);
- g_value_init (&tmpval, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&tmpval, delivery_structure);
- gst_structure_id_take_value (transport, QUARK_DELIVERY, &tmpval);
- } else if ((delivery = gst_mpeg_descriptor_find (&mpegdescriptor,
- DESC_DVB_CABLE_DELIVERY_SYSTEM))) {
-
- guint8 *frequency_bcd =
- DESC_DVB_CABLE_DELIVERY_SYSTEM_frequency (delivery);
- /* see en 300 468 section 6.2.13.1 least significant bcd digit
- * is measured in 100Hz units so multiplier needs to be 100 to get
- * into Hz */
- guint32 frequency = 100 *
- ((frequency_bcd[3] & 0x0F) +
- 10 * ((frequency_bcd[3] & 0xF0) >> 4) +
- 100 * (frequency_bcd[2] & 0x0F) +
- 1000 * ((frequency_bcd[2] & 0xF0) >> 4) +
- 10000 * (frequency_bcd[1] & 0x0F) +
- 100000 * ((frequency_bcd[1] & 0xF0) >> 4) +
- 1000000 * (frequency_bcd[0] & 0x0F) +
- 10000000 * ((frequency_bcd[0] & 0xF0) >> 4));
- guint8 modulation =
- DESC_DVB_CABLE_DELIVERY_SYSTEM_modulation (delivery);
- const gchar *modulation_str;
- guint8 *symbol_rate_bcd =
- DESC_DVB_CABLE_DELIVERY_SYSTEM_symbol_rate (delivery);
- guint32 symbol_rate =
- (symbol_rate_bcd[2] & 0x0F) +
- 10 * ((symbol_rate_bcd[2] & 0xF0) >> 4) +
- 100 * (symbol_rate_bcd[1] & 0x0F) +
- 1000 * ((symbol_rate_bcd[1] & 0xF0) >> 4) +
- 10000 * (symbol_rate_bcd[0] & 0x0F) +
- 100000 * ((symbol_rate_bcd[0] & 0xF0) >> 4);
- guint8 fec_inner = DESC_DVB_CABLE_DELIVERY_SYSTEM_fec_inner (delivery);
- const gchar *fec_inner_str;
-
- switch (fec_inner) {
- case 0:
- fec_inner_str = "undefined";
- break;
- case 1:
- fec_inner_str = "1/2";
- break;
- case 2:
- fec_inner_str = "2/3";
- break;
- case 3:
- fec_inner_str = "3/4";
- break;
- case 4:
- fec_inner_str = "5/6";
- break;
- case 5:
- fec_inner_str = "7/8";
- break;
- case 6:
- fec_inner_str = "8/9";
- break;
- case 0xF:
- fec_inner_str = "none";
- break;
- default:
- fec_inner_str = "reserved";
- }
- switch (modulation) {
- case 0x00:
- modulation_str = "undefined";
- break;
- case 0x01:
- modulation_str = "QAM16";
- break;
- case 0x02:
- modulation_str = "QAM32";
- break;
- case 0x03:
- modulation_str = "QAM64";
- break;
- case 0x04:
- modulation_str = "QAM128";
- break;
- case 0x05:
- modulation_str = "QAM256";
- break;
- default:
- modulation_str = "reserved";
- }
- delivery_structure = gst_structure_new_id (QUARK_CABLE,
- QUARK_MODULATION, G_TYPE_STRING, modulation_str,
- QUARK_FREQUENCY, G_TYPE_UINT, frequency,
- QUARK_SYMBOL_RATE, G_TYPE_UINT, symbol_rate,
- QUARK_INNER_FEC, G_TYPE_STRING, fec_inner_str, NULL);
- g_value_init (&tmpval, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&tmpval, delivery_structure);
- gst_structure_id_take_value (transport, QUARK_DELIVERY, &tmpval);
- }
- if ((delivery = gst_mpeg_descriptor_find (&mpegdescriptor,
- DESC_DTG_LOGICAL_CHANNEL))) {
- guint8 *current_pos = delivery + 2;
- GValue channel_numbers = { 0 };
-
- g_value_init (&channel_numbers, GST_TYPE_LIST);
- while (current_pos < delivery + DESC_LENGTH (delivery)) {
- GstStructure *channel;
- GValue channel_value = { 0 };
- guint16 service_id = GST_READ_UINT16_BE (current_pos);
- guint16 logical_channel_number;
-
- current_pos += 2;
- logical_channel_number = GST_READ_UINT16_BE (current_pos) & 0x03ff;
- channel = gst_structure_new_id (QUARK_CHANNELS,
- QUARK_SERVICE_ID, G_TYPE_UINT,
- service_id, QUARK_LOGICAL_CHANNEL_NUMBER, G_TYPE_UINT,
- logical_channel_number, NULL);
- g_value_init (&channel_value, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&channel_value, channel);
- gst_value_list_append_and_take_value (&channel_numbers,
- &channel_value);
- current_pos += 2;
- }
- gst_structure_id_take_value (transport, QUARK_CHANNELS,
- &channel_numbers);
- }
- if ((delivery = gst_mpeg_descriptor_find (&mpegdescriptor,
- DESC_DVB_FREQUENCY_LIST))) {
- guint8 *current_pos = delivery + 2;
- GValue frequencies = { 0 };
- guint8 type;
-
- type = *current_pos & 0x03;
- current_pos++;
-
- if (type) {
- const gchar *fieldname = NULL;
- g_value_init (&frequencies, GST_TYPE_LIST);
-
- while (current_pos < delivery + DESC_LENGTH (delivery) - 3) {
- guint32 freq = 0;
- guint8 *frequency_bcd = current_pos;
- GValue frequency = { 0 };
-
- switch (type) {
- case 0x01:
- /* satellite */
- freq =
- 10 * ((frequency_bcd[3] & 0x0F) +
- 10 * ((frequency_bcd[3] & 0xF0) >> 4) +
- 100 * (frequency_bcd[2] & 0x0F) +
- 1000 * ((frequency_bcd[2] & 0xF0) >> 4) +
- 10000 * (frequency_bcd[1] & 0x0F) +
- 100000 * ((frequency_bcd[1] & 0xF0) >> 4) +
- 1000000 * (frequency_bcd[0] & 0x0F) +
- 10000000 * ((frequency_bcd[0] & 0xF0) >> 4));
- break;
- case 0x02:
- /* cable */
- freq = 100 *
- ((frequency_bcd[3] & 0x0F) +
- 10 * ((frequency_bcd[3] & 0xF0) >> 4) +
- 100 * (frequency_bcd[2] & 0x0F) +
- 1000 * ((frequency_bcd[2] & 0xF0) >> 4) +
- 10000 * (frequency_bcd[1] & 0x0F) +
- 100000 * ((frequency_bcd[1] & 0xF0) >> 4) +
- 1000000 * (frequency_bcd[0] & 0x0F) +
- 10000000 * ((frequency_bcd[0] & 0xF0) >> 4));
- break;
- case 0x03:
- /* terrestrial */
- freq = GST_READ_UINT32_BE (current_pos) * 10;
- break;
- }
- g_value_init (&frequency, G_TYPE_UINT);
- g_value_set_uint (&frequency, freq);
- gst_value_list_append_and_take_value (&frequencies, &frequency);
- current_pos += 4;
- }
-
- switch (type) {
- case 0x01:
- fieldname = "frequency-list-satellite";
- break;
- case 0x02:
- fieldname = "frequency-list-cable";
- break;
- case 0x03:
- fieldname = "frequency-list-terrestrial";
- break;
- }
-
- gst_structure_take_value (transport, fieldname, &frequencies);
- }
- }
-
- descriptors =
- mpegts_packetizer_parse_descriptors (packetizer, &data,
- data + descriptors_loop_length);
- if (!descriptors) {
- gst_structure_free (transport);
- goto error;
- }
-
- set_descriptors_array_on_structure (transport, QUARK_DESCRIPTORS,
- descriptors);
- }
-
- g_value_init (&transport_value, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&transport_value, transport);
- gst_value_list_append_and_take_value (&transports, &transport_value);
-
- transport_stream_loop_length -= data - entry_begin;
- }
-
- if (data != end - 4) {
- GST_WARNING ("PID %d invalid NIT parsed %d length %d",
- section->pid, (gint) (data - section->data), section->section_length);
- goto error;
- }
-
- gst_structure_id_take_value (nit, QUARK_TRANSPORTS, &transports);
-
- GST_DEBUG ("NIT %" GST_PTR_FORMAT, nit);
-
- return nit;
-
-error:
- if (nit)
- gst_structure_free (nit);
-
- if (GST_VALUE_HOLDS_LIST (&transports))
- g_value_unset (&transports);
-
- return NULL;
-}
-
-GstStructure *
-mpegts_packetizer_parse_sdt (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerSection * section)
-{
- GstStructure *sdt = NULL, *service = NULL;
- guint8 *data, *end, *entry_begin;
- guint16 transport_stream_id, original_network_id, service_id;
- guint tmp;
- guint sdt_info_length;
- guint8 running_status;
- gboolean scrambled;
- guint descriptors_loop_length;
- GValue services = { 0 };
- GValueArray *descriptors = NULL;
- GValue service_value = { 0 };
-
- GST_DEBUG ("SDT");
-
- /* fixed header + CRC == 16 */
- if (section->section_length < 14) {
- GST_WARNING ("PID %d invalid SDT size %d",
- section->pid, section->section_length);
- goto error;
- }
-
- data = section->data;
- end = data + section->section_length;
-
- data += 3;
-
- transport_stream_id = GST_READ_UINT16_BE (data);
- data += 2;
-
- tmp = *data++;
- section->version_number = (tmp >> 1) & 0x1F;
- section->current_next_indicator = tmp & 0x01;
-
- /* skip section_number and last_section_number */
- data += 2;
-
- original_network_id = GST_READ_UINT16_BE (data);
- data += 2;
-
- /* skip reserved byte */
- data += 1;
-
- sdt = gst_structure_new_id (QUARK_SDT,
- QUARK_TRANSPORT_STREAM_ID, G_TYPE_UINT, transport_stream_id,
- QUARK_VERSION_NUMBER, G_TYPE_UINT, section->version_number,
- QUARK_CURRENT_NEXT_INDICATOR, G_TYPE_UINT,
- section->current_next_indicator, QUARK_ORIGINAL_NETWORK_ID, G_TYPE_UINT,
- original_network_id, QUARK_ACTUAL_TRANSPORT_STREAM, G_TYPE_BOOLEAN,
- section->table_id == 0x42, NULL);
-
- sdt_info_length = section->section_length - 11;
- g_value_init (&services, GST_TYPE_LIST);
- /* read up to the CRC */
- while (sdt_info_length - 4 > 0) {
- gchar *service_name;
-
- entry_begin = data;
-
- if (sdt_info_length < 9) {
- /* each entry must be at least 5 bytes (+4 bytes for the CRC) */
- GST_WARNING ("PID %d invalid SDT entry size %d",
- section->pid, sdt_info_length);
- goto error;
- }
-
- service_id = GST_READ_UINT16_BE (data);
- data += 2;
-
- /* EIT_schedule = ((*data & 0x02) == 2); */
- /* EIT_present_following = (*data & 0x01) == 1; */
-
- data += 1;
- tmp = GST_READ_UINT16_BE (data);
-
- running_status = (*data >> 5) & 0x07;
- scrambled = (*data >> 4) & 0x01;
- descriptors_loop_length = tmp & 0x0FFF;
- data += 2;
-
- /* TODO send tag event down relevant pad for channel name and provider */
- service_name = g_strdup_printf ("service-%d", service_id);
- service = gst_structure_new_empty (service_name);
- g_free (service_name);
-
- if (descriptors_loop_length) {
- guint8 *service_descriptor;
- GstMPEGDescriptor mpegdescriptor;
-
- if (data + descriptors_loop_length > end - 4) {
- GST_WARNING ("PID %d invalid SDT entry %d descriptors loop length %d",
- section->pid, service_id, descriptors_loop_length);
- gst_structure_free (service);
- goto error;
- }
- gst_mpeg_descriptor_parse (&mpegdescriptor, data,
- descriptors_loop_length);
- service_descriptor =
- gst_mpeg_descriptor_find (&mpegdescriptor, DESC_DVB_SERVICE);
- if (service_descriptor != NULL) {
- gchar *servicename_tmp, *serviceprovider_name_tmp;
- guint8 serviceprovider_name_length =
- DESC_DVB_SERVICE_provider_name_length (service_descriptor);
- gchar *serviceprovider_name =
- (gchar *) DESC_DVB_SERVICE_provider_name_text (service_descriptor);
- guint8 servicename_length =
- DESC_DVB_SERVICE_name_length (service_descriptor);
- gchar *servicename =
- (gchar *) DESC_DVB_SERVICE_name_text (service_descriptor);
- if (servicename_length + serviceprovider_name_length + 2 <=
- DESC_LENGTH (service_descriptor)) {
- const gchar *running_status_tmp;
- switch (running_status) {
- case 0:
- running_status_tmp = "undefined";
- break;
- case 1:
- running_status_tmp = "not running";
- break;
- case 2:
- running_status_tmp = "starts in a few seconds";
- break;
- case 3:
- running_status_tmp = "pausing";
- break;
- case 4:
- running_status_tmp = "running";
- break;
- default:
- running_status_tmp = "reserved";
- }
- servicename_tmp =
- get_encoding_and_convert (packetizer, servicename,
- servicename_length);
- serviceprovider_name_tmp =
- get_encoding_and_convert (packetizer, serviceprovider_name,
- serviceprovider_name_length);
-
- gst_structure_set (service,
- "name", G_TYPE_STRING, servicename_tmp,
- "provider-name", G_TYPE_STRING, serviceprovider_name_tmp,
- "scrambled", G_TYPE_BOOLEAN, scrambled,
- "running-status", G_TYPE_STRING, running_status_tmp, NULL);
-
- g_free (servicename_tmp);
- g_free (serviceprovider_name_tmp);
- }
- }
-
- descriptors = mpegts_packetizer_parse_descriptors (packetizer,
- &data, data + descriptors_loop_length);
- if (!descriptors) {
- gst_structure_free (service);
- goto error;
- }
- set_descriptors_array_on_structure (service, QUARK_DESCRIPTORS,
- descriptors);
- }
-
- g_value_init (&service_value, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&service_value, service);
- gst_value_list_append_and_take_value (&services, &service_value);
-
- sdt_info_length -= data - entry_begin;
- }
-
- if (data != end - 4) {
- GST_WARNING ("PID %d invalid SDT parsed %d length %d",
- section->pid, (gint) (data - section->data), section->section_length);
- goto error;
- }
-
- gst_structure_id_take_value (sdt, QUARK_SERVICES, &services);
-
- return sdt;
-
-error:
- if (sdt)
- gst_structure_free (sdt);
-
- if (GST_VALUE_HOLDS_LIST (&services))
- g_value_unset (&services);
-
- return NULL;
-}
-
-/* FIXME : Can take up to 50% of total mpeg-ts demuxing cpu usage */
-GstStructure *
-mpegts_packetizer_parse_eit (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerSection * section)
-{
- GstStructure *eit = NULL, *event = NULL;
- guint service_id, last_table_id, segment_last_section_number;
- guint transport_stream_id, original_network_id;
- gboolean free_ca_mode;
- guint event_id, running_status;
- guint16 mjd;
- guint year, month, day, hour, minute, second;
- guint duration;
- guint8 *data, *end, *duration_ptr, *utc_ptr;
- guint16 descriptors_loop_length;
- GValue events = { 0 };
- GValue event_value = { 0 };
- GValueArray *descriptors = NULL;
- gchar *event_name;
- guint tmp;
-
- /* fixed header + CRC == 16 */
- if (section->section_length < 18) {
- GST_WARNING ("PID %d invalid EIT size %d",
- section->pid, section->section_length);
- goto error;
- }
-
- data = section->data;
- end = data + section->section_length;
-
- data += 3;
-
- service_id = GST_READ_UINT16_BE (data);
- data += 2;
-
- tmp = *data++;
- section->version_number = (tmp >> 1) & 0x1F;
- section->current_next_indicator = tmp & 0x01;
-
- /* skip section_number and last_section_number */
- data += 2;
-
- transport_stream_id = GST_READ_UINT16_BE (data);
- data += 2;
- original_network_id = GST_READ_UINT16_BE (data);
- data += 2;
- segment_last_section_number = *data;
- data += 1;
- last_table_id = *data;
- data += 1;
-
- eit = gst_structure_new_id (QUARK_EIT,
- QUARK_VERSION_NUMBER, G_TYPE_UINT, section->version_number,
- QUARK_CURRENT_NEXT_INDICATOR, G_TYPE_UINT,
- section->current_next_indicator, QUARK_SERVICE_ID, G_TYPE_UINT,
- service_id, QUARK_ACTUAL_TRANSPORT_STREAM, G_TYPE_BOOLEAN,
- (section->table_id == 0x4E || (section->table_id >= 0x50
- && section->table_id <= 0x5F)), QUARK_PRESENT_FOLLOWING,
- G_TYPE_BOOLEAN, (section->table_id == 0x4E
- || section->table_id == 0x4F), QUARK_TRANSPORT_STREAM_ID, G_TYPE_UINT,
- transport_stream_id, QUARK_ORIGINAL_NETWORK_ID, G_TYPE_UINT,
- original_network_id, QUARK_SEGMENT_LAST_SECTION_NUMBER, G_TYPE_UINT,
- segment_last_section_number, QUARK_LAST_TABLE_ID, G_TYPE_UINT,
- last_table_id, NULL);
-
- g_value_init (&events, GST_TYPE_LIST);
- while (data < end - 4) {
- /* 12 is the minimum entry size + CRC */
- if (end - data < 12 + 4) {
- GST_WARNING ("PID %d invalid EIT entry length %d",
- section->pid, (gint) (end - 4 - data));
- gst_structure_free (eit);
- goto error;
- }
-
- event_id = GST_READ_UINT16_BE (data);
- data += 2;
- /* start_and_duration = GST_READ_UINT64_BE (data); */
- duration_ptr = data + 5;
- utc_ptr = data + 2;
- mjd = GST_READ_UINT16_BE (data);
- if (mjd == G_MAXUINT16) {
- year = 1900;
- month = day = hour = minute = second = 0;
- } else {
- /* See EN 300 468 Annex C */
- year = (guint32) (((mjd - 15078.2) / 365.25));
- month = (guint8) ((mjd - 14956.1 - (guint) (year * 365.25)) / 30.6001);
- day = mjd - 14956 - (guint) (year * 365.25) - (guint) (month * 30.6001);
- if (month == 14 || month == 15) {
- year++;
- month = month - 1 - 12;
- } else {
- month--;
- }
- year += 1900;
- hour = ((utc_ptr[0] & 0xF0) >> 4) * 10 + (utc_ptr[0] & 0x0F);
- minute = ((utc_ptr[1] & 0xF0) >> 4) * 10 + (utc_ptr[1] & 0x0F);
- second = ((utc_ptr[2] & 0xF0) >> 4) * 10 + (utc_ptr[2] & 0x0F);
- }
-
- duration = (((duration_ptr[0] & 0xF0) >> 4) * 10 +
- (duration_ptr[0] & 0x0F)) * 60 * 60 +
- (((duration_ptr[1] & 0xF0) >> 4) * 10 +
- (duration_ptr[1] & 0x0F)) * 60 +
- ((duration_ptr[2] & 0xF0) >> 4) * 10 + (duration_ptr[2] & 0x0F);
-
- data += 8;
- running_status = *data >> 5;
- free_ca_mode = (*data >> 4) & 0x01;
- descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF;
- data += 2;
-
- /* TODO: send tag event down relevant pad saying what is currently playing */
- event_name = g_strdup_printf ("event-%d", event_id);
- event = gst_structure_new_empty (event_name);
- g_free (event_name);
- gst_structure_id_set (event,
- QUARK_EVENT_ID, G_TYPE_UINT, event_id,
- QUARK_YEAR, G_TYPE_UINT, year,
- QUARK_MONTH, G_TYPE_UINT, month,
- QUARK_DAY, G_TYPE_UINT, day,
- QUARK_HOUR, G_TYPE_UINT, hour,
- QUARK_MINUTE, G_TYPE_UINT, minute,
- QUARK_SECOND, G_TYPE_UINT, second,
- QUARK_DURATION, G_TYPE_UINT, duration,
- QUARK_RUNNING_STATUS, G_TYPE_UINT, running_status,
- QUARK_FREE_CA_MODE, G_TYPE_BOOLEAN, free_ca_mode, NULL);
-
- if (descriptors_loop_length) {
- guint8 *event_descriptor;
- GArray *component_descriptors;
- GArray *extended_event_descriptors;
- GstMPEGDescriptor mpegdescriptor;
-
- if (data + descriptors_loop_length > end - 4) {
- GST_WARNING ("PID %d invalid EIT descriptors loop length %d",
- section->pid, descriptors_loop_length);
- gst_structure_free (event);
- goto error;
- }
- gst_mpeg_descriptor_parse (&mpegdescriptor, data,
- descriptors_loop_length);
- event_descriptor =
- gst_mpeg_descriptor_find (&mpegdescriptor, DESC_DVB_SHORT_EVENT);
- if (event_descriptor != NULL) {
- gchar *eventname_tmp, *eventdescription_tmp;
- guint8 eventname_length =
- DESC_DVB_SHORT_EVENT_name_length (event_descriptor);
- gchar *eventname =
- (gchar *) DESC_DVB_SHORT_EVENT_name_text (event_descriptor);
- guint8 eventdescription_length =
- DESC_DVB_SHORT_EVENT_description_length (event_descriptor);
- gchar *eventdescription =
- (gchar *) DESC_DVB_SHORT_EVENT_description_text (event_descriptor);
- if (eventname_length + eventdescription_length + 2 <=
- DESC_LENGTH (event_descriptor)) {
-
- eventname_tmp =
- get_encoding_and_convert (packetizer, eventname,
- eventname_length);
- eventdescription_tmp =
- get_encoding_and_convert (packetizer, eventdescription,
- eventdescription_length);
-
- gst_structure_id_set (event, QUARK_NAME, G_TYPE_STRING, eventname_tmp,
- QUARK_DESCRIPTION, G_TYPE_STRING, eventdescription_tmp, NULL);
- g_free (eventname_tmp);
- g_free (eventdescription_tmp);
- }
- }
-
- extended_event_descriptors =
- gst_mpeg_descriptor_find_all (&mpegdescriptor,
- DESC_DVB_EXTENDED_EVENT);
- if (extended_event_descriptors) {
- int i;
- guint8 *extended_descriptor;
- GValue extended_items = { 0 };
- GValue extended_item_value = { 0 };
- GstStructure *extended_item;
- gchar *extended_text = NULL;
- g_value_init (&extended_items, GST_TYPE_LIST);
- for (i = 0; i < extended_event_descriptors->len; i++) {
- extended_descriptor = g_array_index (extended_event_descriptors,
- guint8 *, i);
- if (DESC_DVB_EXTENDED_EVENT_descriptor_number (extended_descriptor) ==
- i) {
- guint8 *items_aux =
- DESC_DVB_EXTENDED_EVENT_items (extended_descriptor);
- guint8 *items_limit =
- items_aux +
- DESC_DVB_EXTENDED_EVENT_items_length (extended_descriptor);
- while (items_aux < items_limit) {
- guint8 length_aux;
- gchar *description, *text;
-
- /* Item Description text */
- length_aux = *items_aux;
- ++items_aux;
- description =
- get_encoding_and_convert (packetizer, (gchar *) items_aux,
- length_aux);
- items_aux += length_aux;
-
- /* Item text */
- length_aux = *items_aux;
- ++items_aux;
- text =
- get_encoding_and_convert (packetizer, (gchar *) items_aux,
- length_aux);
- items_aux += length_aux;
-
- extended_item = gst_structure_new_id (QUARK_EXTENDED_ITEM,
- QUARK_DESCRIPTION, G_TYPE_STRING, description,
- QUARK_TEXT, G_TYPE_STRING, text, NULL);
- g_free (description);
- g_free (text);
-
- g_value_init (&extended_item_value, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&extended_item_value, extended_item);
- gst_value_list_append_and_take_value (&extended_items,
- &extended_item_value);
- }
-
- if (extended_text) {
- gchar *tmp;
- gchar *old_extended_text = extended_text;
- tmp = get_encoding_and_convert (packetizer, (gchar *)
- DESC_DVB_EXTENDED_EVENT_text (extended_descriptor),
- DESC_DVB_EXTENDED_EVENT_text_length (extended_descriptor));
- extended_text = g_strdup_printf ("%s%s", extended_text, tmp);
- g_free (old_extended_text);
- g_free (tmp);
- } else {
- extended_text = get_encoding_and_convert (packetizer, (gchar *)
- DESC_DVB_EXTENDED_EVENT_text (extended_descriptor),
- DESC_DVB_EXTENDED_EVENT_text_length (extended_descriptor));
- }
- }
- }
- if (extended_text) {
- gst_structure_id_set (event, QUARK_EXTENDED_TEXT, G_TYPE_STRING,
- extended_text, NULL);
- g_free (extended_text);
- }
- gst_structure_id_take_value (event, QUARK_EXTENDED_ITEMS,
- &extended_items);
- g_array_free (extended_event_descriptors, TRUE);
- }
-
- component_descriptors = gst_mpeg_descriptor_find_all (&mpegdescriptor,
- DESC_DVB_COMPONENT);
- if (component_descriptors) {
- int i;
- guint8 *comp_descriptor;
- GValue components = { 0 };
- g_value_init (&components, GST_TYPE_LIST);
- /* FIXME: do the component descriptor parsing less verbosely
- * and better...a task for 0.10.6 */
- for (i = 0; i < component_descriptors->len; i++) {
- GstStructure *component = NULL;
- GValue component_value = { 0 };
- gint widescreen = 0; /* 0 for 4:3, 1 for 16:9, 2 for > 16:9 */
- gint freq = 25; /* 25 or 30 measured in Hertz */
- /* gboolean highdef = FALSE; */
- gboolean panvectors = FALSE;
- const gchar *comptype = "";
-
- comp_descriptor = g_array_index (component_descriptors, guint8 *, i);
- switch (DESC_DVB_COMPONENT_stream_content (comp_descriptor)) {
- case 0x01:
- /* video */
- switch (DESC_DVB_COMPONENT_type (comp_descriptor)) {
- case 0x01:
- widescreen = 0;
- freq = 25;
- break;
- case 0x02:
- widescreen = 1;
- panvectors = TRUE;
- freq = 25;
- break;
- case 0x03:
- widescreen = 1;
- panvectors = FALSE;
- freq = 25;
- break;
- case 0x04:
- widescreen = 2;
- freq = 25;
- break;
- case 0x05:
- widescreen = 0;
- freq = 30;
- break;
- case 0x06:
- widescreen = 1;
- panvectors = TRUE;
- freq = 30;
- break;
- case 0x07:
- widescreen = 1;
- panvectors = FALSE;
- freq = 30;
- break;
- case 0x08:
- widescreen = 2;
- freq = 30;
- break;
- case 0x09:
- widescreen = 0;
- /* highdef = TRUE; */
- freq = 25;
- break;
- case 0x0A:
- widescreen = 1;
- /* highdef = TRUE; */
- panvectors = TRUE;
- freq = 25;
- break;
- case 0x0B:
- widescreen = 1;
- /* highdef = TRUE; */
- panvectors = FALSE;
- freq = 25;
- break;
- case 0x0C:
- widescreen = 2;
- /* highdef = TRUE; */
- freq = 25;
- break;
- case 0x0D:
- widescreen = 0;
- /* highdef = TRUE; */
- freq = 30;
- break;
- case 0x0E:
- widescreen = 1;
- /* highdef = TRUE; */
- panvectors = TRUE;
- freq = 30;
- break;
- case 0x0F:
- widescreen = 1;
- /* highdef = TRUE; */
- panvectors = FALSE;
- freq = 30;
- break;
- case 0x10:
- widescreen = 2;
- /* highdef = TRUE; */
- freq = 30;
- break;
- }
- component = gst_structure_new ("video", "high-definition",
- G_TYPE_BOOLEAN, TRUE, "frequency", G_TYPE_INT, freq,
- "tag", G_TYPE_INT, DESC_DVB_COMPONENT_tag (comp_descriptor),
- NULL);
- if (widescreen == 0) {
- gst_structure_set (component, "aspect-ratio",
- G_TYPE_STRING, "4:3", NULL);
- } else if (widescreen == 2) {
- gst_structure_set (component, "aspect-ratio", G_TYPE_STRING,
- "> 16:9", NULL);
- } else {
- gst_structure_set (component, "aspect-ratio", G_TYPE_STRING,
- "16:9", "pan-vectors", G_TYPE_BOOLEAN, panvectors, NULL);
- }
- break;
- case 0x02: /* audio */
- comptype = "undefined";
- switch (DESC_DVB_COMPONENT_type (comp_descriptor)) {
- case 0x01:
- comptype = "single channel mono";
- break;
- case 0x02:
- comptype = "dual channel mono";
- break;
- case 0x03:
- comptype = "stereo";
- break;
- case 0x04:
- comptype = "multi-channel multi-lingual";
- break;
- case 0x05:
- comptype = "surround";
- break;
- case 0x40:
- comptype = "audio description for the visually impaired";
- break;
- case 0x41:
- comptype = "audio for the hard of hearing";
- break;
- }
- component = gst_structure_new ("audio", "type", G_TYPE_STRING,
- comptype, "tag", G_TYPE_INT,
- DESC_DVB_COMPONENT_tag (comp_descriptor), NULL);
- break;
- case 0x03: /* subtitles/teletext/vbi */
- comptype = "reserved";
- switch (DESC_DVB_COMPONENT_type (comp_descriptor)) {
- case 0x01:
- comptype = "EBU Teletext subtitles";
- break;
- case 0x02:
- comptype = "associated EBU Teletext";
- break;
- case 0x03:
- comptype = "VBI data";
- break;
- case 0x10:
- comptype = "Normal DVB subtitles";
- break;
- case 0x11:
- comptype = "Normal DVB subtitles for 4:3";
- break;
- case 0x12:
- comptype = "Normal DVB subtitles for 16:9";
- break;
- case 0x13:
- comptype = "Normal DVB subtitles for 2.21:1";
- break;
- case 0x20:
- comptype = "Hard of hearing DVB subtitles";
- break;
- case 0x21:
- comptype = "Hard of hearing DVB subtitles for 4:3";
- break;
- case 0x22:
- comptype = "Hard of hearing DVB subtitles for 16:9";
- break;
- case 0x23:
- comptype = "Hard of hearing DVB subtitles for 2.21:1";
- break;
- }
- component = gst_structure_new ("teletext", "type", G_TYPE_STRING,
- comptype, "tag", G_TYPE_INT,
- DESC_DVB_COMPONENT_tag (comp_descriptor), NULL);
- break;
- }
- if (component) {
- g_value_init (&component_value, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&component_value, component);
- gst_value_list_append_and_take_value (&components,
- &component_value);
- component = NULL;
- }
- }
- gst_structure_take_value (event, "components", &components);
- g_array_free (component_descriptors, TRUE);
- }
-
- descriptors = mpegts_packetizer_parse_descriptors (packetizer,
- &data, data + descriptors_loop_length);
- if (!descriptors) {
- gst_structure_free (event);
- goto error;
- }
- set_descriptors_array_on_structure (event, QUARK_DESCRIPTORS,
- descriptors);
- }
-
- g_value_init (&event_value, GST_TYPE_STRUCTURE);
- g_value_take_boxed (&event_value, event);
- gst_value_list_append_and_take_value (&events, &event_value);
- }
-
- if (data != end - 4) {
- GST_WARNING ("PID %d invalid EIT parsed %d length %d",
- section->pid, (gint) (data - section->data), section->section_length);
- goto error;
- }
-
- gst_structure_id_take_value (eit, QUARK_EVENTS, &events);
-
- GST_DEBUG ("EIT %" GST_PTR_FORMAT, eit);
-
- return eit;
-
-error:
- if (eit)
- gst_structure_free (eit);
-
- if (GST_VALUE_HOLDS_LIST (&events))
- g_value_unset (&events);
-
- return NULL;
-}
-
-static GstStructure *
-parse_tdt_tot_common (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerSection * section, GQuark name)
-{
- GstStructure *res;
- guint16 mjd;
- guint year, month, day, hour, minute, second;
- guint8 *data, *utc_ptr;
-
- /* length at least 8 */
- if (section->section_length < 8) {
- GST_WARNING ("PID %d invalid TDT/TOT size %d",
- section->pid, section->section_length);
- return NULL;
- }
-
- data = section->data;
- data += 3;
-
- mjd = GST_READ_UINT16_BE (data);
- data += 2;
- utc_ptr = data;
- if (mjd == G_MAXUINT16) {
- year = 1900;
- month = day = hour = minute = second = 0;
- } else {
- /* See EN 300 468 Annex C */
- year = (guint32) (((mjd - 15078.2) / 365.25));
- month = (guint8) ((mjd - 14956.1 - (guint) (year * 365.25)) / 30.6001);
- day = mjd - 14956 - (guint) (year * 365.25) - (guint) (month * 30.6001);
- if (month == 14 || month == 15) {
- year++;
- month = month - 1 - 12;
- } else {
- month--;
- }
- year += 1900;
- hour = ((utc_ptr[0] & 0xF0) >> 4) * 10 + (utc_ptr[0] & 0x0F);
- minute = ((utc_ptr[1] & 0xF0) >> 4) * 10 + (utc_ptr[1] & 0x0F);
- second = ((utc_ptr[2] & 0xF0) >> 4) * 10 + (utc_ptr[2] & 0x0F);
- }
- res = gst_structure_new_id (name,
- QUARK_YEAR, G_TYPE_UINT, year,
- QUARK_MONTH, G_TYPE_UINT, month,
- QUARK_DAY, G_TYPE_UINT, day,
- QUARK_HOUR, G_TYPE_UINT, hour,
- QUARK_MINUTE, G_TYPE_UINT, minute, QUARK_SECOND, G_TYPE_UINT, second,
- NULL);
-
- return res;
-}
-
-GstStructure *
-mpegts_packetizer_parse_tdt (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerSection * section)
-{
- GstStructure *tdt = NULL;
- GST_DEBUG ("TDT");
-
- tdt = parse_tdt_tot_common (packetizer, section, QUARK_TDT);
-
- return tdt;
-}
-
-GstStructure *
-mpegts_packetizer_parse_tot (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerSection * section)
-{
- guint8 *data;
- GstStructure *tot = NULL;
- GValueArray *descriptors;
- guint16 desc_len;
-
- GST_DEBUG ("TOT");
-
- tot = parse_tdt_tot_common (packetizer, section, QUARK_TOT);
- data = section->data + 8;
-
- desc_len = ((*data++) & 0xf) << 8;
- desc_len |= *data++;
- descriptors =
- mpegts_packetizer_parse_descriptors (packetizer, &data, data + desc_len);
- if (!descriptors) {
- gst_structure_free (tot);
- return NULL;
- }
- gst_structure_id_set (tot, QUARK_DESCRIPTORS, G_TYPE_VALUE_ARRAY, descriptors,
- NULL);
- g_value_array_free (descriptors);
-
- return tot;
-}
-
-void
-mpegts_packetizer_clear (MpegTSPacketizer2 * packetizer)
-{
- if (packetizer->know_packet_size) {
- packetizer->know_packet_size = FALSE;
- packetizer->packet_size = 0;
- if (packetizer->caps != NULL) {
- gst_caps_unref (packetizer->caps);
- packetizer->caps = NULL;
- }
- }
- if (packetizer->streams) {
- int i;
- for (i = 0; i < 8192; i++) {
- if (packetizer->streams[i]) {
- mpegts_packetizer_stream_free (packetizer->streams[i]);
- }
- }
- memset (packetizer->streams, 0, 8192 * sizeof (MpegTSPacketizerStream *));
- }
-
- gst_adapter_clear (packetizer->adapter);
- packetizer->offset = 0;
- packetizer->empty = TRUE;
- packetizer->priv->available = 0;
- packetizer->priv->mapped = NULL;
- packetizer->priv->mapped_size = 0;
- packetizer->priv->offset = 0;
- packetizer->priv->last_in_time = GST_CLOCK_TIME_NONE;
-}
-
-void
-mpegts_packetizer_flush (MpegTSPacketizer2 * packetizer, gboolean hard)
-{
- GST_DEBUG ("Flushing");
-
- if (packetizer->streams) {
- int i;
- for (i = 0; i < 8192; i++) {
- if (packetizer->streams[i]) {
- mpegts_packetizer_clear_section (packetizer->streams[i]);
- }
- }
- }
- gst_adapter_clear (packetizer->adapter);
-
- packetizer->offset = 0;
- packetizer->empty = TRUE;
- packetizer->priv->available = 0;
- packetizer->priv->mapped = NULL;
- packetizer->priv->offset = 0;
- packetizer->priv->mapped_size = 0;
- packetizer->priv->last_in_time = GST_CLOCK_TIME_NONE;
- if (hard) {
- /* For pull mode seeks in tsdemux the observation must be preserved */
- flush_observations (packetizer);
- }
-}
-
-void
-mpegts_packetizer_remove_stream (MpegTSPacketizer2 * packetizer, gint16 pid)
-{
- MpegTSPacketizerStream *stream = packetizer->streams[pid];
- if (stream) {
- GST_INFO ("Removing stream for PID %d", pid);
- mpegts_packetizer_stream_free (stream);
- packetizer->streams[pid] = NULL;
- }
-}
-
-MpegTSPacketizer2 *
-mpegts_packetizer_new (void)
-{
- MpegTSPacketizer2 *packetizer;
-
- packetizer =
- GST_MPEGTS_PACKETIZER (g_object_new (GST_TYPE_MPEGTS_PACKETIZER, NULL));
-
- return packetizer;
-}
-
-void
-mpegts_packetizer_push (MpegTSPacketizer2 * packetizer, GstBuffer * buffer)
-{
- if (G_UNLIKELY (packetizer->empty)) {
- packetizer->empty = FALSE;
- packetizer->offset = GST_BUFFER_OFFSET (buffer);
- }
-
- GST_DEBUG ("Pushing %" G_GSIZE_FORMAT " byte from offset %" G_GUINT64_FORMAT,
- gst_buffer_get_size (buffer), GST_BUFFER_OFFSET (buffer));
- gst_adapter_push (packetizer->adapter, buffer);
- packetizer->priv->available += gst_buffer_get_size (buffer);
- /* If buffer timestamp is valid, store it */
- if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)))
- packetizer->priv->last_in_time = GST_BUFFER_TIMESTAMP (buffer);
-}
-
-static gboolean
-mpegts_try_discover_packet_size (MpegTSPacketizer2 * packetizer)
-{
- guint8 *dest;
- int i, pos = -1, j;
- static const guint psizes[] = {
- MPEGTS_NORMAL_PACKETSIZE,
- MPEGTS_M2TS_PACKETSIZE,
- MPEGTS_DVB_ASI_PACKETSIZE,
- MPEGTS_ATSC_PACKETSIZE
- };
-
-
- dest = g_malloc (MPEGTS_MAX_PACKETSIZE * 4);
- /* wait for 3 sync bytes */
- while (packetizer->priv->available >= MPEGTS_MAX_PACKETSIZE * 4) {
-
- /* check for sync bytes */
- gst_adapter_copy (packetizer->adapter, dest, 0, MPEGTS_MAX_PACKETSIZE * 4);
- /* find first sync byte */
- pos = -1;
- for (i = 0; i < MPEGTS_MAX_PACKETSIZE; i++) {
- if (dest[i] == PACKET_SYNC_BYTE) {
- for (j = 0; j < 4; j++) {
- guint packetsize = psizes[j];
- /* check each of the packet size possibilities in turn */
- if (dest[i] == PACKET_SYNC_BYTE
- && dest[i + packetsize] == PACKET_SYNC_BYTE
- && dest[i + packetsize * 2] == PACKET_SYNC_BYTE
- && dest[i + packetsize * 3] == PACKET_SYNC_BYTE) {
- packetizer->know_packet_size = TRUE;
- packetizer->packet_size = packetsize;
- packetizer->caps = gst_caps_new_simple ("video/mpegts",
- "systemstream", G_TYPE_BOOLEAN, TRUE,
- "packetsize", G_TYPE_INT, packetsize, NULL);
- if (packetsize == MPEGTS_M2TS_PACKETSIZE)
- pos = i - 4;
- else
- pos = i;
- break;
- }
- }
- break;
- }
- }
-
- if (packetizer->know_packet_size)
- break;
-
- /* Skip MPEGTS_MAX_PACKETSIZE */
- gst_adapter_flush (packetizer->adapter, MPEGTS_MAX_PACKETSIZE);
- packetizer->priv->available -= MPEGTS_MAX_PACKETSIZE;
- packetizer->offset += MPEGTS_MAX_PACKETSIZE;
- }
-
- g_free (dest);
-
- if (packetizer->know_packet_size) {
- GST_DEBUG ("have packetsize detected: %d of %u bytes",
- packetizer->know_packet_size, packetizer->packet_size);
- /* flush to sync byte */
- if (pos > 0) {
- GST_DEBUG ("Flushing out %d bytes", pos);
- gst_adapter_flush (packetizer->adapter, pos);
- packetizer->offset += pos;
- packetizer->priv->available -= MPEGTS_MAX_PACKETSIZE;
- }
- } else {
- /* drop invalid data and move to the next possible packets */
- GST_DEBUG ("Could not determine packet size");
- }
-
- return packetizer->know_packet_size;
-}
-
-gboolean
-mpegts_packetizer_has_packets (MpegTSPacketizer2 * packetizer)
-{
- if (G_UNLIKELY (packetizer->know_packet_size == FALSE)) {
- if (!mpegts_try_discover_packet_size (packetizer))
- return FALSE;
- }
- return packetizer->priv->available >= packetizer->packet_size;
-}
-
-MpegTSPacketizerPacketReturn
-mpegts_packetizer_next_packet (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerPacket * packet)
-{
- MpegTSPacketizerPrivate *priv = packetizer->priv;
- guint skip;
- guint sync_offset;
-
- if (G_UNLIKELY (!packetizer->know_packet_size)) {
- if (!mpegts_try_discover_packet_size (packetizer))
- return PACKET_NEED_MORE;
- }
-
- while (priv->available >= packetizer->packet_size) {
- if (priv->mapped == NULL) {
- priv->mapped_size = priv->available;
- priv->mapped =
- (guint8 *) gst_adapter_map (packetizer->adapter, priv->mapped_size);
- priv->offset = 0;
- }
-
- /* M2TS packets don't start with the sync byte, all other variants do */
- sync_offset = priv->offset;
- if (packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE)
- sync_offset += 4;
+ /* M2TS packets don't start with the sync byte, all other variants do */
+ sync_offset = priv->offset;
+ if (packetizer->packet_size == MPEGTS_M2TS_PACKETSIZE)
+ sync_offset += 4;
/* Check sync byte */
if (G_LIKELY (priv->mapped[sync_offset] == 0x47)) {
}
}
-gboolean
+/*
+ * Ideally it should just return a section if:
+ * * The section is complete
+ * * The section is valid (sanity checks for length for example)
+ * * The section applies now (current_next_indicator)
+ * * The section is an update or was never seen
+ *
+ * The section should be a new GstMpegTSSection:
+ * * properly initialized
+ * * With pid, table_id AND section_type set (move logic from mpegtsbase)
+ * * With data copied into it (yes, minor overhead)
+ *
+ * In all other cases it should just return NULL
+ * */
+GstMpegTSSection *
mpegts_packetizer_push_section (MpegTSPacketizer2 * packetizer,
- MpegTSPacketizerPacket * packet, MpegTSPacketizerSection * section)
+ MpegTSPacketizerPacket * packet)
{
- gboolean res = FALSE;
+ GstMpegTSSection *res = NULL;
MpegTSPacketizerStream *stream;
+ gboolean long_packet;
guint8 pointer, table_id;
#ifndef GST_DISABLE_GST_DEBUG
- guint16 subtable_extension;
+ guint16 subtable_extension = 0;
#endif
guint section_length;
guint8 *data, *data_start;
+ guint8 packet_cc;
data = packet->data;
- section->pid = packet->pid;
+ packet_cc = FLAGS_CONTINUITY_COUNTER (packet->scram_afc_cc);
+
+ GST_MEMDUMP ("section data", packet->data, packet->data_end - packet->data);
+ /* FIXME: If pointer is different from zero, this means the data should be accumulated
+ * to the previous section ! */
if (packet->payload_unit_start_indicator) {
pointer = *data++;
+ /* Sanity check for enough data */
if (data + pointer > packet->data_end) {
- GST_WARNING ("PID 0x%04x PSI section pointer points past the end "
+ GST_DEBUG ("PID 0x%04x PSI section pointer points past the end "
"of the buffer", packet->pid);
goto out;
}
+ if (G_UNLIKELY (pointer != 0)) {
+ GST_FIXME ("PID 0x%04x PSI pointer %d != 0. Handle previous data",
+ packet->pid, pointer);
+ GST_MEMDUMP ("previous data", data, pointer);
+ }
data += pointer;
}
- GST_MEMDUMP ("section data", packet->data, packet->data_end - packet->data);
-
- /* TDT and TOT sections (see ETSI EN 300 468 5.2.5)
- * these sections do not extend to several packets so we don't need to use the
- * sections filter. */
- if (packet->pid == 0x14) {
- section->offset = packet->offset;
- table_id = data[0];
- section->section_length = (GST_READ_UINT24_BE (data) & 0x000FFF) + 3;
+ /*
+ * section_syntax_indicator means that the header is of the following format:
+ * * table_id (8bit)
+ * * section_syntax_indicator (1bit) == 0
+ * * reserved/private fields (3bit)
+ * * section_length (12bit)
+ * * data (of size section_length)
+ * * NO CRC !
+ */
+ long_packet = data[1] & 0x80;
+
+ /* Fast path for short packets */
+ if (!long_packet && packet->payload_unit_start_indicator) {
+ /* We can create the section now (function will check for size) */
+ GST_DEBUG ("Short packet");
+ section_length = (GST_READ_UINT16_BE (data + 1) & 0xfff) + 3;
+ /* Only do fast-path if we have enough byte */
+ if (section_length < packet->data_end - data) {
+ res =
+ gst_mpegts_section_new (packet->pid, g_memdup (data,
+ section_length), section_length);
+ if (data[section_length] != 0xff) {
+ GST_FIXME
+ ("Potentially more data after short section (report in bug #677443)");
+ GST_MEMDUMP ("Remainder", data + section_length,
+ packet->data_end - data - section_length);
- if (data + section->section_length > packet->data_end) {
- GST_WARNING ("PID 0x%04x PSI section length extends past the end "
- "of the buffer", packet->pid);
+ }
+ if (res)
+ res->offset = packet->offset;
+ /* And exit */
goto out;
}
- section->data = data;
- section->table_id = table_id;
- section->complete = TRUE;
- res = TRUE;
- GST_DEBUG ("TDT section pid:0x%04x table_id:0x%02x section_length: %d",
- packet->pid, table_id, section->section_length);
- goto out;
+ /* We don't have enough bytes to do short section shortcut */
}
data_start = data;
+ /* Get our filter */
stream = packetizer->streams[packet->pid];
- if (stream == NULL) {
- stream = mpegts_packetizer_stream_new ();
+ if (G_UNLIKELY (stream == NULL)) {
+ if (!packet->payload_unit_start_indicator) {
+ /* Early exit (we need to start with a section start) */
+ GST_DEBUG ("PID 0x%04x waiting for section start", packet->pid);
+ goto out;
+ }
+ stream = mpegts_packetizer_stream_new (packet->pid);
packetizer->streams[packet->pid] = stream;
}
+ /* If not a new section, and we were expecting a new section or
+ * there is a discontinuity, bail out. */
+ if (!packet->payload_unit_start_indicator) {
+ if (stream->continuity_counter == CONTINUITY_UNSET) {
+ GST_DEBUG ("PID 0x%04x waiting for section start", packet->pid);
+ goto out;
+ }
+ if ((stream->continuity_counter + 1) % 16 != packet_cc) {
+ GST_WARNING ("PID 0x%04x section discontinuity (%d vs %d)", packet->pid,
+ stream->continuity_counter, packet_cc);
+ mpegts_packetizer_clear_section (stream);
+ goto out;
+ }
+ }
+
if (packet->payload_unit_start_indicator) {
+ guint8 version_number, section_number, last_section_number;
+
+ /* Beginning of a new section, do as much pre-parsing as possible */
+ /* table_id : 8 bit */
table_id = *data++;
-#ifndef GST_DISABLE_GST_DEBUG
- /* subtable_extension should be read from 4th and 5th bytes only if
- * section_syntax_indicator is 1 */
- if ((data[0] & 0x80) == 0)
- subtable_extension = 0;
- else
- subtable_extension = GST_READ_UINT16_BE (data + 2);
- GST_DEBUG ("pid: 0x%04x table_id 0x%02x sub_table_extension %d",
- packet->pid, table_id, subtable_extension);
-#endif
+ /* section_syntax_indicator : 1 bit
+ * other_fields (reserved) : 3 bit
+ * section_length : 12 bit */
section_length = (GST_READ_UINT16_BE (data) & 0x0FFF) + 3;
+ data += 2;
+
+ /* subtable_extension (always present, we are in a long section) */
+ /* subtable extension : 16 bit */
+ subtable_extension = GST_READ_UINT16_BE (data);
+ data += 2;
- if (stream->continuity_counter != CONTINUITY_UNSET) {
+ /* reserved : 2 bit
+ * version_number : 5 bit
+ * current_next_indicator : 1 bit */
+ /* Bail out now if current_next_indicator == 0 */
+ if (G_UNLIKELY (!data & 0x01)) {
GST_DEBUG
- ("PID 0x%04x table_id 0x%02x sub_table_extension %d payload_unit_start_indicator set but section "
- "not complete (last_continuity: %d continuity: %d sec len %d",
- packet->pid, table_id, subtable_extension, stream->continuity_counter,
- packet->continuity_counter, section_length);
- mpegts_packetizer_clear_section (stream);
- } else {
+ ("PID 0x%04x table_id 0x%02x section does not apply (current_next_indicator == 0)",
+ packet->pid, table_id);
+ goto out;
+ }
+
+ version_number = *data++ >> 1 & 0x1f;
+ /* section_number : 8 bit */
+ section_number = *data++;
+ /* last_section_number : 8 bit */
+ last_section_number = *data++;
+
+ GST_DEBUG
+ ("PID 0x%04x table_id:0x%02x subtable_extension:0x%04x version_number:%d section_number:%d(last:%d)",
+ packet->pid, table_id, subtable_extension, version_number,
+ section_number, last_section_number);
+
+ /* Check as early as possible whether we already saw this section
+ * i.e. that we saw a subtable with:
+ * * same subtable_extension (might be zero)
+ * * same version_number
+ * * same last_section_number
+ * * same section_number was seen
+ */
+ if (seen_section_before (stream, table_id, subtable_extension,
+ version_number, section_number, last_section_number)) {
GST_DEBUG
- ("pusi set and new stream section is %d long and data we have is: %d",
- section_length, (gint) (packet->data_end - packet->data));
+ ("PID 0x%04x Already processed table_id:0x%02x subtable_extension:0x%04x, version_number:%d, section_number:%d",
+ packet->pid, table_id, subtable_extension, version_number,
+ section_number);
+ goto out;
+ }
+ if (G_UNLIKELY (section_number > last_section_number)) {
+ GST_WARNING
+ ("PID 0x%04x corrupted packet (section_number:%d > last_section_number:%d)",
+ packet->pid, section_number, last_section_number);
+ goto out;
}
- stream->continuity_counter = packet->continuity_counter;
+
+ stream->continuity_counter = packet_cc;
+
+ /* Copy over already parsed values */
+ stream->table_id = table_id;
stream->section_length = section_length;
+ stream->version_number = version_number;
+ stream->subtable_extension = subtable_extension;
+ stream->section_number = section_number;
+ stream->last_section_number = last_section_number;
/* Create enough room to store chunks of sections, including FF padding */
- if (stream->section_allocated == 0) {
- stream->section_data = g_malloc (section_length + 188);
- stream->section_allocated = section_length + 188;
- } else if (G_UNLIKELY (stream->section_allocated < section_length + 188)) {
- stream->section_data =
- g_realloc (stream->section_data, section_length + 188);
- stream->section_allocated = section_length + 188;
- }
+ stream->section_allocated = stream->section_length + 188;
+ stream->section_data = g_malloc (stream->section_allocated);
memcpy (stream->section_data, data_start, packet->data_end - data_start);
stream->section_offset = packet->data_end - data_start;
- stream->section_table_id = table_id;
stream->offset = packet->offset;
-
- res = TRUE;
- } else if (stream->continuity_counter != CONTINUITY_UNSET &&
- (packet->continuity_counter == stream->continuity_counter + 1 ||
- (stream->continuity_counter == MAX_CONTINUITY &&
- packet->continuity_counter == 0))) {
- stream->continuity_counter = packet->continuity_counter;
+ } else {
+ /* valid continuation of an existing section */
+ stream->continuity_counter = packet_cc;
memcpy (stream->section_data + stream->section_offset, data_start,
packet->data_end - data_start);
stream->section_offset += packet->data_end - data_start;
GST_DEBUG ("Appending data (need %d, have %d)", stream->section_length,
stream->section_offset);
-
- res = TRUE;
- } else {
- if (stream->continuity_counter == CONTINUITY_UNSET)
- GST_DEBUG ("PID 0x%04x waiting for pusi", packet->pid);
- else
- GST_DEBUG ("PID 0x%04x section discontinuity "
- "(last_continuity: %d continuity: %d", packet->pid,
- stream->continuity_counter, packet->continuity_counter);
- mpegts_packetizer_clear_section (stream);
}
- if (res) {
- /* we pushed some data in the section adapter, see if the section is
- * complete now */
-
- /* >= as sections can be padded and padding is not included in
- * section_length */
- if (stream->section_offset >= stream->section_length) {
- res = mpegts_packetizer_parse_section_header (packetizer,
- stream, section);
-
- /* flush stuffing bytes */
- mpegts_packetizer_clear_section (stream);
- } else {
- GST_DEBUG ("section not complete");
- /* section not complete yet */
- section->complete = FALSE;
+ /* we pushed some data in the section adapter, see if the section is
+ * complete now */
+ /* >= as sections can be padded and padding is not included in
+ * section_length */
+ if (stream->section_offset >= stream->section_length) {
+ GST_DEBUG ("PID 0x%04x Section complete (Got %d, need %d)",
+ stream->pid, stream->section_offset, stream->section_length);
+ /* Remainder of section data should be padding (0xff) */
+ /* Adding a warning so people can report it in the bug reported regarding
+ * multiple sections after another (still not seen any samples in the wild) */
+ if (stream->section_offset > stream->section_length &&
+ stream->section_data[stream->section_length] != 0xff) {
+ GST_FIXME ("Potentially more data after section (report in bug #677443)");
+ GST_MEMDUMP ("Remainder", stream->section_data + stream->section_length,
+ stream->section_offset - stream->section_length);
}
+ res = mpegts_packetizer_parse_section_header (packetizer, stream);
+
+ /* flush stuffing bytes */
+ mpegts_packetizer_clear_section (stream);
} else {
- GST_WARNING ("section not complete");
- section->complete = FALSE;
+ GST_DEBUG ("PID 0x%04x, section not complete (Got %d, need %d)",
+ stream->pid, stream->section_offset, stream->section_length);
}
out:
packet->data = data;
- GST_DEBUG ("result: %d complete: %d", res, section->complete);
+ GST_DEBUG ("result: %p", res);
return res;
}
{
GST_DEBUG_CATEGORY_INIT (mpegts_packetizer_debug, "mpegtspacketizer", 0,
"MPEG transport stream parser");
-
- QUARK_PAT = g_quark_from_string ("pat");
- QUARK_TRANSPORT_STREAM_ID = g_quark_from_string ("transport-stream-id");
- QUARK_PROGRAM_NUMBER = g_quark_from_string ("program-number");
- QUARK_PID = g_quark_from_string ("pid");
- QUARK_PROGRAMS = g_quark_from_string ("programs");
-
- QUARK_CAT = g_quark_from_string ("cat");
-
- QUARK_PMT = g_quark_from_string ("pmt");
- QUARK_PCR_PID = g_quark_from_string ("pcr-pid");
- QUARK_VERSION_NUMBER = g_quark_from_string ("version-number");
- QUARK_DESCRIPTORS = g_quark_from_string ("descriptors");
- QUARK_STREAM_TYPE = g_quark_from_string ("stream-type");
- QUARK_STREAMS = g_quark_from_string ("streams");
-
- QUARK_NIT = g_quark_from_string ("nit");
- QUARK_NETWORK_ID = g_quark_from_string ("network-id");
- QUARK_CURRENT_NEXT_INDICATOR = g_quark_from_string ("current-next-indicator");
- QUARK_ACTUAL_NETWORK = g_quark_from_string ("actual-network");
- QUARK_NETWORK_NAME = g_quark_from_string ("network-name");
- QUARK_ORIGINAL_NETWORK_ID = g_quark_from_string ("original-network-id");
- QUARK_TRANSPORTS = g_quark_from_string ("transports");
- QUARK_TERRESTRIAL = g_quark_from_string ("terrestrial");
- QUARK_CABLE = g_quark_from_string ("cable");
- QUARK_FREQUENCY = g_quark_from_string ("frequency");
- QUARK_MODULATION = g_quark_from_string ("modulation");
- QUARK_BANDWIDTH = g_quark_from_string ("bandwidth");
- QUARK_CONSTELLATION = g_quark_from_string ("constellation");
- QUARK_HIERARCHY = g_quark_from_string ("hierarchy");
- QUARK_CODE_RATE_HP = g_quark_from_string ("code-rate-hp");
- QUARK_CODE_RATE_LP = g_quark_from_string ("code-rate-lp");
- QUARK_GUARD_INTERVAL = g_quark_from_string ("guard-interval");
- QUARK_TRANSMISSION_MODE = g_quark_from_string ("transmission-mode");
- QUARK_OTHER_FREQUENCY = g_quark_from_string ("other-frequency");
- QUARK_SYMBOL_RATE = g_quark_from_string ("symbol-rate");
- QUARK_INNER_FEC = g_quark_from_string ("inner-fec");
- QUARK_DELIVERY = g_quark_from_string ("delivery");
- QUARK_CHANNELS = g_quark_from_string ("channels");
- QUARK_LOGICAL_CHANNEL_NUMBER = g_quark_from_string ("logical-channel-number");
-
- QUARK_SDT = g_quark_from_string ("sdt");
- QUARK_ACTUAL_TRANSPORT_STREAM =
- g_quark_from_string ("actual-transport-stream");
- QUARK_SERVICES = g_quark_from_string ("services");
-
- QUARK_EIT = g_quark_from_string ("eit");
- QUARK_SERVICE_ID = g_quark_from_string ("service-id");
- QUARK_PRESENT_FOLLOWING = g_quark_from_string ("present-following");
- QUARK_SEGMENT_LAST_SECTION_NUMBER =
- g_quark_from_string ("segment-last-section-number");
- QUARK_LAST_TABLE_ID = g_quark_from_string ("last-table-id");
- QUARK_EVENTS = g_quark_from_string ("events");
- QUARK_NAME = g_quark_from_string ("name");
- QUARK_DESCRIPTION = g_quark_from_string ("description");
- QUARK_EXTENDED_ITEM = g_quark_from_string ("extended_item");
- QUARK_EXTENDED_ITEMS = g_quark_from_string ("extended-items");
- QUARK_TEXT = g_quark_from_string ("text");
- QUARK_EXTENDED_TEXT = g_quark_from_string ("extended-text");
- QUARK_EVENT_ID = g_quark_from_string ("event-id");
- QUARK_YEAR = g_quark_from_string ("year");
- QUARK_MONTH = g_quark_from_string ("month");
- QUARK_DAY = g_quark_from_string ("day");
- QUARK_HOUR = g_quark_from_string ("hour");
- QUARK_MINUTE = g_quark_from_string ("minute");
- QUARK_SECOND = g_quark_from_string ("second");
- QUARK_DURATION = g_quark_from_string ("duration");
- QUARK_RUNNING_STATUS = g_quark_from_string ("running-status");
- QUARK_FREE_CA_MODE = g_quark_from_string ("free-ca-mode");
- QUARK_TDT = g_quark_from_string ("tdt");
- QUARK_TOT = g_quark_from_string ("tot");
-}
-
-/**
- * @text: The text you want to get the encoding from
- * @start_text: Location where the beginning of the actual text is stored
- * @is_multibyte: Location where information whether it's a multibyte encoding
- * or not is stored
- * @returns: GIconv for conversion or NULL
- */
-static LocalIconvCode
-get_encoding (MpegTSPacketizer2 * packetizer, const gchar * text,
- guint * start_text, gboolean * is_multibyte)
-{
- LocalIconvCode encoding;
- guint8 firstbyte;
-
- *is_multibyte = FALSE;
- *start_text = 0;
-
- firstbyte = (guint8) text[0];
-
- /* A wrong value */
- g_return_val_if_fail (firstbyte != 0x00, _ICONV_UNKNOWN);
-
- if (firstbyte <= 0x0B) {
- /* 0x01 => iso 8859-5 */
- encoding = firstbyte + _ICONV_ISO8859_4;
- *start_text = 1;
- goto beach;
- }
-
- /* ETSI EN 300 468, "Selection of character table" */
- switch (firstbyte) {
- case 0x0C:
- case 0x0D:
- case 0x0E:
- case 0x0F:
- /* RESERVED */
- encoding = _ICONV_UNKNOWN;
- break;
- case 0x10:
- {
- guint16 table;
-
- table = GST_READ_UINT16_BE (text + 1);
-
- if (table < 17)
- encoding = _ICONV_UNKNOWN + table;
- else
- encoding = _ICONV_UNKNOWN;;
- *start_text = 3;
- break;
- }
- case 0x11:
- encoding = _ICONV_ISO10646_UC2;
- *start_text = 1;
- *is_multibyte = TRUE;
- break;
- case 0x12:
- /* EUC-KR implements KSX1001 */
- encoding = _ICONV_EUC_KR;
- *start_text = 1;
- *is_multibyte = TRUE;
- break;
- case 0x13:
- encoding = _ICONV_GB2312;
- *start_text = 1;
- break;
- case 0x14:
- encoding = _ICONV_UTF_16BE;
- *start_text = 1;
- *is_multibyte = TRUE;
- break;
- case 0x15:
- /* TODO : Where does this come from ?? */
- encoding = _ICONV_ISO10646_UTF8;
- *start_text = 1;
- break;
- case 0x16:
- case 0x17:
- case 0x18:
- case 0x19:
- case 0x1A:
- case 0x1B:
- case 0x1C:
- case 0x1D:
- case 0x1E:
- case 0x1F:
- /* RESERVED */
- encoding = _ICONV_UNKNOWN;
- break;
- default:
- encoding = _ICONV_ISO6937;
- break;
- }
-
-beach:
- GST_DEBUG
- ("Found encoding %d, first byte is 0x%02x, start_text: %u, is_multibyte: %d",
- encoding, firstbyte, *start_text, *is_multibyte);
-
- return encoding;
-}
-
-/**
- * @text: The text to convert. It may include pango markup (<b> and </b>)
- * @length: The length of the string -1 if it's nul-terminated
- * @start: Where to start converting in the text
- * @encoding: The encoding of text
- * @is_multibyte: Whether the encoding is a multibyte encoding
- * @error: The location to store the error, or NULL to ignore errors
- * @returns: UTF-8 encoded string
- *
- * Convert text to UTF-8.
- */
-static gchar *
-convert_to_utf8 (const gchar * text, gint length, guint start,
- GIConv iconv, gboolean is_multibyte, GError ** error)
-{
- gchar *new_text;
- gchar *tmp, *pos;
- gint i;
-
- text += start;
-
- pos = tmp = g_malloc (length * 2);
-
- if (is_multibyte) {
- if (length == -1) {
- while (*text != '\0') {
- guint16 code = GST_READ_UINT16_BE (text);
-
- switch (code) {
- case 0xE086: /* emphasis on */
- case 0xE087: /* emphasis off */
- /* skip it */
- break;
- case 0xE08A:{
- pos[0] = 0x00; /* 0x00 0x0A is a new line */
- pos[1] = 0x0A;
- pos += 2;
- break;
- }
- default:
- pos[0] = text[0];
- pos[1] = text[1];
- pos += 2;
- break;
- }
-
- text += 2;
- }
- } else {
- for (i = 0; i < length; i += 2) {
- guint16 code = GST_READ_UINT16_BE (text);
-
- switch (code) {
- case 0xE086: /* emphasis on */
- case 0xE087: /* emphasis off */
- /* skip it */
- break;
- case 0xE08A:{
- pos[0] = 0x00; /* 0x00 0x0A is a new line */
- pos[1] = 0x0A;
- pos += 2;
- break;
- }
- default:
- pos[0] = text[0];
- pos[1] = text[1];
- pos += 2;
- break;
- }
-
- text += 2;
- }
- }
- } else {
- if (length == -1) {
- while (*text != '\0') {
- guint8 code = (guint8) (*text);
-
- switch (code) {
- case 0x86: /* emphasis on */
- case 0x87: /* emphasis off */
- /* skip it */
- break;
- case 0x8A:
- *pos = '\n';
- pos += 1;
- break;
- default:
- *pos = *text;
- pos += 1;
- break;
- }
-
- text++;
- }
- } else {
- for (i = 0; i < length; i++) {
- guint8 code = (guint8) (*text);
-
- switch (code) {
- case 0x86: /* emphasis on */
- case 0x87: /* emphasis off */
- /* skip it */
- break;
- case 0x8A:
- *pos = '\n';
- pos += 1;
- break;
- default:
- *pos = *text;
- pos += 1;
- break;
- }
-
- text++;
- }
- }
- }
-
- if (pos > tmp) {
- gsize bread = 0;
-
- new_text =
- g_convert_with_iconv (tmp, pos - tmp, iconv, &bread, NULL, error);
- GST_DEBUG ("Converted to : %s", new_text);
- } else {
- new_text = g_strdup ("");
- }
-
- g_free (tmp);
-
- return new_text;
}
-static gchar *
-get_encoding_and_convert (MpegTSPacketizer2 * packetizer, const gchar * text,
- guint length)
-{
- GError *error = NULL;
- gchar *converted_str;
- guint start_text = 0;
- gboolean is_multibyte;
- LocalIconvCode encoding;
- GIConv iconv = (GIConv) - 1;
-
- g_return_val_if_fail (text != NULL, NULL);
-
- if (text == NULL || length == 0)
- return g_strdup ("");
-
- encoding = get_encoding (packetizer, text, &start_text, &is_multibyte);
-
- if (encoding > _ICONV_UNKNOWN && encoding < _ICONV_MAX) {
- GST_DEBUG ("Encoding %s", iconvtablename[encoding]);
- if (packetizer->priv->iconvs[encoding] == (GIConv) - 1)
- packetizer->priv->iconvs[encoding] =
- g_iconv_open ("utf-8", iconvtablename[encoding]);
- iconv = packetizer->priv->iconvs[encoding];
- }
-
- if (iconv == (GIConv) - 1) {
- GST_WARNING ("Could not detect encoding");
- converted_str = g_strndup (text, length);
- goto beach;
- }
-
- converted_str = convert_to_utf8 (text, length - start_text, start_text,
- iconv, is_multibyte, &error);
- if (error != NULL) {
- GST_WARNING ("Could not convert string: %s", error->message);
- if (converted_str)
- g_free (converted_str);
- g_error_free (error);
- error = NULL;
-
- if (encoding >= _ICONV_ISO8859_2 && encoding <= _ICONV_ISO8859_15) {
- /* Sometimes using the standard 8859-1 set fixes issues */
- GST_DEBUG ("Encoding %s", iconvtablename[_ICONV_ISO8859_1]);
- if (packetizer->priv->iconvs[_ICONV_ISO8859_1] == (GIConv) - 1)
- packetizer->priv->iconvs[_ICONV_ISO8859_1] =
- g_iconv_open ("utf-8", iconvtablename[_ICONV_ISO8859_1]);
- iconv = packetizer->priv->iconvs[_ICONV_ISO8859_1];
-
- GST_INFO ("Trying encoding ISO 8859-1");
- converted_str = convert_to_utf8 (text, length, 1, iconv, FALSE, &error);
- if (error != NULL) {
- GST_WARNING
- ("Could not convert string while assuming encoding ISO 8859-1: %s",
- error->message);
- g_error_free (error);
- goto failed;
- }
- } else if (encoding == _ICONV_ISO6937) {
-
- /* The first part of ISO 6937 is identical to ISO 8859-9, but
- * they differ in the second part. Some channels don't
- * provide the first byte that indicates ISO 8859-9 encoding.
- * If decoding from ISO 6937 failed, we try ISO 8859-9 here.
- */
- if (packetizer->priv->iconvs[_ICONV_ISO8859_9] == (GIConv) - 1)
- packetizer->priv->iconvs[_ICONV_ISO8859_9] =
- g_iconv_open ("utf-8", iconvtablename[_ICONV_ISO8859_9]);
- iconv = packetizer->priv->iconvs[_ICONV_ISO8859_9];
-
- GST_INFO ("Trying encoding ISO 8859-9");
- converted_str = convert_to_utf8 (text, length, 0, iconv, FALSE, &error);
- if (error != NULL) {
- GST_WARNING
- ("Could not convert string while assuming encoding ISO 8859-9: %s",
- error->message);
- g_error_free (error);
- goto failed;
- }
- } else
- goto failed;
- }
-
-beach:
- return converted_str;
-
-failed:
- {
- text += start_text;
- return g_strndup (text, length - start_text);
- }
-}
static void
mpegts_packetizer_resync (MpegTSPCR * pcr, GstClockTime time,
} else
send_diff = gstpcrtime - pcr->base_pcrtime;
- GST_DEBUG ("gstpcr %" GST_TIME_FORMAT ", buftime %" GST_TIME_FORMAT ", base %"
- GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT,
+ GST_DEBUG ("gstpcr %" GST_TIME_FORMAT ", buftime %" GST_TIME_FORMAT
+ ", base %" GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT,
GST_TIME_ARGS (gstpcrtime), GST_TIME_ARGS (time),
GST_TIME_ARGS (pcr->base_pcrtime), GST_TIME_ARGS (send_diff));
slope = recv_diff > 0 ? (send_diff * 8) / recv_diff : 8;
#endif
- GST_DEBUG ("time %" GST_TIME_FORMAT ", base %" GST_TIME_FORMAT ", recv_diff %"
- GST_TIME_FORMAT ", slope %" G_GUINT64_FORMAT, GST_TIME_ARGS (time),
- GST_TIME_ARGS (pcr->base_time), GST_TIME_ARGS (recv_diff), slope);
+ GST_DEBUG ("time %" GST_TIME_FORMAT ", base %" GST_TIME_FORMAT
+ ", recv_diff %" GST_TIME_FORMAT ", slope %" G_GUINT64_FORMAT,
+ GST_TIME_ARGS (time), GST_TIME_ARGS (pcr->base_time),
+ GST_TIME_ARGS (recv_diff), slope);
/* if the difference between the sender timeline and the receiver timeline
* changed too quickly we have to resync because the server likely restarted
}
/* average the min values */
pcr->skew = (pcr->window_min + (124 * pcr->skew)) / 125;
- GST_DEBUG ("delta %" G_GINT64_FORMAT ", new min: %" G_GINT64_FORMAT, delta,
- pcr->window_min);
+ GST_DEBUG ("delta %" G_GINT64_FORMAT ", new min: %" G_GINT64_FORMAT,
+ delta, pcr->window_min);
}
/* wrap around in the window */
if (G_UNLIKELY (pos >= pcr->window_size))
}
static void
-record_pcr (MpegTSPacketizer2 * packetizer, MpegTSPCR * pcrtable, guint64 pcr,
- guint64 offset)
+record_pcr (MpegTSPacketizer2 * packetizer, MpegTSPCR * pcrtable,
+ guint64 pcr, guint64 offset)
{
MpegTSPacketizerPrivate *priv = packetizer->priv;
}
GstClockTime
-mpegts_packetizer_offset_to_ts (MpegTSPacketizer2 * packetizer, guint64 offset,
- guint16 pid)
+mpegts_packetizer_offset_to_ts (MpegTSPacketizer2 * packetizer,
+ guint64 offset, guint16 pid)
{
MpegTSPacketizerPrivate *priv = packetizer->priv;
MpegTSPCR *pcrtable;
}
GstClockTime
-mpegts_packetizer_pts_to_ts (MpegTSPacketizer2 * packetizer, GstClockTime pts,
- guint16 pcr_pid)
+mpegts_packetizer_pts_to_ts (MpegTSPacketizer2 * packetizer,
+ GstClockTime pts, guint16 pcr_pid)
{
GstClockTime res = GST_CLOCK_TIME_NONE;
MpegTSPCR *pcrtable = get_pcr_table (packetizer, pcr_pid);
}
guint64
-mpegts_packetizer_ts_to_offset (MpegTSPacketizer2 * packetizer, GstClockTime ts,
- guint16 pcr_pid)
+mpegts_packetizer_ts_to_offset (MpegTSPacketizer2 * packetizer,
+ GstClockTime ts, guint16 pcr_pid)
{
MpegTSPacketizerPrivate *priv = packetizer->priv;
MpegTSPCR *pcrtable;
pcrtable->last_pcr - pcrtable->first_pcr);
res += pcrtable->first_offset + priv->refoffset;
- GST_DEBUG ("Returning offset %" G_GUINT64_FORMAT " for ts %" GST_TIME_FORMAT,
- res, GST_TIME_ARGS (ts));
+ GST_DEBUG ("Returning offset %" G_GUINT64_FORMAT " for ts %"
+ GST_TIME_FORMAT, res, GST_TIME_ARGS (ts));
return res;
}