mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-25 07:26:29 +00:00
mpegtsmux: Add support for muxing SI tables
The muxer is now able to include DVB sections in the transport stream. The si-interval property will determine how often the SI tables are muxed into the stream. The section is handled by the mpeg-ts library. Below is a small example that will include a Netork Information Table with a Network Name descriptor in the stream. GstMpegTsNIT *nit; GstMpegTsDescriptor *descriptor; GstMpegTsSection *section; GstElement *mpegtsmux; gst_mpegts_initialize (); nit = gst_mpegts_section_nit_new (); nit->actual_network = TRUE; descriptor = gst_mpegts_descriptor_from_dvb_network_name ("Network name"); g_ptr_array_add (nit->descriptors, descriptor); section = gst_mpegts_section_from_nit (nit); // mpegtsmux should be retrieved from the pipeline gst_mpegts_section_send_event (section, mpegtsmux); gst_mpegts_section_unref (section);
This commit is contained in:
parent
b7d256b4c2
commit
93a8137be6
7 changed files with 275 additions and 4 deletions
|
@ -7,7 +7,8 @@ libgstmpegtsmux_la_SOURCES = \
|
||||||
mpegtsmux_aac.c \
|
mpegtsmux_aac.c \
|
||||||
mpegtsmux_ttxt.c
|
mpegtsmux_ttxt.c
|
||||||
|
|
||||||
libgstmpegtsmux_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
|
libgstmpegtsmux_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
|
||||||
|
$(GST_BASE_CFLAGS) $(GST_CFLAGS)
|
||||||
libgstmpegtsmux_la_LIBADD = $(top_builddir)/gst/mpegtsmux/tsmux/libtsmux.la \
|
libgstmpegtsmux_la_LIBADD = $(top_builddir)/gst/mpegtsmux/tsmux/libtsmux.la \
|
||||||
-lgsttag-@GST_API_VERSION@ \
|
-lgsttag-@GST_API_VERSION@ \
|
||||||
$(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ $(GST_BASE_LIBS) $(GST_LIBS)
|
$(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_API_VERSION@ $(GST_BASE_LIBS) $(GST_LIBS)
|
||||||
|
|
|
@ -94,6 +94,7 @@
|
||||||
|
|
||||||
#include <gst/tag/tag.h>
|
#include <gst/tag/tag.h>
|
||||||
#include <gst/video/video.h>
|
#include <gst/video/video.h>
|
||||||
|
#include <gst/mpegts/mpegts.h>
|
||||||
|
|
||||||
#include "mpegtsmux.h"
|
#include "mpegtsmux.h"
|
||||||
|
|
||||||
|
@ -110,7 +111,8 @@ enum
|
||||||
ARG_M2TS_MODE,
|
ARG_M2TS_MODE,
|
||||||
ARG_PAT_INTERVAL,
|
ARG_PAT_INTERVAL,
|
||||||
ARG_PMT_INTERVAL,
|
ARG_PMT_INTERVAL,
|
||||||
ARG_ALIGNMENT
|
ARG_ALIGNMENT,
|
||||||
|
ARG_SI_INTERVAL
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MPEGTSMUX_DEFAULT_ALIGNMENT -1
|
#define MPEGTSMUX_DEFAULT_ALIGNMENT -1
|
||||||
|
@ -177,6 +179,7 @@ static GstPad *mpegtsmux_request_new_pad (GstElement * element,
|
||||||
static void mpegtsmux_release_pad (GstElement * element, GstPad * pad);
|
static void mpegtsmux_release_pad (GstElement * element, GstPad * pad);
|
||||||
static GstStateChangeReturn mpegtsmux_change_state (GstElement * element,
|
static GstStateChangeReturn mpegtsmux_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
|
static gboolean mpegtsmux_send_event (GstElement * element, GstEvent * event);
|
||||||
static void mpegtsdemux_set_header_on_caps (MpegTsMux * mux);
|
static void mpegtsdemux_set_header_on_caps (MpegTsMux * mux);
|
||||||
static gboolean mpegtsmux_src_event (GstPad * pad, GstObject * parent,
|
static gboolean mpegtsmux_src_event (GstPad * pad, GstObject * parent,
|
||||||
GstEvent * event);
|
GstEvent * event);
|
||||||
|
@ -242,6 +245,7 @@ mpegtsmux_class_init (MpegTsMuxClass * klass)
|
||||||
gstelement_class->request_new_pad = mpegtsmux_request_new_pad;
|
gstelement_class->request_new_pad = mpegtsmux_request_new_pad;
|
||||||
gstelement_class->release_pad = mpegtsmux_release_pad;
|
gstelement_class->release_pad = mpegtsmux_release_pad;
|
||||||
gstelement_class->change_state = mpegtsmux_change_state;
|
gstelement_class->change_state = mpegtsmux_change_state;
|
||||||
|
gstelement_class->send_event = mpegtsmux_send_event;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
gstelement_class->set_index = GST_DEBUG_FUNCPTR (mpegtsmux_set_index);
|
gstelement_class->set_index = GST_DEBUG_FUNCPTR (mpegtsmux_set_index);
|
||||||
|
@ -277,6 +281,12 @@ mpegtsmux_class_init (MpegTsMuxClass * klass)
|
||||||
"(-1 = auto, 0 = all available packets)",
|
"(-1 = auto, 0 = all available packets)",
|
||||||
-1, G_MAXINT, MPEGTSMUX_DEFAULT_ALIGNMENT,
|
-1, G_MAXINT, MPEGTSMUX_DEFAULT_ALIGNMENT,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SI_INTERVAL,
|
||||||
|
g_param_spec_uint ("si-interval", "SI interval",
|
||||||
|
"Set the interval (in ticks of the 90kHz clock) for writing out the Service"
|
||||||
|
"Information tables", 1, G_MAXUINT, TSMUX_DEFAULT_SI_INTERVAL,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -310,6 +320,7 @@ mpegtsmux_init (MpegTsMux * mux)
|
||||||
mux->m2ts_mode = MPEGTSMUX_DEFAULT_M2TS;
|
mux->m2ts_mode = MPEGTSMUX_DEFAULT_M2TS;
|
||||||
mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
|
mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
|
||||||
mux->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
|
mux->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
|
||||||
|
mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
|
||||||
mux->prog_map = NULL;
|
mux->prog_map = NULL;
|
||||||
mux->alignment = MPEGTSMUX_DEFAULT_ALIGNMENT;
|
mux->alignment = MPEGTSMUX_DEFAULT_ALIGNMENT;
|
||||||
|
|
||||||
|
@ -478,6 +489,10 @@ gst_mpegtsmux_set_property (GObject * object, guint prop_id,
|
||||||
case ARG_ALIGNMENT:
|
case ARG_ALIGNMENT:
|
||||||
mux->alignment = g_value_get_int (value);
|
mux->alignment = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
case ARG_SI_INTERVAL:
|
||||||
|
mux->si_interval = g_value_get_uint (value);
|
||||||
|
tsmux_set_si_interval (mux->tsmux, mux->si_interval);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -506,6 +521,9 @@ gst_mpegtsmux_get_property (GObject * object, guint prop_id,
|
||||||
case ARG_ALIGNMENT:
|
case ARG_ALIGNMENT:
|
||||||
g_value_set_int (value, mux->alignment);
|
g_value_set_int (value, mux->alignment);
|
||||||
break;
|
break;
|
||||||
|
case ARG_SI_INTERVAL:
|
||||||
|
g_value_set_uint (value, mux->si_interval);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -1706,6 +1724,29 @@ mpegtsmux_change_state (GstElement * element, GstStateChange transition)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mpegtsmux_send_event (GstElement * element, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstMpegTsSection *section;
|
||||||
|
MpegTsMux *mux = GST_MPEG_TSMUX (element);
|
||||||
|
|
||||||
|
g_return_val_if_fail (event != NULL, FALSE);
|
||||||
|
|
||||||
|
section = gst_event_parse_mpegts_section (event);
|
||||||
|
gst_event_unref (event);
|
||||||
|
|
||||||
|
if (section) {
|
||||||
|
GST_DEBUG ("Received event with mpegts section");
|
||||||
|
|
||||||
|
/* TODO: Check that the section type is supported */
|
||||||
|
tsmux_add_mpegts_si_section (mux->tsmux, section);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
plugin_init (GstPlugin * plugin)
|
plugin_init (GstPlugin * plugin)
|
||||||
{
|
{
|
||||||
|
|
|
@ -140,6 +140,7 @@ struct MpegTsMux {
|
||||||
guint pat_interval;
|
guint pat_interval;
|
||||||
guint pmt_interval;
|
guint pmt_interval;
|
||||||
gint alignment;
|
gint alignment;
|
||||||
|
guint si_interval;
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
gboolean first;
|
gboolean first;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
noinst_LTLIBRARIES = libtsmux.la
|
noinst_LTLIBRARIES = libtsmux.la
|
||||||
|
|
||||||
libtsmux_la_CFLAGS = $(GST_CFLAGS)
|
libtsmux_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_CFLAGS)
|
||||||
libtsmux_la_LIBADD = $(GST_LIBS)
|
libtsmux_la_LIBADD = $(GST_LIBS) \
|
||||||
|
$(top_builddir)/gst-libs/gst/mpegts/libgstmpegts-$(GST_API_VERSION).la
|
||||||
libtsmux_la_LDFLAGS = -module -avoid-version
|
libtsmux_la_LDFLAGS = -module -avoid-version
|
||||||
libtsmux_la_SOURCES = tsmux.c tsmuxstream.c
|
libtsmux_la_SOURCES = tsmux.c tsmuxstream.c
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <gst/mpegts/mpegts.h>
|
||||||
|
|
||||||
#include "tsmux.h"
|
#include "tsmux.h"
|
||||||
#include "tsmuxstream.h"
|
#include "tsmuxstream.h"
|
||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
|
@ -114,6 +116,11 @@
|
||||||
|
|
||||||
static gboolean tsmux_write_pat (TsMux * mux);
|
static gboolean tsmux_write_pat (TsMux * mux);
|
||||||
static gboolean tsmux_write_pmt (TsMux * mux, TsMuxProgram * program);
|
static gboolean tsmux_write_pmt (TsMux * mux, TsMuxProgram * program);
|
||||||
|
static void
|
||||||
|
tsmux_section_free (TsMuxSection * section)
|
||||||
|
{
|
||||||
|
gst_mpegts_section_unref (section->section);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tsmux_new:
|
* tsmux_new:
|
||||||
|
@ -139,6 +146,13 @@ tsmux_new (void)
|
||||||
mux->last_pat_ts = -1;
|
mux->last_pat_ts = -1;
|
||||||
mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
|
mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
|
||||||
|
|
||||||
|
mux->si_changed = TRUE;
|
||||||
|
mux->last_si_ts = -1;
|
||||||
|
mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
|
||||||
|
|
||||||
|
mux->si_sections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||||
|
NULL, (GDestroyNotify) tsmux_section_free);
|
||||||
|
|
||||||
return mux;
|
return mux;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,6 +228,72 @@ tsmux_get_pat_interval (TsMux * mux)
|
||||||
return mux->pat_interval;
|
return mux->pat_interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tsmux_set_si_interval:
|
||||||
|
* @mux: a #TsMux
|
||||||
|
* @freq: a new SI table interval
|
||||||
|
*
|
||||||
|
* Set the interval (in cycles of the 90kHz clock) for writing out the SI tables.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
tsmux_set_si_interval (TsMux * mux, guint freq)
|
||||||
|
{
|
||||||
|
g_return_if_fail (mux != NULL);
|
||||||
|
|
||||||
|
mux->si_interval = freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tsmux_get_si_interval:
|
||||||
|
* @mux: a #TsMux
|
||||||
|
*
|
||||||
|
* Get the configured SI table interval. See also tsmux_set_si_interval().
|
||||||
|
*
|
||||||
|
* Returns: the configured SI interval
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
tsmux_get_si_interval (TsMux * mux)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (mux != NULL, 0);
|
||||||
|
|
||||||
|
return mux->si_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tsmux_add_mpegts_si_section:
|
||||||
|
* @mux: a #TsMux
|
||||||
|
* @section: (transfer full): a #GstMpegTsSection to add
|
||||||
|
*
|
||||||
|
* Add a Service Information #GstMpegTsSection to the stream
|
||||||
|
*
|
||||||
|
* Returns: #TRUE on success, #FALSE otherwise
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
tsmux_add_mpegts_si_section (TsMux * mux, GstMpegTsSection * section)
|
||||||
|
{
|
||||||
|
TsMuxSection *tsmux_section;
|
||||||
|
|
||||||
|
g_return_val_if_fail (mux != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (section != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (mux->si_sections != NULL, FALSE);
|
||||||
|
|
||||||
|
tsmux_section = g_slice_new0 (TsMuxSection);
|
||||||
|
|
||||||
|
GST_DEBUG ("Adding mpegts section with type %d to mux",
|
||||||
|
section->section_type);
|
||||||
|
|
||||||
|
tsmux_section->section = section;
|
||||||
|
tsmux_section->pi.pid = section->pid;
|
||||||
|
|
||||||
|
g_hash_table_insert (mux->si_sections,
|
||||||
|
GINT_TO_POINTER (section->section_type), tsmux_section);
|
||||||
|
|
||||||
|
mux->si_changed = TRUE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tsmux_free:
|
* tsmux_free:
|
||||||
* @mux: a #TsMux
|
* @mux: a #TsMux
|
||||||
|
@ -244,6 +324,9 @@ tsmux_free (TsMux * mux)
|
||||||
}
|
}
|
||||||
g_list_free (mux->streams);
|
g_list_free (mux->streams);
|
||||||
|
|
||||||
|
/* Free SI table sections */
|
||||||
|
g_hash_table_destroy (mux->si_sections);
|
||||||
|
|
||||||
g_slice_free (TsMux, mux);
|
g_slice_free (TsMux, mux);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,6 +837,115 @@ tsmux_write_ts_header (guint8 * buf, TsMuxPacketInfo * pi,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
tsmux_section_write_packet (GstMpegTsSectionType * type,
|
||||||
|
TsMuxSection * section, TsMux * mux)
|
||||||
|
{
|
||||||
|
GstBuffer *section_buffer;
|
||||||
|
GstBuffer *packet_buffer = NULL;
|
||||||
|
GstMemory *mem;
|
||||||
|
guint8 *packet;
|
||||||
|
guint8 *data;
|
||||||
|
gsize data_size;
|
||||||
|
gsize payload_written;
|
||||||
|
guint len = 0, offset = 0, payload_len = 0;
|
||||||
|
|
||||||
|
g_return_val_if_fail (section != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (mux != NULL, FALSE);
|
||||||
|
|
||||||
|
/* Mark the start of new PES unit */
|
||||||
|
section->pi.packet_start_unit_indicator = TRUE;
|
||||||
|
|
||||||
|
data = gst_mpegts_section_packetize (section->section, &data_size);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
TS_DEBUG ("Could not packetize section");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark payload data size */
|
||||||
|
section->pi.stream_avail = data_size;
|
||||||
|
payload_written = 0;
|
||||||
|
|
||||||
|
section_buffer = gst_buffer_new_wrapped (data, data_size);
|
||||||
|
|
||||||
|
TS_DEBUG ("Section buffer with size %" G_GSIZE_FORMAT " created",
|
||||||
|
gst_buffer_get_size (section_buffer));
|
||||||
|
|
||||||
|
while (section->pi.stream_avail > 0) {
|
||||||
|
|
||||||
|
packet = g_malloc (TSMUX_PACKET_LENGTH);
|
||||||
|
|
||||||
|
if (section->pi.packet_start_unit_indicator) {
|
||||||
|
/* Wee need room for a pointer byte */
|
||||||
|
section->pi.stream_avail++;
|
||||||
|
|
||||||
|
if (!tsmux_write_ts_header (packet, §ion->pi, &len, &offset))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Write the pointer byte */
|
||||||
|
packet[offset++] = 0x00;
|
||||||
|
payload_len = len - 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (!tsmux_write_ts_header (packet, §ion->pi, &len, &offset))
|
||||||
|
goto fail;
|
||||||
|
payload_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrap the TS header and adaption field in a GstMemory */
|
||||||
|
mem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
|
||||||
|
packet, TSMUX_PACKET_LENGTH, 0, offset, packet, g_free);
|
||||||
|
|
||||||
|
TS_DEBUG ("Creating packet buffer at offset "
|
||||||
|
"%" G_GSIZE_FORMAT " with length %u", payload_written, payload_len);
|
||||||
|
|
||||||
|
packet_buffer = gst_buffer_copy_region (section_buffer, GST_BUFFER_COPY_ALL,
|
||||||
|
payload_written, payload_len);
|
||||||
|
|
||||||
|
/* Prepend the header to the section data */
|
||||||
|
gst_buffer_prepend_memory (packet_buffer, mem);
|
||||||
|
|
||||||
|
TS_DEBUG ("Writing %d bytes to section. %d bytes remaining",
|
||||||
|
len, section->pi.stream_avail - len);
|
||||||
|
|
||||||
|
/* Push the packet without PCR */
|
||||||
|
if G_UNLIKELY
|
||||||
|
(!tsmux_packet_out (mux, packet_buffer, -1)) {
|
||||||
|
/* Buffer given away */
|
||||||
|
packet_buffer = NULL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
section->pi.stream_avail -= len;
|
||||||
|
payload_written += payload_len;
|
||||||
|
section->pi.packet_start_unit_indicator = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (packet)
|
||||||
|
g_free (packet);
|
||||||
|
if (packet_buffer)
|
||||||
|
gst_buffer_unref (packet_buffer);
|
||||||
|
if (section_buffer)
|
||||||
|
gst_buffer_unref (section_buffer);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
tsmux_write_si (TsMux * mux)
|
||||||
|
{
|
||||||
|
g_hash_table_foreach (mux->si_sections,
|
||||||
|
(GHFunc) tsmux_section_write_packet, mux);
|
||||||
|
|
||||||
|
mux->si_changed = FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tsmux_write_stream_packet:
|
* tsmux_write_stream_packet:
|
||||||
* @mux: a #TsMux
|
* @mux: a #TsMux
|
||||||
|
@ -779,6 +971,7 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
||||||
if (tsmux_stream_is_pcr (stream)) {
|
if (tsmux_stream_is_pcr (stream)) {
|
||||||
gint64 cur_pts = tsmux_stream_get_pts (stream);
|
gint64 cur_pts = tsmux_stream_get_pts (stream);
|
||||||
gboolean write_pat;
|
gboolean write_pat;
|
||||||
|
gboolean write_si;
|
||||||
GList *cur;
|
GList *cur;
|
||||||
|
|
||||||
cur_pcr = 0;
|
cur_pcr = 0;
|
||||||
|
@ -822,6 +1015,20 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check if we need to rewrite sit */
|
||||||
|
if (mux->last_si_ts == -1 || mux->si_changed)
|
||||||
|
write_si = TRUE;
|
||||||
|
else if (cur_pts >= mux->last_si_ts + mux->si_interval)
|
||||||
|
write_si = TRUE;
|
||||||
|
else
|
||||||
|
write_si = FALSE;
|
||||||
|
|
||||||
|
if (write_si) {
|
||||||
|
mux->last_si_ts = cur_pts;
|
||||||
|
if (!tsmux_write_si (mux))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* check if we need to rewrite any of the current pmts */
|
/* check if we need to rewrite any of the current pmts */
|
||||||
for (cur = mux->programs; cur; cur = cur->next) {
|
for (cur = mux->programs; cur; cur = cur->next) {
|
||||||
TsMuxProgram *program = (TsMuxProgram *) cur->data;
|
TsMuxProgram *program = (TsMuxProgram *) cur->data;
|
||||||
|
|
|
@ -82,6 +82,8 @@
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <gst/mpegts/mpegts.h>
|
||||||
|
|
||||||
#include "tsmuxcommon.h"
|
#include "tsmuxcommon.h"
|
||||||
#include "tsmuxstream.h"
|
#include "tsmuxstream.h"
|
||||||
|
|
||||||
|
@ -104,6 +106,7 @@ typedef void (*TsMuxAllocFunc) (GstBuffer ** buf, void *user_data);
|
||||||
|
|
||||||
struct TsMuxSection {
|
struct TsMuxSection {
|
||||||
TsMuxPacketInfo pi;
|
TsMuxPacketInfo pi;
|
||||||
|
GstMpegTsSection *section;
|
||||||
|
|
||||||
/* Private sections can be up to 4096 bytes */
|
/* Private sections can be up to 4096 bytes */
|
||||||
guint8 data[TSMUX_MAX_SECTION_LENGTH];
|
guint8 data[TSMUX_MAX_SECTION_LENGTH];
|
||||||
|
@ -148,6 +151,9 @@ struct TsMux {
|
||||||
guint16 next_pmt_pid;
|
guint16 next_pmt_pid;
|
||||||
guint16 next_stream_pid;
|
guint16 next_stream_pid;
|
||||||
|
|
||||||
|
/* Table with TsMuxSection to write */
|
||||||
|
GHashTable *si_sections;
|
||||||
|
|
||||||
TsMuxSection pat;
|
TsMuxSection pat;
|
||||||
/* PAT transport_stream_id */
|
/* PAT transport_stream_id */
|
||||||
guint16 transport_id;
|
guint16 transport_id;
|
||||||
|
@ -160,6 +166,13 @@ struct TsMux {
|
||||||
/* last time PAT written in MPEG PTS clock time */
|
/* last time PAT written in MPEG PTS clock time */
|
||||||
gint64 last_pat_ts;
|
gint64 last_pat_ts;
|
||||||
|
|
||||||
|
/* trigger writing Service Information Tables */
|
||||||
|
gboolean si_changed;
|
||||||
|
/* interval between SIT in MPEG PTS clock time */
|
||||||
|
guint si_interval;
|
||||||
|
/* last time SIT written in MPEG PTS clock time */
|
||||||
|
gint64 last_si_ts;
|
||||||
|
|
||||||
/* callback to write finished packet */
|
/* callback to write finished packet */
|
||||||
TsMuxWriteFunc write_func;
|
TsMuxWriteFunc write_func;
|
||||||
void *write_func_data;
|
void *write_func_data;
|
||||||
|
@ -188,6 +201,11 @@ void tsmux_program_free (TsMuxProgram *program);
|
||||||
void tsmux_set_pmt_interval (TsMuxProgram *program, guint interval);
|
void tsmux_set_pmt_interval (TsMuxProgram *program, guint interval);
|
||||||
guint tsmux_get_pmt_interval (TsMuxProgram *program);
|
guint tsmux_get_pmt_interval (TsMuxProgram *program);
|
||||||
|
|
||||||
|
/* SI table management */
|
||||||
|
void tsmux_set_si_interval (TsMux *mux, guint interval);
|
||||||
|
guint tsmux_get_si_interval (TsMux *mux);
|
||||||
|
gboolean tsmux_add_mpegts_si_section (TsMux * mux, GstMpegTsSection * section);
|
||||||
|
|
||||||
/* stream management */
|
/* stream management */
|
||||||
TsMuxStream * tsmux_create_stream (TsMux *mux, TsMuxStreamType stream_type, guint16 pid, gchar *language);
|
TsMuxStream * tsmux_create_stream (TsMux *mux, TsMuxStreamType stream_type, guint16 pid, gchar *language);
|
||||||
TsMuxStream * tsmux_find_stream (TsMux *mux, guint16 pid);
|
TsMuxStream * tsmux_find_stream (TsMux *mux, guint16 pid);
|
||||||
|
|
|
@ -119,6 +119,8 @@ G_BEGIN_DECLS
|
||||||
#define TSMUX_DEFAULT_PAT_INTERVAL (TSMUX_CLOCK_FREQ / 10)
|
#define TSMUX_DEFAULT_PAT_INTERVAL (TSMUX_CLOCK_FREQ / 10)
|
||||||
/* PMT interval (1/10th sec) */
|
/* PMT interval (1/10th sec) */
|
||||||
#define TSMUX_DEFAULT_PMT_INTERVAL (TSMUX_CLOCK_FREQ / 10)
|
#define TSMUX_DEFAULT_PMT_INTERVAL (TSMUX_CLOCK_FREQ / 10)
|
||||||
|
/* SI interval (1/10th sec) */
|
||||||
|
#define TSMUX_DEFAULT_SI_INTERVAL (TSMUX_CLOCK_FREQ / 10)
|
||||||
|
|
||||||
typedef struct TsMuxPacketInfo TsMuxPacketInfo;
|
typedef struct TsMuxPacketInfo TsMuxPacketInfo;
|
||||||
typedef struct TsMuxProgram TsMuxProgram;
|
typedef struct TsMuxProgram TsMuxProgram;
|
||||||
|
|
Loading…
Reference in a new issue