summaryrefslogtreecommitdiff
path: root/gst/mpegtsmux/tsmux
diff options
context:
space:
mode:
authorMathieu Duponchelle <mathieu@centricular.com>2019-05-15 01:35:04 +0200
committerMathieu Duponchelle <mduponchelle1@gmail.com>2019-05-19 19:40:48 +0000
commit9190541e3cee2d6b8b5a9465228fff2ad804d97f (patch)
tree3a68b07fd2793073c39730deb473675a81bd5278 /gst/mpegtsmux/tsmux
parent52efb62876b0fb1e7ef37415d38e551ea3cc9365 (diff)
downloadgstreamer-plugins-bad-9190541e3cee2d6b8b5a9465228fff2ad804d97f.tar.gz
tsmux: refactor logic for when to (re)transmit tables
In order to output them at regular intervals in the bitstream when a bitrate is specified.
Diffstat (limited to 'gst/mpegtsmux/tsmux')
-rw-r--r--gst/mpegtsmux/tsmux/tsmux.c266
-rw-r--r--gst/mpegtsmux/tsmux/tsmux.h13
2 files changed, 157 insertions, 122 deletions
diff --git a/gst/mpegtsmux/tsmux/tsmux.c b/gst/mpegtsmux/tsmux/tsmux.c
index 91dadd6b0..ad5c2d527 100644
--- a/gst/mpegtsmux/tsmux/tsmux.c
+++ b/gst/mpegtsmux/tsmux/tsmux.c
@@ -107,7 +107,7 @@
#define TSMUX_PCR_OFFSET (TSMUX_CLOCK_FREQ / 8)
/* Times per second to write PCR */
-#define TSMUX_DEFAULT_PCR_FREQ (25)
+#define TSMUX_DEFAULT_PCR_FREQ (50)
/* Base for all written PCR and DTS/PTS,
* so we have some slack to go backwards */
@@ -143,13 +143,14 @@ tsmux_new (void)
mux->next_stream_pid = TSMUX_START_ES_PID;
mux->pat_changed = TRUE;
- mux->last_pat_ts = G_MININT64;
+ mux->next_pat_pcr = -1;
mux->pat_interval = TSMUX_DEFAULT_PAT_INTERVAL;
mux->si_changed = TRUE;
- mux->last_si_ts = G_MININT64;
mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
+ mux->next_si_pcr = -1;
+
mux->si_sections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) tsmux_section_free);
@@ -262,7 +263,7 @@ tsmux_resend_pat (TsMux * mux)
{
g_return_if_fail (mux != NULL);
- mux->last_pat_ts = G_MININT64;
+ mux->next_pat_pcr = -1;
}
/**
@@ -309,7 +310,7 @@ tsmux_resend_si (TsMux * mux)
{
g_return_if_fail (mux != NULL);
- mux->last_si_ts = G_MININT64;
+ mux->next_si_pcr = -1;
}
/**
@@ -415,9 +416,10 @@ tsmux_program_new (TsMux * mux, gint prog_id)
program = g_slice_new0 (TsMuxProgram);
program->pmt_changed = TRUE;
- program->last_pmt_ts = G_MININT64;
program->pmt_interval = TSMUX_DEFAULT_PMT_INTERVAL;
+ program->next_pmt_pcr = -1;
+
if (prog_id == 0) {
program->pgm_number = mux->next_pgm_no++;
while (g_list_find_custom (mux->programs, &program->pgm_number,
@@ -490,7 +492,7 @@ tsmux_resend_pmt (TsMuxProgram * program)
{
g_return_if_fail (program != NULL);
- program->last_pmt_ts = G_MININT64;
+ program->next_pmt_pcr = -1;
}
/**
@@ -1057,14 +1059,129 @@ tsmux_write_null_ts_header (guint8 * buf)
*buf++ = 0x10;
}
+static gint64
+get_current_pcr (TsMux * mux, gint64 cur_ts)
+{
+ if (mux->bitrate)
+ return (CLOCK_BASE - TSMUX_PCR_OFFSET) * 300 +
+ gst_util_uint64_scale (mux->n_bytes * 8, TSMUX_SYS_CLOCK_FREQ,
+ mux->bitrate);
+ else if (cur_ts != G_MININT64)
+ return (cur_ts -
+ TSMUX_PCR_OFFSET) * (TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
+ else
+ return 0;
+}
+
+static gint64
+write_new_pcr (TsMux * mux, TsMuxStream * stream, gint64 cur_pcr)
+{
+ if (stream->next_pcr == -1 || cur_pcr > stream->next_pcr) {
+ stream->pi.flags |=
+ TSMUX_PACKET_FLAG_ADAPTATION | TSMUX_PACKET_FLAG_WRITE_PCR;
+ stream->pi.pcr = cur_pcr;
+
+ if (stream->next_pcr == -1)
+ stream->next_pcr =
+ cur_pcr + TSMUX_SYS_CLOCK_FREQ / TSMUX_DEFAULT_PCR_FREQ;
+ else
+ stream->next_pcr += TSMUX_SYS_CLOCK_FREQ / TSMUX_DEFAULT_PCR_FREQ;
+ } else {
+ cur_pcr = -1;
+ }
+
+ return cur_pcr;
+}
+
static gboolean
-pad_stream (TsMux * mux, TsMuxStream * stream, gint64 cur_ts, gint64 * cur_pcr)
+rewrite_si (TsMux * mux, gint64 cur_ts)
+{
+ gboolean write_pat;
+ gboolean write_si;
+ GList *cur;
+ gint64 cur_pcr;
+
+ cur_pcr = get_current_pcr (mux, cur_ts);
+
+ /* check if we need to rewrite pat */
+ if (mux->next_pat_pcr == -1 || mux->pat_changed)
+ write_pat = TRUE;
+ else if (cur_pcr > mux->next_pat_pcr)
+ write_pat = TRUE;
+ else
+ write_pat = FALSE;
+
+ if (write_pat) {
+ if (mux->next_pat_pcr == -1)
+ mux->next_pat_pcr = cur_pcr + mux->pat_interval * 300;
+ else
+ mux->next_pat_pcr += mux->pat_interval * 300;
+
+ if (!tsmux_write_pat (mux))
+ return FALSE;
+
+ cur_pcr = get_current_pcr (mux, cur_ts);
+ }
+
+ /* check if we need to rewrite sit */
+ if (mux->next_si_pcr == -1 || mux->si_changed)
+ write_si = TRUE;
+ else if (cur_pcr > mux->next_si_pcr)
+ write_si = TRUE;
+ else
+ write_si = FALSE;
+
+ if (write_si) {
+ if (mux->next_si_pcr == -1)
+ mux->next_si_pcr = cur_pcr + mux->si_interval * 300;
+ else
+ mux->next_si_pcr += mux->si_interval * 300;
+
+ if (!tsmux_write_si (mux))
+ return FALSE;
+
+ cur_pcr = get_current_pcr (mux, cur_ts);
+ }
+
+ /* check if we need to rewrite any of the current pmts */
+ for (cur = mux->programs; cur; cur = cur->next) {
+ TsMuxProgram *program = (TsMuxProgram *) cur->data;
+ gboolean write_pmt;
+
+ if (program->next_pmt_pcr == -1 || program->pmt_changed)
+ write_pmt = TRUE;
+ else if (cur_pcr > program->next_pmt_pcr)
+ write_pmt = TRUE;
+ else
+ write_pmt = FALSE;
+
+ if (write_pmt) {
+ if (program->next_pmt_pcr == -1)
+ program->next_pmt_pcr = cur_pcr + program->pmt_interval * 300;
+ else
+ program->next_pmt_pcr += program->pmt_interval * 300;
+
+ if (!tsmux_write_pmt (mux, program))
+ return FALSE;
+
+ cur_pcr = get_current_pcr (mux, cur_ts);
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+pad_stream (TsMux * mux, TsMuxStream * stream, gint64 cur_ts)
{
guint64 bitrate;
GstBuffer *buf = NULL;
GstMapInfo map;
gboolean ret = TRUE;
+ if (!mux->bitrate)
+ goto done;
+
do {
if (GST_CLOCK_STIME_IS_VALID (cur_ts)) {
GstClockTimeDiff diff;
@@ -1074,11 +1191,6 @@ pad_stream (TsMux * mux, TsMuxStream * stream, gint64 cur_ts, gint64 * cur_pcr)
diff = GST_CLOCK_DIFF (stream->first_ts, cur_ts);
- *cur_pcr =
- (CLOCK_BASE - TSMUX_PCR_OFFSET) * 300 +
- gst_util_uint64_scale (mux->n_bytes * 8, TSMUX_SYS_CLOCK_FREQ,
- mux->bitrate);
-
if (diff) {
bitrate =
gst_util_uint64_scale (mux->n_bytes * 8, TSMUX_CLOCK_FREQ, diff);
@@ -1086,8 +1198,16 @@ pad_stream (TsMux * mux, TsMuxStream * stream, gint64 cur_ts, gint64 * cur_pcr)
GST_LOG ("Transport stream bitrate: %" G_GUINT64_FORMAT, bitrate);
if (bitrate < mux->bitrate) {
+ gint64 new_pcr;
+ guint payload_len, payload_offs;
+
GST_LOG ("Padding transport stream");
+ if (!rewrite_si (mux, cur_ts)) {
+ ret = FALSE;
+ goto done;
+ }
+
if (!tsmux_get_buffer (mux, &buf)) {
ret = FALSE;
goto done;
@@ -1095,31 +1215,19 @@ pad_stream (TsMux * mux, TsMuxStream * stream, gint64 cur_ts, gint64 * cur_pcr)
gst_buffer_map (buf, &map, GST_MAP_READ);
- if (stream->next_pcr == -1 || *cur_pcr > stream->next_pcr) {
- guint payload_len, payload_offs;
-
- stream->pi.flags |=
- TSMUX_PACKET_FLAG_ADAPTATION | TSMUX_PACKET_FLAG_WRITE_PCR;
- stream->pi.pcr = *cur_pcr;
-
- if (stream->next_pcr == -1)
- stream->next_pcr =
- *cur_pcr + TSMUX_SYS_CLOCK_FREQ / TSMUX_DEFAULT_PCR_FREQ;
- else
- stream->next_pcr += TSMUX_SYS_CLOCK_FREQ / TSMUX_DEFAULT_PCR_FREQ;
-
+ if ((new_pcr =
+ write_new_pcr (mux, stream, get_current_pcr (mux,
+ cur_ts)) != -1))
tsmux_write_ts_header (map.data, &stream->pi, &payload_len,
&payload_offs, 0);
-
- stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
- } else {
+ else
tsmux_write_null_ts_header (map.data);
- *cur_pcr = -1;
- }
gst_buffer_unmap (buf, &map);
- if (!(ret = tsmux_packet_out (mux, buf, *cur_pcr)))
+ stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
+
+ if (!(ret = tsmux_packet_out (mux, buf, new_pcr)))
goto done;
}
} else {
@@ -1149,7 +1257,7 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
guint payload_len, payload_offs;
TsMuxPacketInfo *pi = &stream->pi;
gboolean res;
- gint64 cur_pcr = -1;
+ gint64 new_pcr = -1;
GstBuffer *buf = NULL;
GstMapInfo map;
@@ -1157,94 +1265,20 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
g_return_val_if_fail (stream != NULL, FALSE);
if (tsmux_stream_is_pcr (stream)) {
- gint64 cur_ts;
- gboolean write_pat;
- gboolean write_si;
- GList *cur;
+ gint64 cur_ts = CLOCK_BASE;
if (tsmux_stream_get_dts (stream) != G_MININT64)
- cur_ts = tsmux_stream_get_dts (stream);
+ cur_ts += tsmux_stream_get_dts (stream);
else
- cur_ts = tsmux_stream_get_pts (stream);
-
- cur_pcr = 0;
-
- if (mux->bitrate) {
- if (!pad_stream (mux, stream, cur_ts, &cur_pcr))
- goto fail;
- } else {
- /* FIXME: The current PCR needs more careful calculation than just
- * writing a fixed offset */
- if (cur_ts != G_MININT64) {
- TS_DEBUG ("TS for PCR stream is %" G_GINT64_FORMAT, cur_ts);
- /* CLOCK_BASE >= TSMUX_PCR_OFFSET */
- cur_ts += CLOCK_BASE;
- cur_pcr = (cur_ts - TSMUX_PCR_OFFSET) *
- (TSMUX_SYS_CLOCK_FREQ / TSMUX_CLOCK_FREQ);
- }
- }
+ cur_ts += tsmux_stream_get_pts (stream);
- /* Need to decide whether to write a new PCR in this packet */
- if (stream->next_pcr == -1 || cur_pcr > stream->next_pcr) {
- stream->pi.flags |=
- TSMUX_PACKET_FLAG_ADAPTATION | TSMUX_PACKET_FLAG_WRITE_PCR;
- stream->pi.pcr = cur_pcr;
-
- if (stream->next_pcr == -1)
- stream->next_pcr =
- cur_pcr + TSMUX_SYS_CLOCK_FREQ / TSMUX_DEFAULT_PCR_FREQ;
- else
- stream->next_pcr += TSMUX_SYS_CLOCK_FREQ / TSMUX_DEFAULT_PCR_FREQ;
- } else {
- cur_pcr = -1;
- }
-
- /* check if we need to rewrite pat */
- if (mux->last_pat_ts == G_MININT64 || mux->pat_changed)
- write_pat = TRUE;
- else if (cur_ts >= mux->last_pat_ts + mux->pat_interval)
- write_pat = TRUE;
- else
- write_pat = FALSE;
-
- if (write_pat) {
- mux->last_pat_ts = cur_ts;
- if (!tsmux_write_pat (mux))
- return FALSE;
- }
-
- /* check if we need to rewrite sit */
- if (mux->last_si_ts == G_MININT64 || mux->si_changed)
- write_si = TRUE;
- else if (cur_ts >= mux->last_si_ts + mux->si_interval)
- write_si = TRUE;
- else
- write_si = FALSE;
-
- if (write_si) {
- mux->last_si_ts = cur_ts;
- if (!tsmux_write_si (mux))
- return FALSE;
- }
-
- /* check if we need to rewrite any of the current pmts */
- for (cur = mux->programs; cur; cur = cur->next) {
- TsMuxProgram *program = (TsMuxProgram *) cur->data;
- gboolean write_pmt;
+ if (!rewrite_si (mux, cur_ts))
+ goto fail;
- if (program->last_pmt_ts == G_MININT64 || program->pmt_changed)
- write_pmt = TRUE;
- else if (cur_ts >= program->last_pmt_ts + program->pmt_interval)
- write_pmt = TRUE;
- else
- write_pmt = FALSE;
+ if (!pad_stream (mux, stream, cur_ts))
+ goto fail;
- if (write_pmt) {
- program->last_pmt_ts = cur_ts;
- if (!tsmux_write_pmt (mux, program))
- return FALSE;
- }
- }
+ new_pcr = write_new_pcr (mux, stream, get_current_pcr (mux, cur_ts));
}
pi->packet_start_unit_indicator = tsmux_stream_at_pes_start (stream);
@@ -1274,7 +1308,7 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
gst_buffer_unmap (buf, &map);
GST_DEBUG ("Writing PES of size %d", (int) gst_buffer_get_size (buf));
- res = tsmux_packet_out (mux, buf, cur_pcr);
+ res = tsmux_packet_out (mux, buf, new_pcr);
/* Reset all dynamic flags */
stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
diff --git a/gst/mpegtsmux/tsmux/tsmux.h b/gst/mpegtsmux/tsmux/tsmux.h
index 0f5713b4f..c622e89ef 100644
--- a/gst/mpegtsmux/tsmux/tsmux.h
+++ b/gst/mpegtsmux/tsmux/tsmux.h
@@ -119,8 +119,9 @@ struct TsMuxProgram {
/* interval between PMT in MPEG PTS clock time */
guint pmt_interval;
- /* last time PMT written in MPEG PTS clock time */
- gint64 last_pmt_ts;
+
+ /* Next PMT position, 27 MHz */
+ gint64 next_pmt_pcr;
/* program ID for the PAT */
guint16 pgm_number;
@@ -160,15 +161,15 @@ struct TsMux {
gboolean pat_changed;
/* interval between PAT in MPEG PTS clock time */
guint pat_interval;
- /* last time PAT written in MPEG PTS clock time */
- gint64 last_pat_ts;
+ /* Next PAT position, 27 MHz */
+ gint64 next_pat_pcr;
/* 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;
+ /* Next SIT position, 27 MHz */
+ gint64 next_si_pcr;
/* callback to write finished packet */
TsMuxWriteFunc write_func;