mpegts: Add support for SIT sections

Selection Information Tables (EN 300 468)

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1852>
This commit is contained in:
Edward Hervey 2020-11-22 18:48:08 +01:00 committed by Edward Hervey
parent 5d3a0ca6a9
commit 3cb32df838
6 changed files with 269 additions and 0 deletions

View file

@ -86,6 +86,13 @@ typedef enum {
GST_MTS_DESC_DVB_SERVICE_MOVE = 0x60,
GST_MTS_DESC_DVB_SHORT_SMOOTHING_BUFFER = 0x61,
GST_MTS_DESC_DVB_FREQUENCY_LIST = 0x62,
/**
* GST_MTS_DESC_DVB_PARTIAL_TRANSPORT_STREAM:
*
* Partial Transport Stream descriptor. Only present in SIT Sections.
*
* See also: %GST_MPEGTS_SECTION_SIT, %GstMpegtsSIT
*/
GST_MTS_DESC_DVB_PARTIAL_TRANSPORT_STREAM = 0x63,
GST_MTS_DESC_DVB_DATA_BROADCAST = 0x64,
GST_MTS_DESC_DVB_SCRAMBLING = 0x65,

View file

@ -85,6 +85,12 @@
* * gst_mpegts_section_get_tot()
* * %GstMpegtsTOT
*
* ## Selection Information Table (SIT)
* See:
* * gst_mpegts_section_get_sit()
* * %GstMpegtsSIT
* * %GstMpegtsSITService
*
* # API
*/
@ -1252,3 +1258,160 @@ gst_mpegts_section_get_tot (GstMpegtsSection * section)
return (const GstMpegtsTOT *) section->cached_parsed;
}
/* Selection Information Table (SIT) */
static GstMpegtsSITService *
_gst_mpegts_sit_service_copy (GstMpegtsSITService * sit)
{
GstMpegtsSITService *copy = g_slice_dup (GstMpegtsSITService, sit);
copy->service_id = sit->service_id;
copy->running_status = sit->running_status;
copy->descriptors = g_ptr_array_ref (sit->descriptors);
return copy;
}
static void
_gst_mpegts_sit_service_free (GstMpegtsSITService * sit)
{
if (sit->descriptors)
g_ptr_array_unref (sit->descriptors);
g_slice_free (GstMpegtsSITService, sit);
}
G_DEFINE_BOXED_TYPE (GstMpegtsSITService, gst_mpegts_sit_service,
(GBoxedCopyFunc) _gst_mpegts_sit_service_copy,
(GFreeFunc) _gst_mpegts_sit_service_free);
static GstMpegtsSIT *
_gst_mpegts_sit_copy (GstMpegtsSIT * sit)
{
GstMpegtsSIT *copy = g_slice_dup (GstMpegtsSIT, sit);
copy->services = g_ptr_array_ref (sit->services);
copy->descriptors = g_ptr_array_ref (sit->descriptors);
return copy;
}
static void
_gst_mpegts_sit_free (GstMpegtsSIT * sit)
{
g_ptr_array_unref (sit->services);
g_ptr_array_unref (sit->descriptors);
g_slice_free (GstMpegtsSIT, sit);
}
G_DEFINE_BOXED_TYPE (GstMpegtsSIT, gst_mpegts_sit,
(GBoxedCopyFunc) _gst_mpegts_sit_copy, (GFreeFunc) _gst_mpegts_sit_free);
static gpointer
_parse_sit (GstMpegtsSection * section)
{
GstMpegtsSIT *sit = NULL;
guint i = 0, allocated_services = 8;
guint8 *data, *end, *entry_begin;
guint sit_info_length;
guint descriptors_loop_length;
GST_DEBUG ("SIT");
sit = g_slice_new0 (GstMpegtsSIT);
data = section->data;
end = data + section->section_length;
/* Skip common fields */
data += 8;
descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0fff;
data += 2;
sit->descriptors =
gst_mpegts_parse_descriptors (data, descriptors_loop_length);
if (sit->descriptors == NULL)
goto error;
data += descriptors_loop_length;
sit_info_length = end - data;;
sit->services = g_ptr_array_new_full (allocated_services,
(GDestroyNotify) _gst_mpegts_sit_service_free);
/* read up to the CRC */
while (sit_info_length - 4 > 0) {
GstMpegtsSITService *service = g_slice_new0 (GstMpegtsSITService);
g_ptr_array_add (sit->services, service);
entry_begin = data;
if (sit_info_length - 4 < 4) {
/* each entry must be at least 4 bytes (+4 bytes for the CRC) */
GST_WARNING ("PID %d invalid SIT entry size %d",
section->pid, sit_info_length);
goto error;
}
service->service_id = GST_READ_UINT16_BE (data);
data += 2;
service->running_status = (*data >> 5) & 0x07;
descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0fff;
data += 2;
if (descriptors_loop_length && (data + descriptors_loop_length > end - 4)) {
GST_WARNING ("PID %d invalid SIT entry %d descriptors loop length %d",
section->pid, service->service_id, descriptors_loop_length);
goto error;
}
service->descriptors =
gst_mpegts_parse_descriptors (data, descriptors_loop_length);
if (!service->descriptors)
goto error;
data += descriptors_loop_length;
sit_info_length -= data - entry_begin;
i += 1;
}
if (data != end - 4) {
GST_WARNING ("PID %d invalid SIT parsed %d length %d",
section->pid, (gint) (data - section->data), section->section_length);
goto error;
}
return sit;
error:
if (sit)
_gst_mpegts_sit_free (sit);
return NULL;
}
/**
* gst_mpegts_section_get_sit:
* @section: a #GstMpegtsSection of type %GST_MPEGTS_SECTION_SIT
*
* Returns the #GstMpegtsSIT contained in the @section.
*
* Returns: The #GstMpegtsSIT contained in the section, or %NULL if an error
* happened.
*
* Since: 1.20
*/
const GstMpegtsSIT *
gst_mpegts_section_get_sit (GstMpegtsSection * section)
{
g_return_val_if_fail (section->section_type == GST_MPEGTS_SECTION_SIT, NULL);
g_return_val_if_fail (section->cached_parsed || section->data, NULL);
if (!section->cached_parsed)
section->cached_parsed =
__common_section_checks (section, 18, _parse_sit,
(GDestroyNotify) _gst_mpegts_sit_free);
return (const GstMpegtsSIT *) section->cached_parsed;
}

