Merge branch 'mpegtsmux-audio-aggregation' into 'main'

mpegtsmux: Accumulate audio packets for larger PES and a couple of small fixes

Closes #1125

See merge request gstreamer/gstreamer!2085
This commit is contained in:
Jan Schmidt 2024-05-03 20:23:11 +00:00
commit db8ad907bb
10 changed files with 352 additions and 70 deletions

View file

@ -114,6 +114,7 @@ gst_base_ts_mux_pad_reset (GstBaseTsMuxPad * pad)
pad->free_func (pad->prepare_data);
pad->prepare_data = NULL;
pad->prepare_func = NULL;
pad->prepared_size_func = NULL;
pad->free_func = NULL;
if (pad->codec_data)
@ -254,19 +255,25 @@ enum
PROP_SI_INTERVAL,
PROP_BITRATE,
PROP_PCR_INTERVAL,
PROP_AUDIO_PES_TARGET_TIME,
PROP_AUDIO_PES_TARGET_BYTES,
PROP_SCTE_35_PID,
PROP_SCTE_35_NULL_INTERVAL
};
#define DEFAULT_SCTE_35_PID 0
#define BASETSMUX_DEFAULT_ALIGNMENT -1
#define CLOCK_BASE 9LL
#define CLOCK_FREQ (CLOCK_BASE * 10000) /* 90 kHz PTS clock */
#define CLOCK_FREQ_SCR (CLOCK_FREQ * 300) /* 27 MHz SCR clock */
#define TS_MUX_CLOCK_BASE (TSMUX_CLOCK_FREQ * 10 * 360)
#define BASETSMUX_DEFAULT_ALIGNMENT -1
#define BASETSMUX_DEFAULT_AUDIO_PES_TARGET_TIME (CLOCK_FREQ / 1000 * 350) /* 350ms */
/* Aim for a PES header about every 16 TS packets, leaving space for a (max) 22-byte PES header */
#define BASETSMUX_DEFAULT_AUDIO_PES_TARGET_BYTES (16 * TSMUX_PAYLOAD_LENGTH - 22)
#define GSTTIME_TO_MPEGTIME(time) \
(((time) > 0 ? (gint64) 1 : (gint64) -1) * \
(gint64) gst_util_uint64_scale (ABS(time), CLOCK_BASE, GST_MSECOND/10))
@ -374,7 +381,6 @@ gst_base_ts_mux_reset (GstBaseTsMux * mux, gboolean alloc)
GList *l;
mux->first = TRUE;
mux->last_flow_ret = GST_FLOW_OK;
mux->last_ts = GST_CLOCK_TIME_NONE;
mux->is_delta = TRUE;
mux->is_header = FALSE;
@ -473,6 +479,7 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
g_clear_pointer (&ts_pad->codec_data, gst_buffer_unref);
ts_pad->prepare_func = NULL;
ts_pad->prepared_size_func = NULL;
stream_format = gst_structure_get_string (s, "stream-format");
@ -517,6 +524,7 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
ts_pad->codec_data =
gst_base_ts_mux_aac_mpeg2_make_codec_data (mux, caps);
ts_pad->prepare_func = gst_base_ts_mux_prepare_aac_mpeg2;
ts_pad->prepared_size_func = gst_base_ts_mux_prepared_size_aac;
if (ts_pad->codec_data == NULL) {
GST_ERROR_OBJECT (mux, "Invalid or incomplete caps for MPEG-2 AAC");
goto not_negotiated;
@ -536,6 +544,7 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
gst_buffer_get_size (codec_data));
ts_pad->codec_data = gst_buffer_ref (codec_data);
ts_pad->prepare_func = gst_base_ts_mux_prepare_aac_mpeg4;
ts_pad->prepared_size_func = gst_base_ts_mux_prepared_size_aac;
} else {
ts_pad->codec_data = NULL;
GST_ERROR_OBJECT (mux, "Need codec_data for raw MPEG-4 AAC");
@ -580,6 +589,7 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
st = TSMUX_ST_PS_TELETEXT;
/* needs a particularly sized layout */
ts_pad->prepare_func = gst_base_ts_mux_prepare_teletext;
ts_pad->prepared_size_func = gst_base_ts_mux_prepared_size_teletext;
} else if (strcmp (mt, "audio/x-opus") == 0) {
guint8 channels, mapping_family, stream_count, coupled_count;
guint8 channel_mapping[256];
@ -672,6 +682,7 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
st = TSMUX_ST_PS_OPUS;
ts_pad->prepare_func = gst_base_ts_mux_prepare_opus;
ts_pad->prepared_size_func = gst_base_ts_mux_prepared_size_opus;
} else if (strcmp (mt, "meta/x-klv") == 0) {
st = TSMUX_ST_PS_KLV;
} else if (strcmp (mt, "image/x-jpc") == 0) {
@ -767,6 +778,7 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
}
st = TSMUX_ST_VIDEO_JP2K;
ts_pad->prepare_func = gst_base_ts_mux_prepare_jpeg2000;
ts_pad->prepared_size_func = gst_base_ts_mux_prepared_size_jpeg2000;
ts_pad->prepare_data = private_data;
ts_pad->free_func = gst_base_ts_mux_free_jpeg2000;
} else {
@ -796,6 +808,13 @@ gst_base_ts_mux_create_or_update_stream (GstBaseTsMux * mux,
ts_pad->stream =
tsmux_create_stream (mux->tsmux, st, stream_number, ts_pad->pid,
ts_pad->language, ts_pad->bitrate, ts_pad->max_bitrate);
/* if this is an audio stream, report the PES target time in the latency */
if (ts_pad->stream->is_audio) {
gst_aggregator_set_latency (GST_AGGREGATOR (mux),
mux->audio_pes_target_time, GST_CLOCK_TIME_NONE);
}
if (ts_pad->stream == NULL)
goto error;
}
@ -1314,75 +1333,25 @@ alloc_packet_cb (GstBuffer ** buf, void *user_data)
klass->allocate_packet (mux, buf);
}
/* Sends the buffer to tsmux for output.
* Called with mux->lock held. Releases the lock before exit */
static GstFlowReturn
gst_base_ts_mux_aggregate_buffer (GstBaseTsMux * mux,
GstAggregatorPad * agg_pad, GstBuffer * buf)
gst_base_ts_mux_output_buffer_locked (GstBaseTsMux * mux,
GstBaseTsMuxPad * best, GstBuffer * buf, gint64 bufdts)
{
GstFlowReturn ret = GST_FLOW_OK;
GstBaseTsMuxPad *best = GST_BASE_TS_MUX_PAD (agg_pad);
TsMuxProgram *prog;
gint64 pts = GST_CLOCK_STIME_NONE;
TsMuxProgram *prog = best->prog;
gint64 dts = GST_CLOCK_STIME_NONE;
gint64 pts = GST_CLOCK_STIME_NONE;
gboolean delta = TRUE, header = FALSE;
StreamData *stream_data;
GstMpegtsSection *scte_section = NULL;
GST_DEBUG_OBJECT (mux, "Pads collected");
if (buf && gst_buffer_get_size (buf) == 0
&& GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)) {
gst_buffer_unref (buf);
return GST_FLOW_OK;
}
g_mutex_lock (&mux->lock);
if (G_UNLIKELY (mux->first)) {
ret = gst_base_ts_mux_create_streams (mux);
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
if (buf)
gst_buffer_unref (buf);
g_mutex_unlock (&mux->lock);
return ret;
}
mux->first = FALSE;
}
prog = best->prog;
if (prog == NULL) {
GList *cur;
gst_base_ts_mux_create_pad_stream (mux, GST_PAD (best));
tsmux_resend_pat (mux->tsmux);
tsmux_resend_si (mux->tsmux);
prog = best->prog;
g_assert_nonnull (prog);
/* output PMT for each program */
for (cur = mux->tsmux->programs; cur; cur = cur->next) {
TsMuxProgram *program = (TsMuxProgram *) cur->data;
tsmux_resend_pmt (program);
}
}
g_assert (buf != NULL);
if (best->prepare_func) {
GstBuffer *tmp;
tmp = best->prepare_func (buf, best, mux);
g_assert (tmp);
gst_buffer_unref (buf);
buf = tmp;
}
if (mux->force_key_unit_event != NULL && best->stream->is_video_stream) {
GstEvent *event;
g_mutex_unlock (&mux->lock);
event = check_pending_key_unit_event (mux->force_key_unit_event,
&agg_pad->segment, GST_BUFFER_PTS (buf),
&GST_AGGREGATOR_PAD_CAST (best)->segment, GST_BUFFER_PTS (buf),
GST_BUFFER_FLAGS (buf), mux->pending_key_unit_ts);
if (event) {
GstClockTime running_time;
@ -1446,10 +1415,10 @@ gst_base_ts_mux_aggregate_buffer (GstBaseTsMux * mux,
GST_BUFFER_FLAG_DELTA_UNIT) ? " (keyframe)" : "");
}
if (GST_CLOCK_STIME_IS_VALID (best->dts)) {
dts = GSTTIME_TO_MPEGTIME (best->dts);
if (GST_CLOCK_STIME_IS_VALID (bufdts)) {
dts = GSTTIME_TO_MPEGTIME (bufdts);
GST_DEBUG_OBJECT (mux, "Buffer has DTS %" GST_STIME_FORMAT " dts %"
G_GINT64_FORMAT, GST_STIME_ARGS (best->dts), dts);
G_GINT64_FORMAT, GST_STIME_ARGS (bufdts), dts);
}
/* should not have a DTS without PTS */
@ -1506,10 +1475,86 @@ gst_base_ts_mux_aggregate_buffer (GstBaseTsMux * mux,
/* ERRORS */
write_fail:
{
return mux->last_flow_ret;
g_mutex_unlock (&mux->lock);
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
gst_base_ts_mux_prepare_and_accumulate_buffer (GstBaseTsMux * mux,
GstAggregatorPad * agg_pad, GstBuffer * buf)
{
GstFlowReturn ret = GST_FLOW_OK;
GstBaseTsMuxPad *best = GST_BASE_TS_MUX_PAD (agg_pad);
TsMuxProgram *prog;
GST_DEBUG_OBJECT (mux, "Pads collected");
if (buf && gst_buffer_get_size (buf) == 0
&& GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)) {
gst_buffer_unref (buf);
return GST_FLOW_OK;
}
g_mutex_lock (&mux->lock);
if (G_UNLIKELY (mux->first)) {
ret = gst_base_ts_mux_create_streams (mux);
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
if (buf)
gst_buffer_unref (buf);
g_mutex_unlock (&mux->lock);
return ret;
}
mux->first = FALSE;
}
prog = best->prog;
if (prog == NULL) {
GList *cur;
gst_base_ts_mux_create_pad_stream (mux, GST_PAD (best));
tsmux_resend_pat (mux->tsmux);
tsmux_resend_si (mux->tsmux);
prog = best->prog;
g_assert_nonnull (prog);
/* output PMT for each program */
for (cur = mux->tsmux->programs; cur; cur = cur->next) {
TsMuxProgram *program = (TsMuxProgram *) cur->data;
tsmux_resend_pmt (program);
}
}
g_assert (buf != NULL);
if (best->prepare_func) {
GstBuffer *tmp;
tmp = best->prepare_func (buf, best, mux);
g_assert (tmp);
gst_buffer_unref (buf);
buf = tmp;
}
if (best->stream->is_audio) {
if (gst_buffer_get_size (buf) < mux->audio_pes_target_bytes) {
/* Start accumulating audio buffers on this pad */
GST_DEBUG_OBJECT (best, "Starting to accumulate audio PES on pad");
mux->current_pad = gst_object_ref (best);
mux->current_buffer = buf;
mux->current_buffer_dts = best->dts;
g_mutex_unlock (&mux->lock);
return GST_FLOW_OK;
}
}
return gst_base_ts_mux_output_buffer_locked (mux, best, buf, best->dts);
}
/* GstElement implementation */
static gboolean
gst_base_ts_mux_has_pad_with_pid (GstBaseTsMux * mux, guint16 pid)
@ -2414,6 +2459,39 @@ beach:
return ret;
}
static gboolean
can_accumulate_buffer (GstBaseTsMux * mux,
GstBaseTsMuxPad * pad, GstBuffer * new_buf, GstBuffer * current_buf)
{
gsize new_buf_size;
/* If this buffer would overflow the target time, don't accumulate it */
if (GST_BUFFER_DTS_IS_VALID (current_buf) && GST_BUFFER_DTS_IS_VALID (new_buf)
&& GST_CLOCK_DIFF (GST_BUFFER_DTS (current_buf),
GST_BUFFER_DTS (new_buf)) > mux->audio_pes_target_time) {
GST_LOG_OBJECT (pad,
"Not accumulating %" GST_PTR_FORMAT " into pending %" GST_PTR_FORMAT
" - time overflow", new_buf, current_buf);
return FALSE;
}
/* If this buffer would overflow the target size, don't accumulate it */
if (pad->prepared_size_func != NULL)
new_buf_size = pad->prepared_size_func (pad, new_buf);
else
new_buf_size = gst_buffer_get_size (new_buf);
if (gst_buffer_get_size (current_buf) + new_buf_size >
mux->audio_pes_target_bytes) {
GST_LOG_OBJECT (pad,
"Not accumulating %" GST_PTR_FORMAT " into pending %" GST_PTR_FORMAT
" - bytes overflow", new_buf, current_buf);
return FALSE;
}
return TRUE;
}
static GstBaseTsMuxPad *
gst_base_ts_mux_find_best_pad (GstAggregator * aggregator)
{
@ -2478,13 +2556,35 @@ gst_base_ts_mux_are_all_pads_eos (GstBaseTsMux * mux)
return ret;
}
static GstFlowReturn
finish_current_pes (GstBaseTsMux * mux)
{
GstFlowReturn ret;
/* Output the accumulated buffer, then choose a new best pad */
GST_DEBUG_OBJECT (mux->current_pad,
"Outputting accumulated audio PES on pad: %" GST_PTR_FORMAT,
mux->current_buffer);
g_mutex_lock (&mux->lock);
ret =
gst_base_ts_mux_output_buffer_locked (GST_BASE_TS_MUX (mux),
mux->current_pad, mux->current_buffer, mux->current_buffer_dts);
mux->current_buffer = NULL;
gst_object_unref (mux->current_pad);
mux->current_pad = NULL;
return ret;
}
static GstFlowReturn
gst_base_ts_mux_aggregate (GstAggregator * agg, gboolean timeout)
{
GstBaseTsMux *mux = GST_BASE_TS_MUX (agg);
GstFlowReturn ret = GST_FLOW_OK;
GstBaseTsMuxPad *best = gst_base_ts_mux_find_best_pad (agg);
GstBaseTsMuxPad *best = NULL;
GstCaps *caps;
/* set caps on the srcpad if no caps were set yet */
@ -2501,6 +2601,56 @@ gst_base_ts_mux_aggregate (GstAggregator * agg, gboolean timeout)
}
gst_caps_unref (caps);
/* If we're accumulating packets from an audio pad, see if we can fit
* more */
if (mux->current_pad != NULL) {
GstBuffer *buffer =
gst_aggregator_pad_peek_buffer (GST_AGGREGATOR_PAD (mux->current_pad));
gboolean can_accumulate;
if (buffer == NULL)
goto maybe_eos;
can_accumulate =
can_accumulate_buffer (mux, mux->current_pad, buffer,
mux->current_buffer);
gst_buffer_unref (buffer);
if (can_accumulate) {
GstBuffer *tmp;
/* Collect another buffer from the current pad */
best = mux->current_pad;
buffer = gst_aggregator_pad_pop_buffer (GST_AGGREGATOR_PAD (best));
if (!buffer) {
/* We might have gotten a flush event after we picked the pad */
goto maybe_eos;
}
if (best->prepare_func) {
tmp = best->prepare_func (buffer, best, mux);
gst_buffer_unref (buffer);
buffer = tmp;
}
GST_LOG_OBJECT (best,
"Accumulating from current pad. Concatenating %" GST_PTR_FORMAT
" and %" GST_PTR_FORMAT, mux->current_buffer, buffer);
/* Append the new packet to the current PES */
mux->current_buffer = gst_buffer_append (mux->current_buffer, buffer);
goto done;
} else {
ret = finish_current_pes (mux);
if (ret != GST_FLOW_OK)
goto done;
}
}
if (best == NULL)
best = gst_base_ts_mux_find_best_pad (agg);
if (best) {
GstBuffer *buffer;
@ -2511,7 +2661,7 @@ gst_base_ts_mux_aggregate (GstAggregator * agg, gboolean timeout)
}
ret =
gst_base_ts_mux_aggregate_buffer (GST_BASE_TS_MUX (agg),
gst_base_ts_mux_prepare_and_accumulate_buffer (GST_BASE_TS_MUX (agg),
GST_AGGREGATOR_PAD (best), buffer);
gst_object_unref (best);
@ -2520,9 +2670,21 @@ gst_base_ts_mux_aggregate (GstAggregator * agg, gboolean timeout)
goto done;
}
maybe_eos:
if (mux->current_pad != NULL
&& gst_aggregator_pad_is_eos (GST_AGGREGATOR_PAD (mux->current_pad))) {
/* drain some possibly cached data */
if (mux->current_pad != NULL) {
ret = finish_current_pes (mux);
if (ret != GST_FLOW_OK)
goto done;
}
}
if (gst_base_ts_mux_are_all_pads_eos (mux)) {
GstBaseTsMuxClass *klass = GST_BASE_TS_MUX_GET_CLASS (mux);
/* drain some possibly cached data */
GST_DEBUG_OBJECT (mux, "All pads are EOS. Finishing up");
if (klass->drain)
klass->drain (mux);
gst_base_ts_mux_push_packets (mux, TRUE);
@ -2633,15 +2795,15 @@ gst_base_ts_mux_set_property (GObject * object, guint prop_id,
break;
case PROP_PMT_INTERVAL:
mux->pmt_interval = g_value_get_uint (value);
g_mutex_lock (&mux->lock);
GST_OBJECT_LOCK (mux);
for (l = GST_ELEMENT_CAST (mux)->sinkpads; l; l = l->next) {
GstBaseTsMuxPad *ts_pad = GST_BASE_TS_MUX_PAD (l->data);
g_mutex_lock (&mux->lock);
tsmux_set_pmt_interval (ts_pad->prog, mux->pmt_interval);
g_mutex_unlock (&mux->lock);
}
GST_OBJECT_UNLOCK (mux);
g_mutex_unlock (&mux->lock);
break;
case PROP_ALIGNMENT:
mux->alignment = g_value_get_int (value);
@ -2666,6 +2828,14 @@ gst_base_ts_mux_set_property (GObject * object, guint prop_id,
tsmux_set_pcr_interval (mux->tsmux, mux->pcr_interval);
g_mutex_unlock (&mux->lock);
break;
case PROP_AUDIO_PES_TARGET_TIME:
mux->audio_pes_target_time_ticks = g_value_get_uint (value);
mux->audio_pes_target_time =
MPEGTIME_TO_GSTTIME (mux->audio_pes_target_time_ticks);
break;
case PROP_AUDIO_PES_TARGET_BYTES:
mux->audio_pes_target_bytes = g_value_get_uint (value);
break;
case PROP_SCTE_35_PID:
mux->scte35_pid = g_value_get_uint (value);
break;
@ -2706,6 +2876,12 @@ gst_base_ts_mux_get_property (GObject * object, guint prop_id,
case PROP_PCR_INTERVAL:
g_value_set_uint (value, mux->pcr_interval);
break;
case PROP_AUDIO_PES_TARGET_TIME:
g_value_set_uint (value, mux->audio_pes_target_time_ticks);
break;
case PROP_AUDIO_PES_TARGET_BYTES:
g_value_set_uint (value, mux->audio_pes_target_bytes);
break;
case PROP_SCTE_35_PID:
g_value_set_uint (value, mux->scte35_pid);
break;
@ -2865,6 +3041,20 @@ gst_base_ts_mux_class_init (GstBaseTsMuxClass * klass)
TSMUX_DEFAULT_SCTE_35_NULL_INTERVAL,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_AUDIO_PES_TARGET_TIME, g_param_spec_uint ("audio-pes-target-time",
"Audio PES target time",
"Target audio PES duration for aggregating raw audio packets (in ticks of the 90kHz clock)",
0, G_MAXUINT, BASETSMUX_DEFAULT_AUDIO_PES_TARGET_TIME,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_AUDIO_PES_TARGET_BYTES, g_param_spec_uint ("audio-pes-target-bytes",
"Audio PES target size",
"Target audio PES size for aggregating raw audio packets (in bytes)",
0, G_MAXUINT, BASETSMUX_DEFAULT_AUDIO_PES_TARGET_BYTES,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
gst_element_class_add_static_pad_template_with_gtype (gstelement_class,
&gst_base_ts_mux_src_factory, GST_TYPE_AGGREGATOR_PAD);
@ -2890,5 +3080,10 @@ gst_base_ts_mux_init (GstBaseTsMux * mux)
mux->packet_size = GST_BASE_TS_MUX_NORMAL_PACKET_LENGTH;
mux->automatic_alignment = 0;
mux->audio_pes_target_time_ticks = BASETSMUX_DEFAULT_AUDIO_PES_TARGET_TIME;
mux->audio_pes_target_time =
MPEGTIME_TO_GSTTIME (mux->audio_pes_target_time_ticks);
mux->audio_pes_target_bytes = BASETSMUX_DEFAULT_AUDIO_PES_TARGET_BYTES;
g_mutex_init (&mux->lock);
}

View file

@ -98,6 +98,7 @@ typedef struct GstBaseTsPadData GstBaseTsPadData;
typedef GstBuffer * (*GstBaseTsMuxPadPrepareFunction) (GstBuffer * buf,
GstBaseTsMuxPad * data, GstBaseTsMux * mux);
typedef gsize (*GstBaseTsMuxPadPreparedSizeFunction) (GstBaseTsMuxPad * data, GstBuffer * buf);
typedef void (*GstBaseTsMuxPadFreePrepareDataFunction) (gpointer prepare_data);
@ -119,6 +120,8 @@ struct _GstBaseTsMuxPad
/* handler to prepare input data */
GstBaseTsMuxPadPrepareFunction prepare_func;
/* handler to calculate size of prepared input data */
GstBaseTsMuxPadPreparedSizeFunction prepared_size_func;
/* handler to free the private data */
GstBaseTsMuxPadFreePrepareDataFunction free_func;
@ -165,14 +168,22 @@ struct GstBaseTsMux {
guint scte35_null_interval;
guint32 last_scte35_event_seqnum;
GstClockTime audio_pes_target_time;
guint audio_pes_target_time_ticks;
guint audio_pes_target_bytes;
/* state */
gboolean first;
GstClockTime pending_key_unit_ts;
GstEvent *force_key_unit_event;
GstMpegtsSection *pending_scte35_section;
/* Used when accumulating multiple packets for a PES: */
GstBaseTsMuxPad *current_pad;
GstBuffer *current_buffer;
gint64 current_buffer_dts;
/* write callback handling/state */
GstFlowReturn last_flow_ret;
GQueue streamheader;
gboolean streamheader_sent;
gboolean is_delta;

View file

@ -134,6 +134,14 @@ gst_base_ts_mux_prepare_aac_adts (GstBuffer * buf,
return out_buf;
}
gsize
gst_base_ts_mux_prepared_size_aac (GstBaseTsMuxPad * pad, GstBuffer * buf)
{
(void) pad;
return gst_buffer_get_size (buf) + 7;
}
/* Constructs a dummy codec_data buffer for generating ADTS headers
* from raw MPEG-2 AAC input, where we don't expect codec_data in the caps,
* and need to get the info from the profile/channels/rate fields */

View file

@ -69,6 +69,9 @@
#include "gstbasetsmux.h"
gsize gst_base_ts_mux_prepared_size_aac (GstBaseTsMuxPad * pad, GstBuffer * buf);
GstBuffer * gst_base_ts_mux_prepare_aac_mpeg4 (GstBuffer * buf, GstBaseTsMuxPad * pad,
GstBaseTsMux * mux);

View file

@ -128,6 +128,16 @@ gst_base_ts_mux_prepare_jpeg2000 (GstBuffer * buf, GstBaseTsMuxPad * pad,
return out_buf;
}
gsize
gst_base_ts_mux_prepared_size_jpeg2000 (GstBaseTsMuxPad * pad, GstBuffer * buf)
{
j2k_private_data *private_data = pad->prepare_data;
const guint header_size = private_data->interlace ? 48 : 38;
gsize insize = gst_buffer_get_size (buf);
return header_size + insize;
}
void
gst_base_ts_mux_free_jpeg2000 (gpointer prepare_data)
{

View file

@ -59,6 +59,7 @@ typedef struct j2k_private_data
GstBuffer *gst_base_ts_mux_prepare_jpeg2000 (GstBuffer * buf, GstBaseTsMuxPad * pad,
GstBaseTsMux * mux);
gsize gst_base_ts_mux_prepared_size_jpeg2000 (GstBaseTsMuxPad * pad, GstBuffer * buf);
void gst_base_ts_mux_free_jpeg2000 (gpointer prepare_data);

View file

@ -131,3 +131,22 @@ gst_base_ts_mux_prepare_opus (GstBuffer * buf, GstBaseTsMuxPad * pad,
return outbuf;
}
gsize
gst_base_ts_mux_prepared_size_opus (GstBaseTsMuxPad * pad, GstBuffer * buf)
{
gsize insize = gst_buffer_get_size (buf);
gsize outsize;
GstAudioClippingMeta *cmeta = gst_buffer_get_audio_clipping_meta (buf);
(void) pad;
g_assert (!cmeta || cmeta->format == GST_FORMAT_DEFAULT);
outsize = 2 + insize / 255 + 1;
if (cmeta && cmeta->start)
outsize += 2;
if (cmeta && cmeta->end)
outsize += 2;
return outsize + insize;
}

View file

@ -71,5 +71,6 @@
GstBuffer * gst_base_ts_mux_prepare_opus (GstBuffer * buf, GstBaseTsMuxPad * pad,
GstBaseTsMux * mux);
gsize gst_base_ts_mux_prepared_size_opus (GstBaseTsMuxPad * pad, GstBuffer * buf);
#endif /* __BASETSMUX_OPUS_H__ */

View file

@ -138,3 +138,36 @@ gst_base_ts_mux_prepare_teletext (GstBuffer * buf, GstBaseTsMuxPad * pad,
return out_buf;
}
gsize
gst_base_ts_mux_prepared_size_teletext (GstBaseTsMuxPad * pad, GstBuffer * buf)
{
gint size, stuff;
guint8 *data;
GstMapInfo map;
(void) pad;
gst_buffer_map (buf, &map, GST_MAP_READ);
size = map.size;
data = map.data;
/* check if leading data_identifier byte is already present,
* if not increase size since it will need to be added */
if (data[0] < 0x10 || data[0] > 0x1F) {
size += 1;
}
gst_buffer_unmap (buf, &map);
if (size <= 184 - 45) {
stuff = 184 - 45 - size;
} else {
stuff = size - (184 - 45);
stuff = 184 - (stuff % 184);
}
if (G_UNLIKELY (stuff == 1))
stuff += 184;
return size + stuff;
}

View file

@ -71,5 +71,6 @@
GstBuffer * gst_base_ts_mux_prepare_teletext (GstBuffer * buf, GstBaseTsMuxPad * pad,
GstBaseTsMux * mux);
gsize gst_base_ts_mux_prepared_size_teletext (GstBaseTsMuxPad * pad, GstBuffer *buf);
#endif /* __BASETSMUX_TTXT_H__ */