mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-20 08:41:07 +00:00
mpegtsmux: avoid memcpy due to temporary packet buffer
... by writing directly into the output buffer instead.
This commit is contained in:
parent
8800946aa3
commit
05dcabfe16
3 changed files with 128 additions and 32 deletions
|
@ -151,7 +151,8 @@ static void gst_mpegtsmux_get_property (GObject * object, guint prop_id,
|
|||
|
||||
static void mpegtsmux_reset (MpegTsMux * mux, gboolean alloc);
|
||||
static void mpegtsmux_dispose (GObject * object);
|
||||
static gboolean new_packet_cb (guint8 * data, guint len, void *user_data,
|
||||
static void alloc_packet_cb (GstBuffer ** _buf, void *user_data);
|
||||
static gboolean new_packet_cb (GstBuffer * buf, void *user_data,
|
||||
gint64 new_pcr);
|
||||
static void release_buffer_cb (guint8 * data, void *user_data);
|
||||
static GstFlowReturn mpegtsmux_collect_packet (MpegTsMux * mux,
|
||||
|
@ -342,6 +343,7 @@ mpegtsmux_reset (MpegTsMux * mux, gboolean alloc)
|
|||
if (alloc) {
|
||||
mux->tsmux = tsmux_new ();
|
||||
tsmux_set_write_func (mux->tsmux, new_packet_cb, mux);
|
||||
tsmux_set_alloc_func (mux->tsmux, alloc_packet_cb, mux);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1368,20 +1370,20 @@ exit:
|
|||
/* Called when the TsMux has prepared a packet for output. Return FALSE
|
||||
* on error */
|
||||
static gboolean
|
||||
new_packet_cb (guint8 * data, guint len, void *user_data, gint64 new_pcr)
|
||||
new_packet_cb (GstBuffer * buf, void *user_data, gint64 new_pcr)
|
||||
{
|
||||
MpegTsMux *mux = (MpegTsMux *) user_data;
|
||||
gint offset = 0;
|
||||
GstBuffer *buf;
|
||||
|
||||
if (mux->m2ts_mode == TRUE)
|
||||
offset = 4;
|
||||
|
||||
buf = gst_buffer_new_and_alloc (NORMAL_TS_PACKET_LENGTH + offset);
|
||||
offset = GST_BUFFER_DATA (buf) - GST_BUFFER_MALLOCDATA (buf);
|
||||
GST_BUFFER_TIMESTAMP (buf) = mux->last_ts;
|
||||
memcpy (GST_BUFFER_DATA (buf) + offset, data, len);
|
||||
/* do common init (flags and streamheaders) */
|
||||
new_packet_common_init (mux, buf, data, len);
|
||||
new_packet_common_init (mux, buf,
|
||||
GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
|
||||
|
||||
/* all is meant for downstream, including any prefix */
|
||||
GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf);
|
||||
GST_BUFFER_SIZE (buf) += offset;
|
||||
|
||||
if (offset)
|
||||
return new_packet_m2ts (mux, buf, new_pcr);
|
||||
|
@ -1391,6 +1393,26 @@ new_packet_cb (guint8 * data, guint len, void *user_data, gint64 new_pcr)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* called when TsMux needs new packet to write into */
|
||||
static void
|
||||
alloc_packet_cb (GstBuffer ** _buf, void *user_data)
|
||||
{
|
||||
MpegTsMux *mux = (MpegTsMux *) user_data;
|
||||
GstBuffer *buf;
|
||||
gint offset = 0;
|
||||
|
||||
if (mux->m2ts_mode == TRUE)
|
||||
offset = 4;
|
||||
|
||||
/* TODO might be even more efficient to avoid later memcpy
|
||||
* if these are subbuffer from a larger buffer or so */
|
||||
buf = gst_buffer_new_and_alloc (NORMAL_TS_PACKET_LENGTH + offset);
|
||||
GST_BUFFER_DATA (buf) += offset;
|
||||
GST_BUFFER_SIZE (buf) -= offset;
|
||||
|
||||
*_buf = buf;
|
||||
}
|
||||
|
||||
static void
|
||||
mpegtsdemux_set_header_on_caps (MpegTsMux * mux)
|
||||
{
|
||||
|
|
|
@ -160,6 +160,25 @@ tsmux_set_write_func (TsMux * mux, TsMuxWriteFunc func, void *user_data)
|
|||
mux->write_func_data = user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* tsmux_set_alloc_func:
|
||||
* @mux: a #TsMux
|
||||
* @func: a user callback function
|
||||
* @user_data: user data passed to @func
|
||||
*
|
||||
* Set the callback function and user data to be called when @mux needs
|
||||
* a new buffer to write a packet into.
|
||||
* @user_data will be passed as user data in @func.
|
||||
*/
|
||||
void
|
||||
tsmux_set_alloc_func (TsMux * mux, TsMuxAllocFunc func, void *user_data)
|
||||
{
|
||||
g_return_if_fail (mux != NULL);
|
||||
|
||||
mux->alloc_func = func;
|
||||
mux->alloc_func_data = user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* tsmux_set_pat_interval:
|
||||
* @mux: a #TsMux
|
||||
|
@ -435,13 +454,32 @@ tsmux_find_stream (TsMux * mux, guint16 pid)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
tsmux_packet_out (TsMux * mux, gint64 pcr)
|
||||
tsmux_get_buffer (TsMux * mux, GstBuffer ** buf)
|
||||
{
|
||||
if (G_UNLIKELY (mux->write_func == NULL))
|
||||
return TRUE;
|
||||
g_return_val_if_fail (buf, FALSE);
|
||||
|
||||
return mux->write_func (mux->packet_buf, TSMUX_PACKET_LENGTH,
|
||||
mux->write_func_data, pcr);
|
||||
if (G_UNLIKELY (!mux->alloc_func))
|
||||
return FALSE;
|
||||
|
||||
mux->alloc_func (buf, mux->alloc_func_data);
|
||||
|
||||
if (!*buf)
|
||||
return FALSE;
|
||||
|
||||
g_assert (GST_BUFFER_SIZE (*buf) == TSMUX_PACKET_LENGTH);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tsmux_packet_out (TsMux * mux, GstBuffer * buf, gint64 pcr)
|
||||
{
|
||||
if (G_UNLIKELY (mux->write_func == NULL)) {
|
||||
if (buf)
|
||||
gst_buffer_unref (buf);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return mux->write_func (buf, mux->write_func_data, pcr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -707,6 +745,8 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
|||
TsMuxPacketInfo *pi = &stream->pi;
|
||||
gboolean res;
|
||||
gint64 cur_pcr = -1;
|
||||
GstBuffer *buf = NULL;
|
||||
guint8 *data;
|
||||
|
||||
g_return_val_if_fail (mux != NULL, FALSE);
|
||||
g_return_val_if_fail (stream != NULL, FALSE);
|
||||
|
@ -786,19 +826,32 @@ tsmux_write_stream_packet (TsMux * mux, TsMuxStream * stream)
|
|||
}
|
||||
pi->stream_avail = tsmux_stream_bytes_avail (stream);
|
||||
|
||||
if (!tsmux_write_ts_header (mux->packet_buf, pi, &payload_len, &payload_offs))
|
||||
/* obtain buffer */
|
||||
if (!tsmux_get_buffer (mux, &buf))
|
||||
return FALSE;
|
||||
|
||||
if (!tsmux_stream_get_data (stream, mux->packet_buf + payload_offs,
|
||||
payload_len))
|
||||
return FALSE;
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
|
||||
res = tsmux_packet_out (mux, cur_pcr);
|
||||
if (!tsmux_write_ts_header (data, pi, &payload_len, &payload_offs))
|
||||
goto fail;
|
||||
|
||||
if (!tsmux_stream_get_data (stream, data + payload_offs, payload_len))
|
||||
goto fail;
|
||||
|
||||
res = tsmux_packet_out (mux, buf, cur_pcr);
|
||||
|
||||
/* Reset all dynamic flags */
|
||||
stream->pi.flags &= TSMUX_PACKET_FLAG_PES_FULL_HEADER;
|
||||
|
||||
return res;
|
||||
|
||||
/* ERRORS */
|
||||
fail:
|
||||
{
|
||||
if (buf)
|
||||
gst_buffer_unref (buf);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -824,6 +877,7 @@ tsmux_write_section (TsMux * mux, TsMuxSection * section)
|
|||
guint payload_remain;
|
||||
guint payload_len, payload_offs;
|
||||
TsMuxPacketInfo *pi;
|
||||
GstBuffer *buf = NULL;
|
||||
|
||||
pi = §ion->pi;
|
||||
|
||||
|
@ -833,44 +887,61 @@ tsmux_write_section (TsMux * mux, TsMuxSection * section)
|
|||
payload_remain = pi->stream_avail;
|
||||
|
||||
while (payload_remain > 0) {
|
||||
guint8 *data;
|
||||
|
||||
/* obtain buffer */
|
||||
if (!tsmux_get_buffer (mux, &buf))
|
||||
goto fail;
|
||||
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
|
||||
if (pi->packet_start_unit_indicator) {
|
||||
/* Need to write an extra single byte start pointer */
|
||||
pi->stream_avail++;
|
||||
|
||||
if (!tsmux_write_ts_header (mux->packet_buf, pi,
|
||||
&payload_len, &payload_offs)) {
|
||||
if (!tsmux_write_ts_header (data, pi, &payload_len, &payload_offs)) {
|
||||
pi->stream_avail--;
|
||||
return FALSE;
|
||||
goto fail;
|
||||
}
|
||||
pi->stream_avail--;
|
||||
|
||||
/* Write the pointer byte */
|
||||
mux->packet_buf[payload_offs] = 0x00;
|
||||
data[payload_offs] = 0x00;
|
||||
|
||||
payload_offs++;
|
||||
payload_len--;
|
||||
pi->packet_start_unit_indicator = FALSE;
|
||||
} else {
|
||||
if (!tsmux_write_ts_header (mux->packet_buf, pi,
|
||||
&payload_len, &payload_offs))
|
||||
return FALSE;
|
||||
if (!tsmux_write_ts_header (data, pi, &payload_len, &payload_offs))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
TS_DEBUG ("Outputting %d bytes to section. %d remaining after",
|
||||
payload_len, payload_remain - payload_len);
|
||||
|
||||
memcpy (mux->packet_buf + payload_offs, cur_in, payload_len);
|
||||
memcpy (data + payload_offs, cur_in, payload_len);
|
||||
|
||||
cur_in += payload_len;
|
||||
payload_remain -= payload_len;
|
||||
|
||||
/* we do not write PCR in section */
|
||||
if (G_UNLIKELY (!tsmux_packet_out (mux, -1))) {
|
||||
return FALSE;
|
||||
if (G_UNLIKELY (!tsmux_packet_out (mux, buf, -1))) {
|
||||
/* buffer given away */
|
||||
buf = NULL;
|
||||
goto fail;
|
||||
}
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
fail:
|
||||
{
|
||||
if (buf)
|
||||
gst_buffer_unref (buf);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -99,7 +99,8 @@ G_BEGIN_DECLS
|
|||
typedef struct TsMuxSection TsMuxSection;
|
||||
typedef struct TsMux TsMux;
|
||||
|
||||
typedef gboolean (*TsMuxWriteFunc) (guint8 *data, guint len, void *user_data, gint64 new_pcr);
|
||||
typedef gboolean (*TsMuxWriteFunc) (GstBuffer * buf, void *user_data, gint64 new_pcr);
|
||||
typedef void (*TsMuxAllocFunc) (GstBuffer ** buf, void *user_data);
|
||||
|
||||
struct TsMuxSection {
|
||||
TsMuxPacketInfo pi;
|
||||
|
@ -159,11 +160,12 @@ struct TsMux {
|
|||
/* last time PAT written in MPEG PTS clock time */
|
||||
gint64 last_pat_ts;
|
||||
|
||||
/* temp packet buffer */
|
||||
guint8 packet_buf[TSMUX_PACKET_LENGTH];
|
||||
/* callback to write finished packet */
|
||||
TsMuxWriteFunc write_func;
|
||||
void *write_func_data;
|
||||
/* callback to alloc new packet buffer */
|
||||
TsMuxAllocFunc alloc_func;
|
||||
void *alloc_func_data;
|
||||
|
||||
/* scratch space for writing ES_info descriptors */
|
||||
guint8 es_info_buf[TSMUX_MAX_ES_INFO_LENGTH];
|
||||
|
@ -175,6 +177,7 @@ void tsmux_free (TsMux *mux);
|
|||
|
||||
/* Setting muxing session properties */
|
||||
void tsmux_set_write_func (TsMux *mux, TsMuxWriteFunc func, void *user_data);
|
||||
void tsmux_set_alloc_func (TsMux *mux, TsMuxAllocFunc func, void *user_data);
|
||||
void tsmux_set_pat_interval (TsMux *mux, guint interval);
|
||||
guint tsmux_get_pat_interval (TsMux *mux);
|
||||
guint16 tsmux_get_new_pid (TsMux *mux);
|
||||
|
|
Loading…
Reference in a new issue