View file

@ -433,6 +433,68 @@ GType gst_mpegts_tot_get_type (void);
GST_MPEGTS_API
const GstMpegtsTOT *gst_mpegts_section_get_tot (GstMpegtsSection *section);
/* SIT */
typedef struct _GstMpegtsSITService GstMpegtsSITService;
/**
* GST_TYPE_MPEGTS_SIT_SERVICE:
*
* Since: 1.20
*/
#define GST_TYPE_MPEGTS_SIT_SERVICE (gst_mpegts_sit_service_get_type())
typedef struct _GstMpegtsSIT GstMpegtsSIT;
/**
* GST_TYPE_MPEGTS_SIT:
*
* Since: 1.20
*/
#define GST_TYPE_MPEGTS_SIT (gst_mpegts_sit_get_type())
/**
* GstMpegtsSITService:
* @service_id: The Program number this table belongs to
* @running_status: Status of this service
* @descriptors: (element-type GstMpegtsDescriptor): List of descriptors
*
* SIT Service entry
*
* Since: 1.20
*/
struct _GstMpegtsSITService
{
guint16 service_id;
GstMpegtsRunningStatus running_status;
GPtrArray *descriptors;
};
/**
* GstMpegtsSIT:
* @descriptors: (element-type GstMpegtsDescriptor): List of descriptors
* @services: (element-type GstMpegtsSITService): List of services
*
* Selection Information Table (EN 300 468)
*
* Since: 1.20
*/
struct _GstMpegtsSIT
{
GPtrArray *descriptors;
GPtrArray *services;
};
GST_MPEGTS_API
GType gst_mpegts_sit_get_type (void);
GST_MPEGTS_API
GType gst_mpegts_sit_service_get_type (void);
GST_MPEGTS_API
const GstMpegtsSIT *gst_mpegts_section_get_sit (GstMpegtsSection *section);
G_END_DECLS
#endif /* GST_MPEGTS_SECTION_H */

View file

@ -1086,6 +1086,9 @@ _identify_section (guint16 pid, guint8 table_id)
case GST_MTS_TABLE_ID_SCTE_SPLICE:
return GST_MPEGTS_SECTION_SCTE_SIT;
break;
case GST_MTS_TABLE_ID_SELECTION_INFORMATION:
if (pid == 0x001f)
return GST_MPEGTS_SECTION_SIT;
default:
/* Handle ranges */
if (table_id >= GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_PRESENT &&

View file

@ -77,6 +77,14 @@ typedef enum {
GST_MPEGTS_SECTION_SDT,
GST_MPEGTS_SECTION_TDT,
GST_MPEGTS_SECTION_TOT,
/**
* GST_MPEGTS_SECTION_SIT:
*
* Selection Information Table (EN 300 468)
*
* Since: 1.20
*/
GST_MPEGTS_SECTION_SIT,
GST_MPEGTS_SECTION_ATSC_TVCT,
GST_MPEGTS_SECTION_ATSC_CVCT,
GST_MPEGTS_SECTION_ATSC_MGT,

View file

@ -1035,6 +1035,29 @@ dump_sdt (GstMpegtsSection * section)
}
}
static void
dump_sit (GstMpegtsSection * section)
{
const GstMpegtsSIT *sit = gst_mpegts_section_get_sit (section);
guint i, len;
g_assert (sit);
dump_descriptors (sit->descriptors, 7);
len = sit->services->len;
g_printf (" %d Services:\n", len);
for (i = 0; i < len; i++) {
GstMpegtsSITService *service = g_ptr_array_index (sit->services, i);
g_print
(" service_id:0x%04x, running_status:0x%02x (%s)\n",
service->service_id, service->running_status,
enum_name (GST_TYPE_MPEGTS_RUNNING_STATUS, service->running_status));
dump_descriptors (service->descriptors, 9);
}
}
static void
dump_tdt (GstMpegtsSection * section)
{
@ -1256,6 +1279,9 @@ dump_section (GstMpegtsSection * section)
case GST_MPEGTS_SECTION_EIT:
dump_eit (section);
break;
case GST_MPEGTS_SECTION_SIT:
dump_sit (section);
break;
case GST_MPEGTS_SECTION_ATSC_MGT:
dump_mgt (section);
break;