mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-24 08:08:22 +00:00
mpegts: Add support for creating PAT/PMT
This commit is contained in:
parent
fccfc76805
commit
ffb51c2123
2 changed files with 272 additions and 0 deletions
|
@ -482,6 +482,109 @@ gst_mpegts_section_get_pat (GstMpegTsSection * section)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_mpegts_pat_new:
|
||||||
|
*
|
||||||
|
* Allocates a new #GPtrArray for #GstMpegTsPatProgram
|
||||||
|
*
|
||||||
|
* Returns: (transfer full) (element-type GstMpegTsPatProgram): A newly allocated #GPtrArray
|
||||||
|
*/
|
||||||
|
GPtrArray *
|
||||||
|
gst_mpegts_pat_new (void)
|
||||||
|
{
|
||||||
|
GPtrArray *pat;
|
||||||
|
|
||||||
|
pat = g_ptr_array_new_with_free_func (
|
||||||
|
(GDestroyNotify) _mpegts_pat_program_free);
|
||||||
|
|
||||||
|
return pat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_mpegts_pat_program_new:
|
||||||
|
*
|
||||||
|
* Allocates a new #GstMpegTsPatProgram.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): A newly allocated #GstMpegTsPatProgram
|
||||||
|
*/
|
||||||
|
GstMpegTsPatProgram *
|
||||||
|
gst_mpegts_pat_program_new (void)
|
||||||
|
{
|
||||||
|
GstMpegTsPatProgram *program;
|
||||||
|
|
||||||
|
program = g_slice_new0 (GstMpegTsPatProgram);
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_packetize_pat (GstMpegTsSection * section)
|
||||||
|
{
|
||||||
|
GPtrArray *programs;
|
||||||
|
guint8 *data;
|
||||||
|
gsize length;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
programs = gst_mpegts_section_get_pat (section);
|
||||||
|
|
||||||
|
if (programs == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* 8 byte common section fields
|
||||||
|
4 byte CRC */
|
||||||
|
length = 12;
|
||||||
|
|
||||||
|
/* 2 byte program number
|
||||||
|
2 byte program/network PID */
|
||||||
|
length += programs->len * 4;
|
||||||
|
|
||||||
|
_packetize_common_section (section, length);
|
||||||
|
data = section->data + 8;
|
||||||
|
|
||||||
|
for (i = 0; i < programs->len; i++) {
|
||||||
|
GstMpegTsPatProgram *program;
|
||||||
|
|
||||||
|
program = g_ptr_array_index (programs, i);
|
||||||
|
|
||||||
|
/* program_number - 16 bit uimsbf */
|
||||||
|
GST_WRITE_UINT16_BE (data, program->program_number);
|
||||||
|
data += 2;
|
||||||
|
|
||||||
|
/* reserved - 3 bit
|
||||||
|
program/network_PID - 13 uimsbf */
|
||||||
|
GST_WRITE_UINT16_BE (data, program->network_or_program_map_PID | 0xE000);
|
||||||
|
data += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_unref (programs);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_mpegts_section_from_pat:
|
||||||
|
* @programs: (transfer full) (element-type GstMpegTsPatProgram): an array of #GstMpegTsPatProgram
|
||||||
|
* @ts_id: Transport stream ID of the PAT
|
||||||
|
*
|
||||||
|
* Creates a PAT #GstMpegTsSection from the @programs array of #GstMpegTsPatPrograms
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a #GstMpegTsSection
|
||||||
|
*/
|
||||||
|
GstMpegTsSection *
|
||||||
|
gst_mpegts_section_from_pat (GPtrArray * programs, guint16 ts_id)
|
||||||
|
{
|
||||||
|
GstMpegTsSection *section;
|
||||||
|
|
||||||
|
section = _gst_mpegts_section_init (0x00,
|
||||||
|
GST_MTS_TABLE_ID_PROGRAM_ASSOCIATION);
|
||||||
|
|
||||||
|
section->subtable_extension = ts_id;
|
||||||
|
section->cached_parsed = (gpointer) programs;
|
||||||
|
section->packetizer = _packetize_pat;
|
||||||
|
section->destroy_parsed = (GDestroyNotify) g_ptr_array_unref;
|
||||||
|
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
/* Program Map Table */
|
/* Program Map Table */
|
||||||
|
|
||||||
|
@ -639,6 +742,167 @@ gst_mpegts_section_get_pmt (GstMpegTsSection * section)
|
||||||
return (const GstMpegTsPMT *) section->cached_parsed;
|
return (const GstMpegTsPMT *) section->cached_parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_mpegts_pmt_new:
|
||||||
|
*
|
||||||
|
* Allocates and initializes a new #GstMpegTsPMT.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): #GstMpegTsPMT
|
||||||
|
*/
|
||||||
|
GstMpegTsPMT *
|
||||||
|
gst_mpegts_pmt_new (void)
|
||||||
|
{
|
||||||
|
GstMpegTsPMT *pmt;
|
||||||
|
|
||||||
|
pmt = g_slice_new0 (GstMpegTsPMT);
|
||||||
|
|
||||||
|
pmt->descriptors =
|
||||||
|
g_ptr_array_new_with_free_func ((GDestroyNotify) _free_descriptor);
|
||||||
|
pmt->streams = g_ptr_array_new_with_free_func ((GDestroyNotify)
|
||||||
|
_gst_mpegts_pmt_stream_free);
|
||||||
|
|
||||||
|
return pmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_mpegts_pmt_stream_new:
|
||||||
|
*
|
||||||
|
* Allocates and initializes a new #GstMpegTsPMTStream.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): #GstMpegTsPMTStream
|
||||||
|
*/
|
||||||
|
GstMpegTsPMTStream *
|
||||||
|
gst_mpegts_pmt_stream_new (void)
|
||||||
|
{
|
||||||
|
GstMpegTsPMTStream *stream;
|
||||||
|
|
||||||
|
stream = g_slice_new0 (GstMpegTsPMTStream);
|
||||||
|
|
||||||
|
stream->descriptors =
|
||||||
|
g_ptr_array_new_with_free_func ((GDestroyNotify) _free_descriptor);
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_packetize_pmt (GstMpegTsSection * section)
|
||||||
|
{
|
||||||
|
const GstMpegTsPMT *pmt;
|
||||||
|
GstMpegTsPMTStream *stream;
|
||||||
|
GstMpegTsDescriptor *descriptor;
|
||||||
|
gsize length, pgm_info_length, stream_length;
|
||||||
|
guint8 *data;
|
||||||
|
guint i, j;
|
||||||
|
|
||||||
|
pmt = gst_mpegts_section_get_pmt (section);
|
||||||
|
|
||||||
|
if (pmt == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* 8 byte common section fields
|
||||||
|
2 byte PCR pid
|
||||||
|
2 byte program info length
|
||||||
|
4 byte CRC */
|
||||||
|
length = 16;
|
||||||
|
|
||||||
|
/* Find length of program info */
|
||||||
|
pgm_info_length = 0;
|
||||||
|
if (pmt->descriptors) {
|
||||||
|
for (i = 0; i < pmt->descriptors->len; i++) {
|
||||||
|
descriptor = g_ptr_array_index (pmt->descriptors, i);
|
||||||
|
pgm_info_length += descriptor->length + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find length of PMT streams */
|
||||||
|
stream_length = 0;
|
||||||
|
if (pmt->streams) {
|
||||||
|
for (i = 0; i < pmt->streams->len; i++) {
|
||||||
|
stream = g_ptr_array_index (pmt->streams, i);
|
||||||
|
|
||||||
|
/* 1 byte stream type
|
||||||
|
2 byte PID
|
||||||
|
2 byte ES info length */
|
||||||
|
stream_length += 5;
|
||||||
|
|
||||||
|
if (stream->descriptors) {
|
||||||
|
for (j = 0; j < stream->descriptors->len; j++) {
|
||||||
|
descriptor = g_ptr_array_index (stream->descriptors, i);
|
||||||
|
stream_length += descriptor->length + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
length += pgm_info_length + stream_length;
|
||||||
|
|
||||||
|
_packetize_common_section (section, length);
|
||||||
|
data = section->data + 8;
|
||||||
|
|
||||||
|
/* reserved - 3 bit
|
||||||
|
PCR_PID - 13 uimsbf */
|
||||||
|
GST_WRITE_UINT16_BE (data, pmt->pcr_pid | 0xE000);
|
||||||
|
data += 2;
|
||||||
|
|
||||||
|
/* reserved - 4 bit
|
||||||
|
program_info_length - 12 uimsbf */
|
||||||
|
GST_WRITE_UINT16_BE (data, pgm_info_length | 0xF000);
|
||||||
|
data += 2;
|
||||||
|
|
||||||
|
_packetize_descriptor_array (pmt->descriptors, &data);
|
||||||
|
|
||||||
|
if (pmt->streams) {
|
||||||
|
guint8 *pos;
|
||||||
|
|
||||||
|
for (i = 0; i < pmt->streams->len; i++) {
|
||||||
|
stream = g_ptr_array_index (pmt->streams, i);
|
||||||
|
/* stream_type - 8 bit uimsbf */
|
||||||
|
*data++ = stream->stream_type;
|
||||||
|
|
||||||
|
/* reserved - 3 bit
|
||||||
|
elementary_PID - 13 bit uimsbf */
|
||||||
|
GST_WRITE_UINT16_BE (data, stream->pid | 0xE000);
|
||||||
|
data += 2;
|
||||||
|
|
||||||
|
/* reserved - 4 bit
|
||||||
|
ES_info_length - 12 bit uimsbf */
|
||||||
|
pos = data;
|
||||||
|
data += 2;
|
||||||
|
_packetize_descriptor_array (stream->descriptors, &data);
|
||||||
|
|
||||||
|
/* Go back and update descriptor length */
|
||||||
|
GST_WRITE_UINT16_BE (pos, (data - pos - 2) | 0xF000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_mpegts_section_from_pmt:
|
||||||
|
* @pmt: (transfer full): a #GstMpegTsPMT to create a #GstMpegTsSection from
|
||||||
|
* @pid: The PID that the #GstMpegTsPMT belongs to
|
||||||
|
*
|
||||||
|
* Creates a #GstMpegTsSection from @pmt that is bound to @pid
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): #GstMpegTsSection
|
||||||
|
*/
|
||||||
|
GstMpegTsSection *
|
||||||
|
gst_mpegts_section_from_pmt (GstMpegTsPMT * pmt, guint16 pid)
|
||||||
|
{
|
||||||
|
GstMpegTsSection *section;
|
||||||
|
|
||||||
|
g_return_val_if_fail (pmt != NULL, NULL);
|
||||||
|
|
||||||
|
section = _gst_mpegts_section_init (pid, GST_MTS_TABLE_ID_TS_PROGRAM_MAP);
|
||||||
|
|
||||||
|
section->subtable_extension = pmt->program_number;
|
||||||
|
section->cached_parsed = (gpointer) pmt;
|
||||||
|
section->packetizer = _packetize_pmt;
|
||||||
|
section->destroy_parsed = (GDestroyNotify) _gst_mpegts_pmt_free;
|
||||||
|
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
/* Conditional Access Table */
|
/* Conditional Access Table */
|
||||||
static gpointer
|
static gpointer
|
||||||
|
|
|
@ -182,6 +182,11 @@ struct _GstMpegTsPatProgram
|
||||||
GPtrArray *gst_mpegts_section_get_pat (GstMpegTsSection *section);
|
GPtrArray *gst_mpegts_section_get_pat (GstMpegTsSection *section);
|
||||||
GType gst_mpegts_pat_program_get_type (void);
|
GType gst_mpegts_pat_program_get_type (void);
|
||||||
|
|
||||||
|
GPtrArray *gst_mpegts_pat_new (void);
|
||||||
|
GstMpegTsPatProgram *gst_mpegts_pat_program_new (void);
|
||||||
|
GstMpegTsSection *gst_mpegts_section_from_pat (GPtrArray * programs,
|
||||||
|
guint16 ts_id);
|
||||||
|
|
||||||
/* CAT */
|
/* CAT */
|
||||||
|
|
||||||
GPtrArray *gst_mpegts_section_get_cat (GstMpegTsSection *section);
|
GPtrArray *gst_mpegts_section_get_cat (GstMpegTsSection *section);
|
||||||
|
@ -348,7 +353,10 @@ struct _GstMpegTsPMT
|
||||||
GType gst_mpegts_pmt_get_type (void);
|
GType gst_mpegts_pmt_get_type (void);
|
||||||
GType gst_mpegts_pmt_stream_get_type (void);
|
GType gst_mpegts_pmt_stream_get_type (void);
|
||||||
|
|
||||||
|
GstMpegTsPMT *gst_mpegts_pmt_new (void);
|
||||||
|
GstMpegTsPMTStream *gst_mpegts_pmt_stream_new (void);
|
||||||
const GstMpegTsPMT *gst_mpegts_section_get_pmt (GstMpegTsSection *section);
|
const GstMpegTsPMT *gst_mpegts_section_get_pmt (GstMpegTsSection *section);
|
||||||
|
GstMpegTsSection *gst_mpegts_section_from_pmt (GstMpegTsPMT *pmt, guint16 pid);
|
||||||
|
|
||||||
/* TSDT */
|
/* TSDT */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue