summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>2012-06-11 14:03:26 +0200
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>2012-06-11 16:38:51 +0200
commit320436cd77c4b72893824b8b20fdeb314e6bd3b7 (patch)
tree8d6e29c8cb1e626876e3c57f0ded21c9d2e62c6e
parent74fb4199f5037abc7423de3c831f51ac3a75d466 (diff)
mpegtsmux: avoid memcpy due to temporary packet buffer
... by writing directly into the output buffer instead.
-rw-r--r--gst/mpegtsmux/mpegtsmux.c40
-rw-r--r--gst/mpegtsmux/tsmux/tsmux.c109
-rw-r--r--gst/mpegtsmux/tsmux/tsmux.h9
3 files changed, 127 insertions, 31 deletions
diff --git a/gst/mpegtsmux/mpegtsmux.c b/gst/mpegtsmux/mpegtsmux.c
index a9028c597..1aaa10bb5 100644
--- a/gst/mpegtsmux/mpegtsmux.c
+++ b/gst/mpegtsmux/mpegtsmux.c
@@ -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)
{
diff --git a/gst/mpegtsmux/tsmux/tsmux.c b/gst/mpegtsmux/tsmux/tsmux.c
index e84e311d1..06f799250 100644
--- a/gst/mpegtsmux/tsmux/tsmux.c
+++ b/gst/mpegtsmux/tsmux/tsmux.c
@@ -161,6 +161,25 @@ tsmux_set_write_func (TsMux * mux, TsMuxWriteFunc func, void *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
* @freq: a new PAT interval
@@ -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))
+ g_return_val_if_fail (buf, FALSE);
+
+ 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 (mux->packet_buf, TSMUX_PACKET_LENGTH,
- mux->write_func_data, pcr);
+ 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 = &section->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
diff --git a/gst/mpegtsmux/tsmux/tsmux.h b/gst/mpegtsmux/tsmux/tsmux.h
index 210330715..876344204 100644
--- a/gst/mpegtsmux/tsmux/tsmux.h
+++ b/gst/mpegtsmux/tsmux/tsmux.h
@@ -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);