mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
mpegtsmux: Expose bitrate property
This allows outputting a Transport Stream with a constant bitrate, by inserting null packets.
This commit is contained in:
parent
4d53a7ac09
commit
07235bbf46
7 changed files with 106 additions and 3 deletions
|
@ -115,7 +115,8 @@ enum
|
|||
PROP_PAT_INTERVAL,
|
||||
PROP_PMT_INTERVAL,
|
||||
PROP_ALIGNMENT,
|
||||
PROP_SI_INTERVAL
|
||||
PROP_SI_INTERVAL,
|
||||
PROP_BITRATE,
|
||||
};
|
||||
|
||||
#define MPEGTSMUX_DEFAULT_ALIGNMENT -1
|
||||
|
@ -305,6 +306,13 @@ mpegtsmux_class_init (MpegTsMuxClass * klass)
|
|||
"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));
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
|
||||
g_param_spec_uint64 ("bitrate", "Bitrate (in bits per second)",
|
||||
"Set the target bitrate, will insert null packets as padding "
|
||||
" to achieve multiplex-wide constant bitrate",
|
||||
0, G_MAXUINT64, TSMUX_DEFAULT_BITRATE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -338,6 +346,7 @@ mpegtsmux_init (MpegTsMux * mux)
|
|||
mux->si_interval = TSMUX_DEFAULT_SI_INTERVAL;
|
||||
mux->prog_map = NULL;
|
||||
mux->alignment = MPEGTSMUX_DEFAULT_ALIGNMENT;
|
||||
mux->bitrate = TSMUX_DEFAULT_BITRATE;
|
||||
|
||||
/* initial state */
|
||||
mpegtsmux_reset (mux, TRUE);
|
||||
|
@ -511,6 +520,11 @@ gst_mpegtsmux_set_property (GObject * object, guint prop_id,
|
|||
mux->si_interval = g_value_get_uint (value);
|
||||
tsmux_set_si_interval (mux->tsmux, mux->si_interval);
|
||||
break;
|
||||
case PROP_BITRATE:
|
||||
mux->bitrate = g_value_get_uint64 (value);
|
||||
if (mux->tsmux)
|
||||
tsmux_set_bitrate (mux->tsmux, mux->bitrate);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -542,6 +556,9 @@ gst_mpegtsmux_get_property (GObject * object, guint prop_id,
|
|||
case PROP_SI_INTERVAL:
|
||||
g_value_set_uint (value, mux->si_interval);
|
||||
break;
|
||||
case PROP_BITRATE:
|
||||
g_value_set_uint64 (value, mux->bitrate);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -139,6 +139,7 @@ struct MpegTsMux {
|
|||
guint pmt_interval;
|
||||
gint alignment;
|
||||
guint si_interval;
|
||||
guint64 bitrate;
|
||||
|
||||
/* state */
|
||||
gboolean first;
|
||||
|
|
|
@ -634,6 +634,8 @@ tsmux_packet_out (TsMux * mux, GstBuffer * buf, gint64 pcr)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
mux->n_bytes += gst_buffer_get_size (buf);
|
||||
|
||||
return mux->write_func (buf, mux->write_func_data, pcr);
|
||||
}
|
||||
|
||||
|
@ -1019,6 +1021,67 @@ tsmux_write_si (TsMux * mux)
|
|||
|
||||
}
|
||||
|
||||
static void
|
||||
tsmux_write_null_ts_header (guint8 * buf)
|
||||
{
|
||||
*buf++ = TSMUX_SYNC_BYTE;
|
||||
*buf++ = 0x1f;
|
||||
*buf++ = 0xff;
|
||||
*buf++ = 0x10;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pad_stream (TsMux * mux, TsMuxStream * stream, gint64 cur_ts)
|
||||
{
|
||||
guint64 bitrate;
|
||||
GstBuffer *buf = NULL;
|
||||
GstMapInfo map;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
do {
|
||||
if (GST_CLOCK_STIME_IS_VALID (cur_ts)) {
|
||||
GstClockTimeDiff diff;
|
||||
|
||||
if (!GST_CLOCK_STIME_IS_VALID (stream->first_ts))
|
||||
stream->first_ts = cur_ts;
|
||||
|
||||
diff = GST_CLOCK_DIFF (stream->first_ts, cur_ts);
|
||||
|
||||
if (diff) {
|
||||
bitrate =
|
||||
gst_util_uint64_scale (mux->n_bytes * 8, TSMUX_CLOCK_FREQ, diff);
|
||||
|
||||
GST_LOG ("Transport stream bitrate: %" G_GUINT64_FORMAT, bitrate);
|
||||
|
||||
if (bitrate < mux->bitrate) {
|
||||
GST_LOG_OBJECT (mux, "Padding transport stream");
|
||||
|
||||
if (!tsmux_get_buffer (mux, &buf)) {
|
||||
ret = FALSE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
gst_buffer_map (buf, &map, GST_MAP_READ);
|
||||
|
||||
tsmux_write_null_ts_header (map.data);
|
||||
|
||||
gst_buffer_unmap (buf, &map);
|
||||
|
||||
if (!(ret = tsmux_packet_out (mux, buf, -1)))
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (bitrate < mux->bitrate);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tsmux_write_stream_packet:
|
||||
* @mux: a #TsMux
|
||||
|
@ -1052,6 +1115,11 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
|||
else
|
||||
cur_ts = tsmux_stream_get_pts (stream);
|
||||
|
||||
if (mux->bitrate) {
|
||||
if (!pad_stream (mux, stream, cur_ts))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cur_pcr = 0;
|
||||
if (cur_ts != G_MININT64) {
|
||||
TS_DEBUG ("TS for PCR stream is %" G_GINT64_FORMAT, cur_ts);
|
||||
|
@ -1165,9 +1233,10 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
|||
/* ERRORS */
|
||||
fail:
|
||||
{
|
||||
gst_buffer_unmap (buf, &map);
|
||||
if (buf)
|
||||
if (buf) {
|
||||
gst_buffer_unmap (buf, &map);
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -1312,3 +1381,9 @@ tsmux_write_pmt (TsMux * mux, TsMuxProgram * program)
|
|||
return tsmux_section_write_packet (GINT_TO_POINTER (GST_MPEGTS_SECTION_PMT),
|
||||
&program->pmt, mux);
|
||||
}
|
||||
|
||||
void
|
||||
tsmux_set_bitrate (TsMux * mux, guint64 bitrate)
|
||||
{
|
||||
mux->bitrate = bitrate;
|
||||
}
|
||||
|
|
|
@ -178,6 +178,9 @@ struct TsMux {
|
|||
|
||||
/* scratch space for writing ES_info descriptors */
|
||||
guint8 es_info_buf[TSMUX_MAX_ES_INFO_LENGTH];
|
||||
|
||||
guint64 bitrate;
|
||||
guint64 n_bytes;
|
||||
};
|
||||
|
||||
/* create/free new muxer session */
|
||||
|
@ -191,6 +194,7 @@ void tsmux_set_pat_interval (TsMux *mux, guint interval);
|
|||
guint tsmux_get_pat_interval (TsMux *mux);
|
||||
void tsmux_resend_pat (TsMux *mux);
|
||||
guint16 tsmux_get_new_pid (TsMux *mux);
|
||||
void tsmux_set_bitrate (TsMux *mux, guint64 bitrate);
|
||||
|
||||
/* pid/program management */
|
||||
TsMuxProgram * tsmux_program_new (TsMux *mux, gint prog_id);
|
||||
|
|
|
@ -121,6 +121,8 @@ G_BEGIN_DECLS
|
|||
#define TSMUX_DEFAULT_PMT_INTERVAL (TSMUX_CLOCK_FREQ / 10)
|
||||
/* SI interval (1/10th sec) */
|
||||
#define TSMUX_DEFAULT_SI_INTERVAL (TSMUX_CLOCK_FREQ / 10)
|
||||
/* Bitrate (bits per second) */
|
||||
#define TSMUX_DEFAULT_BITRATE 0
|
||||
|
||||
typedef struct TsMuxPacketInfo TsMuxPacketInfo;
|
||||
typedef struct TsMuxProgram TsMuxProgram;
|
||||
|
|
|
@ -224,6 +224,8 @@ tsmux_stream_new (guint16 pid, TsMuxStreamType stream_type)
|
|||
break;
|
||||
}
|
||||
|
||||
stream->first_ts = GST_CLOCK_STIME_NONE;
|
||||
|
||||
stream->last_pts = GST_CLOCK_STIME_NONE;
|
||||
stream->last_dts = GST_CLOCK_STIME_NONE;
|
||||
|
||||
|
|
|
@ -197,6 +197,8 @@ struct TsMuxStream {
|
|||
gint64 last_dts;
|
||||
gint64 last_pts;
|
||||
|
||||
gint64 first_ts;
|
||||
|
||||
/* count of programs using this as PCR */
|
||||
gint pcr_ref;
|
||||
/* Next time PCR should be written */
|
||||
|
|
Loading…
Reference in a new issue