diff options
author | Mathieu Duponchelle <mathieu@centricular.com> | 2019-05-15 01:35:04 +0200 |
---|---|---|
committer | Mathieu Duponchelle <mduponchelle1@gmail.com> | 2019-05-19 19:40:48 +0000 |
commit | 9190541e3cee2d6b8b5a9465228fff2ad804d97f (patch) | |
tree | 3a68b07fd2793073c39730deb473675a81bd5278 /gst/mpegtsmux/tsmux | |
parent | 52efb62876b0fb1e7ef37415d38e551ea3cc9365 (diff) | |
download | gstreamer-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.c | 266 | ||||
-rw-r--r-- | gst/mpegtsmux/tsmux/tsmux.h | 13 |
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; |