mpegpsmux: port to 0.11

Naive port. Barely tested.
This commit is contained in:
Tim-Philipp Müller 2012-12-31 19:42:03 +00:00
parent c3c33d88d4
commit c056ecb02b
7 changed files with 167 additions and 229 deletions

View file

@ -315,7 +315,7 @@ GST_PLUGINS_NONPORTED=" aiff \
freeverb \
hdvparse ivfparse jp2kdecimator \
kate librfb \
mpegpsmux mve mythtv nsf nuvdemux \
mve mythtv nsf nuvdemux \
patchdetect real \
sdi stereo tta videofilters \
videomeasure videosignal vmnc \

View file

@ -93,37 +93,20 @@ static void gst_mpegpsmux_set_property (GObject * object, guint prop_id,
static void gst_mpegpsmux_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void mpegpsmux_dispose (GObject * object);
static void mpegpsmux_finalize (GObject * object);
static gboolean new_packet_cb (guint8 * data, guint len, void *user_data);
static void release_buffer_cb (guint8 * data, void *user_data);
static gboolean mpegpsdemux_prepare_srcpad (MpegPsMux * mux);
static GstFlowReturn mpegpsmux_collected (GstCollectPads * pads,
MpegPsMux * mux);
static GstPad *mpegpsmux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name);
GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void mpegpsmux_release_pad (GstElement * element, GstPad * pad);
static GstStateChangeReturn mpegpsmux_change_state (GstElement * element,
GstStateChange transition);
GST_BOILERPLATE (MpegPsMux, mpegpsmux, GstElement, GST_TYPE_ELEMENT);
static void
mpegpsmux_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&mpegpsmux_sink_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&mpegpsmux_src_factory));
gst_element_class_set_static_metadata (element_class,
"MPEG Program Stream Muxer", "Codec/Muxer",
"Multiplexes media streams into an MPEG Program Stream",
"Lin YANG <oxcsnicho@gmail.com>");
}
#define parent_class mpegpsmux_parent_class
G_DEFINE_TYPE (MpegPsMux, mpegpsmux, GST_TYPE_ELEMENT);
static void
mpegpsmux_class_init (MpegPsMuxClass * klass)
@ -131,9 +114,9 @@ mpegpsmux_class_init (MpegPsMuxClass * klass)
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_mpegpsmux_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_mpegpsmux_get_property);
gobject_class->dispose = mpegpsmux_dispose;
gobject_class->set_property = gst_mpegpsmux_set_property;
gobject_class->get_property = gst_mpegpsmux_get_property;
gobject_class->finalize = mpegpsmux_finalize;
gstelement_class->request_new_pad = mpegpsmux_request_new_pad;
gstelement_class->release_pad = mpegpsmux_release_pad;
@ -143,10 +126,20 @@ mpegpsmux_class_init (MpegPsMuxClass * klass)
g_param_spec_boolean ("aggregate-gops", "Aggregate GOPs",
"Whether to aggregate GOPs and push them out as buffer lists",
DEFAULT_AGGREGATE_GOPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&mpegpsmux_sink_factory));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&mpegpsmux_src_factory));
gst_element_class_set_static_metadata (gstelement_class,
"MPEG Program Stream Muxer", "Codec/Muxer",
"Multiplexes media streams into an MPEG Program Stream",
"Lin YANG <oxcsnicho@gmail.com>");
}
static void
mpegpsmux_init (MpegPsMux * mux, MpegPsMuxClass * g_class)
mpegpsmux_init (MpegPsMux * mux)
{
mux->srcpad = gst_pad_new_from_static_template (&mpegpsmux_src_factory,
"src");
@ -166,7 +159,7 @@ mpegpsmux_init (MpegPsMux * mux, MpegPsMuxClass * g_class)
}
static void
mpegpsmux_dispose (GObject * object)
mpegpsmux_finalize (GObject * object)
{
MpegPsMux *mux = GST_MPEG_PSMUX (object);
@ -184,7 +177,7 @@ mpegpsmux_dispose (GObject * object)
mux->gop_list = NULL;
}
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
G_OBJECT_CLASS (mpegpsmux_parent_class)->finalize (object);
}
static void
@ -219,25 +212,17 @@ gst_mpegpsmux_get_property (GObject * object, guint prop_id,
}
}
static void
release_buffer_cb (guint8 * data, void *user_data)
{
/* release a given buffer. callback func */
GstBuffer *buf = (GstBuffer *) user_data;
gst_buffer_unref (buf);
}
static GstFlowReturn
mpegpsmux_create_stream (MpegPsMux * mux, MpegPsPadData * ps_data, GstPad * pad)
{
/* Create a steam. Fill in codec specific information */
GstFlowReturn ret = GST_FLOW_ERROR;
GstCaps *caps = gst_pad_get_negotiated_caps (pad);
GstCaps *caps;
GstStructure *s;
gboolean is_video = FALSE;
caps = gst_pad_get_current_caps (pad);
if (caps == NULL) {
GST_DEBUG_OBJECT (pad, "Sink pad caps were not set before pushing");
return GST_FLOW_NOT_NEGOTIATED;
@ -266,8 +251,8 @@ mpegpsmux_create_stream (MpegPsMux * mux, MpegPsPadData * ps_data, GstPad * pad)
value = gst_structure_get_value (s, "codec_data");
if (value) {
ps_data->codec_data = gst_buffer_ref (gst_value_get_buffer (value));
GST_DEBUG_OBJECT (pad, "we have additional codec data (%d bytes)",
GST_BUFFER_SIZE (ps_data->codec_data));
GST_DEBUG_OBJECT (pad, "%" G_GSIZE_FORMAT " bytes of codec data",
gst_buffer_get_size (ps_data->codec_data));
ps_data->prepare_func = mpegpsmux_prepare_h264;
} else {
ps_data->codec_data = NULL;
@ -302,8 +287,8 @@ mpegpsmux_create_stream (MpegPsMux * mux, MpegPsPadData * ps_data, GstPad * pad)
value = gst_structure_get_value (s, "codec_data");
if (value) {
ps_data->codec_data = gst_buffer_ref (gst_value_get_buffer (value));
GST_DEBUG_OBJECT (pad, "we have additional codec data (%d bytes)",
GST_BUFFER_SIZE (ps_data->codec_data));
GST_DEBUG_OBJECT (pad, "%" G_GSIZE_FORMAT " bytes of codec data",
gst_buffer_get_size (ps_data->codec_data));
ps_data->prepare_func = mpegpsmux_prepare_aac;
} else {
ps_data->codec_data = NULL;
@ -347,8 +332,6 @@ mpegpsmux_create_stream (MpegPsMux * mux, MpegPsPadData * ps_data, GstPad * pad)
gst_structure_get_int (s, "channels", &ps_data->stream->audio_channels);
gst_structure_get_int (s, "bitrate", &ps_data->stream->audio_bitrate);
psmux_stream_set_buffer_release_func (ps_data->stream, release_buffer_cb);
ret = GST_FLOW_OK;
if (is_video && mux->video_stream_id == 0) {
@ -483,7 +466,7 @@ mpegpsmux_push_gop_list (MpegPsMux * mux)
g_assert (mux->gop_list != NULL);
GST_DEBUG_OBJECT (mux, "Sending pending GOP of %u buffers",
gst_buffer_list_n_groups (mux->gop_list));
gst_buffer_list_length (mux->gop_list));
flow = gst_pad_push_list (mux->srcpad, mux->gop_list);
mux->gop_list = NULL;
return flow;
@ -549,9 +532,9 @@ mpegpsmux_collected (GstCollectPads * pads, MpegPsMux * mux)
goto done;
}
/* FIXME: porting: add DTS */
/* give the buffer to libpsmux for processing */
psmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf), buf, pts, -1, keyunit);
psmux_stream_add_data (best->stream, buf, pts, -1, keyunit);
best->queued_buf = NULL;
@ -588,9 +571,8 @@ write_fail:
static GstPad *
mpegpsmux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name)
GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
{
MpegPsMux *mux = GST_MPEG_PSMUX (element);
GstPad *pad = NULL;
MpegPsPadData *pad_data = NULL;
@ -652,26 +634,6 @@ mpegpsmux_release_pad (GstElement * element, GstPad * pad)
gst_collect_pads_remove_pad (mux->collect, pad);
}
static void
add_buffer_to_goplist (MpegPsMux * mux, GstBuffer * buf)
{
GstBufferListIterator *it;
if (mux->gop_list == NULL)
mux->gop_list = gst_buffer_list_new ();
it = gst_buffer_list_iterate (mux->gop_list);
/* move iterator to end */
while (gst_buffer_list_iterator_next_group (it)) {
/* .. */
}
gst_buffer_list_iterator_add_group (it);
gst_buffer_list_iterator_add (it, buf);
gst_buffer_list_iterator_free (it);
}
static gboolean
new_packet_cb (guint8 * data, guint len, void *user_data)
{
@ -683,18 +645,17 @@ new_packet_cb (guint8 * data, guint len, void *user_data)
GstFlowReturn ret;
GST_LOG_OBJECT (mux, "Outputting a packet of length %d", len);
buf = gst_buffer_new_and_alloc (len);
if (G_UNLIKELY (buf == NULL)) {
mux->last_flow_ret = GST_FLOW_ERROR;
return FALSE;
}
gst_buffer_set_caps (buf, GST_PAD_CAPS (mux->srcpad));
memcpy (GST_BUFFER_DATA (buf), data, len);
data = g_memdup (data, len);
buf = gst_buffer_new_wrapped (data, len);
GST_BUFFER_TIMESTAMP (buf) = mux->last_ts;
if (mux->aggregate_gops) {
add_buffer_to_goplist (mux, buf);
if (mux->gop_list == NULL)
mux->gop_list = gst_buffer_list_new ();
gst_buffer_list_add (mux->gop_list, buf);
return TRUE;
}
@ -708,22 +669,17 @@ new_packet_cb (guint8 * data, guint len, void *user_data)
return TRUE;
}
/* prepare the source pad for output */
static gboolean
mpegpsdemux_prepare_srcpad (MpegPsMux * mux)
{
GstSegment segment;
GValue val = { 0, };
GList *headers, *l;
GstCaps *caps;
/* prepare the source pad for output */
GstEvent *new_seg =
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0);
GstCaps *caps = gst_caps_new_simple ("video/mpeg",
"mpegversion", G_TYPE_INT, 2,
"systemstream", G_TYPE_BOOLEAN, TRUE,
NULL);
/* gst_static_pad_template_get_caps (&mpegpsmux_src_factory); */
caps = gst_caps_new_simple ("video/mpeg",
"mpegversion", G_TYPE_INT, 2, "systemstream", G_TYPE_BOOLEAN, TRUE, NULL);
headers = psmux_get_stream_headers (mux->psmux);
g_value_init (&val, GST_TYPE_ARRAY);
@ -740,13 +696,12 @@ mpegpsdemux_prepare_srcpad (MpegPsMux * mux)
g_value_unset (&val);
g_list_free (headers);
/* Set caps on src pad from our template and push new segment */
gst_pad_set_caps (mux->srcpad, caps);
/* Set caps on src pad and push new segment */
gst_pad_push_event (mux->srcpad, gst_event_new_caps (caps));
gst_caps_unref (caps);
if (!gst_pad_push_event (mux->srcpad, new_seg)) {
GST_WARNING_OBJECT (mux, "New segment event was not handled");
return FALSE;
}
gst_segment_init (&segment, GST_FORMAT_BYTES);
gst_pad_push_event (mux->srcpad, gst_event_new_segment (&segment));
return TRUE;
}

View file

@ -95,24 +95,28 @@ GST_DEBUG_CATEGORY_EXTERN (mpegpsmux_debug);
GstBuffer *
mpegpsmux_prepare_aac (GstBuffer * buf, MpegPsPadData * data, MpegPsMux * mux)
{
guint8 adts_header[7] = { 0, };
GstBuffer *out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) + 7);
gsize out_offset = 0;
GstBuffer *out_buf;
GstMemory *mem;
gsize out_size;
guint8 *adts_header, codec_data[2];
guint8 rate_idx = 0, channels = 0, obj_type = 0;
GST_DEBUG_OBJECT (mux, "Preparing AAC buffer for output");
/* We want the same metadata */
gst_buffer_copy_metadata (out_buf, buf, GST_BUFFER_COPY_ALL);
adts_header = g_malloc0 (7);
/* We want the same data and metadata, and then prepend some bytes */
out_buf = gst_buffer_copy (buf);
out_size = gst_buffer_get_size (buf) + 7;
gst_buffer_extract (data->codec_data, 0, codec_data, 2);
/* Generate ADTS header */
obj_type = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data)) & 0xC) >> 2;
obj_type = (codec_data[0] & 0xC) >> 2;
obj_type++;
rate_idx = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data)) & 0x3) << 1;
rate_idx |=
(GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + 1) & 0x80) >> 7;
channels =
(GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + 1) & 0x78) >> 3;
rate_idx = (codec_data[0] & 0x3) << 1;
rate_idx |= (codec_data[1] & 0x80) >> 7;
channels = (codec_data[1] & 0x78) >> 3;
GST_DEBUG_OBJECT (mux, "Rate index %u, channels %u, object type %u", rate_idx,
channels, obj_type);
/* Sync point over a full byte */
@ -129,24 +133,20 @@ mpegpsmux_prepare_aac (GstBuffer * buf, MpegPsPadData * data, MpegPsMux * mux)
/* channels continued over next 2 bits + 4 bits at zero */
adts_header[3] = (channels & 0x3) << 6;
/* frame size over last 2 bits */
adts_header[3] |= (GST_BUFFER_SIZE (out_buf) & 0x1800) >> 11;
adts_header[3] |= (gst_buffer_get_size (out_buf) & 0x1800) >> 11;
/* frame size continued over full byte */
adts_header[4] = (GST_BUFFER_SIZE (out_buf) & 0x1FF8) >> 3;
adts_header[4] = (out_size & 0x1FF8) >> 3;
/* frame size continued first 3 bits */
adts_header[5] = (GST_BUFFER_SIZE (out_buf) & 0x7) << 5;
adts_header[5] = (out_size & 0x7) << 5;
/* buffer fullness (0x7FF for VBR) over 5 last bits */
adts_header[5] |= 0x1F;
/* buffer fullness (0x7FF for VBR) continued over 6 first bits + 2 zeros for
* number of raw data blocks */
adts_header[6] = 0xFC;
/* Insert ADTS header */
memcpy (GST_BUFFER_DATA (out_buf) + out_offset, adts_header, 7);
out_offset += 7;
/* Now copy complete frame */
memcpy (GST_BUFFER_DATA (out_buf) + out_offset, GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf));
/* Prepend ADTS header */
mem = gst_memory_new_wrapped (0, adts_header, 7, 0, 7, adts_header, g_free);
gst_buffer_prepend_memory (out_buf, mem);
return out_buf;
}

View file

@ -87,6 +87,7 @@
#endif
#include "mpegpsmux_h264.h"
#include <gst/base/gstbytewriter.h>
#include <string.h>
GST_DEBUG_CATEGORY_EXTERN (mpegpsmux_debug);
@ -95,32 +96,37 @@ GST_DEBUG_CATEGORY_EXTERN (mpegpsmux_debug);
GstBuffer *
mpegpsmux_prepare_h264 (GstBuffer * buf, MpegPsPadData * data, MpegPsMux * mux)
{
GstByteWriter bw;
GstMapInfo codec_data, map;
guint8 nal_length_size = 0;
guint8 startcode[4] = { 0x00, 0x00, 0x00, 0x01 };
GstBuffer *out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) * 2);
gint offset = 4, i = 0, nb_sps = 0, nb_pps = 0;
gsize out_offset = 0, in_offset = 0;
GstBuffer *out_buf;
guint8 nb_sps = 0, nb_pps = 0;
gint offset = 4, i = 0;
gsize in_offset;
GST_DEBUG_OBJECT (mux, "Preparing H264 buffer for output");
/* We want the same metadata */
gst_buffer_copy_metadata (out_buf, buf, GST_BUFFER_COPY_ALL);
/* FIXME: are we prepending SPS/PPS in front of every single buffer?
* (should only be in front of keyframes really, if at all) */
/* FIXME: create a byte-stream version of SPS/PPS once in set_caps */
if (!gst_buffer_map (data->codec_data, &codec_data, GST_MAP_READ))
return NULL;
gst_byte_writer_init_with_size (&bw, gst_buffer_get_size (buf) * 2, FALSE);
/* Get NAL length size */
nal_length_size =
(GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset) & 0x03) + 1;
nal_length_size = (codec_data.data[offset] & 0x03) + 1;
GST_LOG_OBJECT (mux, "NAL length will be coded on %u bytes", nal_length_size);
offset++;
/* Generate SPS */
nb_sps = GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset) & 0x1f;
nb_sps = codec_data.data[offset] & 0x1f;
GST_DEBUG_OBJECT (mux, "we have %d Sequence Parameter Set", nb_sps);
offset++;
/* For each SPS */
for (i = 0; i < nb_sps; i++) {
guint16 sps_size =
GST_READ_UINT16_BE (GST_BUFFER_DATA (data->codec_data) + offset);
guint16 sps_size = GST_READ_UINT16_BE (codec_data.data + offset);
GST_LOG_OBJECT (mux, "Sequence Parameter Set is %d bytes", sps_size);
@ -128,24 +134,21 @@ mpegpsmux_prepare_h264 (GstBuffer * buf, MpegPsPadData * data, MpegPsMux * mux)
offset += 2;
/* Fake a start code */
memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4);
out_offset += 4;
/* Now push the SPS */
memcpy (GST_BUFFER_DATA (out_buf) + out_offset,
GST_BUFFER_DATA (data->codec_data) + offset, sps_size);
gst_byte_writer_put_uint32_be (&bw, 0x00000001);
/* Now push the SPS */
gst_byte_writer_put_data (&bw, codec_data.data + offset, sps_size);
out_offset += sps_size;
offset += sps_size;
}
nb_pps = GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset);
nb_pps = codec_data.data[offset];
GST_LOG_OBJECT (mux, "we have %d Picture Parameter Set", nb_sps);
offset++;
/* For each PPS */
for (i = 0; i < nb_pps; i++) {
gint pps_size =
GST_READ_UINT16_BE (GST_BUFFER_DATA (data->codec_data) + offset);
gint pps_size = GST_READ_UINT16_BE (codec_data.data + offset);
GST_LOG_OBJECT (mux, "Picture Parameter Set is %d bytes", pps_size);
@ -153,47 +156,52 @@ mpegpsmux_prepare_h264 (GstBuffer * buf, MpegPsPadData * data, MpegPsMux * mux)
offset += 2;
/* Fake a start code */
memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4);
out_offset += 4;
/* Now push the PPS */
memcpy (GST_BUFFER_DATA (out_buf) + out_offset,
GST_BUFFER_DATA (data->codec_data) + offset, pps_size);
gst_byte_writer_put_uint32_be (&bw, 0x00000001);
/* Now push the PPS */
gst_byte_writer_put_data (&bw, codec_data.data + offset, pps_size);
out_offset += pps_size;
offset += pps_size;
}
while (in_offset < GST_BUFFER_SIZE (buf) &&
out_offset < GST_BUFFER_SIZE (out_buf) - 4) {
gst_buffer_unmap (data->codec_data, &codec_data);
if (!gst_buffer_map (buf, &map, GST_MAP_READ))
return NULL;
/* now process NALs and change them to byte-stream format */
in_offset = 0;
while (in_offset < map.size) {
guint32 nal_size = 0;
switch (nal_length_size) {
case 1:
nal_size = GST_READ_UINT8 (GST_BUFFER_DATA (buf) + in_offset);
nal_size = GST_READ_UINT8 (map.data + in_offset);
break;
case 2:
nal_size = GST_READ_UINT16_BE (GST_BUFFER_DATA (buf) + in_offset);
nal_size = GST_READ_UINT16_BE (map.data + in_offset);
break;
case 4:
nal_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + in_offset);
nal_size = GST_READ_UINT32_BE (map.data + in_offset);
break;
default:
GST_WARNING_OBJECT (mux, "unsupported NAL length size %u",
nal_length_size);
break;
}
in_offset += nal_length_size;
/* Generate an Elementary stream buffer by inserting a startcode */
memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4);
out_offset += 4;
memcpy (GST_BUFFER_DATA (out_buf) + out_offset,
GST_BUFFER_DATA (buf) + in_offset,
MIN (nal_size, GST_BUFFER_SIZE (out_buf) - out_offset));
gst_byte_writer_put_uint32_be (&bw, 0x00000001);
gst_byte_writer_put_data (&bw, map.data + in_offset,
MIN (nal_size, map.size - in_offset));
in_offset += nal_size;
out_offset += nal_size;
}
GST_BUFFER_SIZE (out_buf) = out_offset;
out_buf = gst_byte_writer_reset_and_get_buffer (&bw);
/* We want the same metadata */
gst_buffer_copy_into (out_buf, buf, GST_BUFFER_COPY_METADATA, 0, 0);
return out_buf;
}

View file

@ -341,20 +341,19 @@ psmux_write_pack_header (PsMux * mux)
static void
psmux_ensure_system_header (PsMux * mux)
{
GstBuffer *buf;
bits_buffer_t bw;
guint len = 12 + (mux->nb_streams +
(mux->nb_private_streams > 1 ? mux->nb_private_streams - 1 : 0)) * 3;
GList *cur;
gboolean private_hit = FALSE;
guint8 *data;
if (mux->sys_header != NULL)
return;
buf = gst_buffer_new_and_alloc (len);
data = g_malloc (len);
/* system_header_start_code */
bits_initwrite (&bw, len, GST_BUFFER_DATA (buf));
bits_initwrite (&bw, len, data);
/* system_header start code */
bits_write (&bw, 24, PSMUX_START_CODE_PREFIX);
@ -374,8 +373,7 @@ psmux_ensure_system_header (PsMux * mux)
bits_write (&bw, 1, 0); /* packet_rate_restriction_flag */
bits_write (&bw, 7, 0x7f); /* reserved_bits */
for (cur = g_list_first (mux->streams), private_hit = FALSE; cur != NULL;
cur = g_list_next (cur)) {
for (cur = mux->streams, private_hit = FALSE; cur != NULL; cur = cur->next) {
PsMuxStream *stream = (PsMuxStream *) cur->data;
if (private_hit && stream->stream_id == PSMUX_EXTENDED_STREAM)
@ -390,19 +388,22 @@ psmux_ensure_system_header (PsMux * mux)
private_hit = TRUE;
}
GST_MEMDUMP ("System Header", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
GST_MEMDUMP ("System Header", data, len);
mux->sys_header = buf;
mux->sys_header = gst_buffer_new_wrapped (data, len);
}
static gboolean
psmux_write_system_header (PsMux * mux)
{
GstMapInfo map;
psmux_ensure_system_header (mux);
memcpy (mux->packet_buf, GST_BUFFER_DATA (mux->sys_header),
GST_BUFFER_SIZE (mux->sys_header));
mux->packet_bytes_written = GST_BUFFER_SIZE (mux->sys_header);
gst_buffer_map (mux->sys_header, &map, GST_MAP_READ);
memcpy (mux->packet_buf, map.data, map.size);
mux->packet_bytes_written = map.size;
gst_buffer_unmap (mux->sys_header, &map);
return psmux_packet_out (mux);
}
@ -410,19 +411,19 @@ psmux_write_system_header (PsMux * mux)
static void
psmux_ensure_program_stream_map (PsMux * mux)
{
GstBuffer *buf;
gint psm_size = 16, es_map_size = 0;
bits_buffer_t bw;
GList *cur;
guint16 len;
guint8 *pos;
guint8 *data;
if (mux->psm != NULL)
return;
/* pre-write the descriptor loop */
pos = mux->es_info_buf;
for (cur = g_list_first (mux->streams); cur != NULL; cur = g_list_next (cur)) {
for (cur = mux->streams; cur != NULL; cur = cur->next) {
PsMuxStream *stream = (PsMuxStream *) cur->data;
len = 0;
@ -442,9 +443,9 @@ psmux_ensure_program_stream_map (PsMux * mux)
psm_size += es_map_size;
buf = gst_buffer_new_and_alloc (psm_size);
data = g_malloc (psm_size);
bits_initwrite (&bw, psm_size, GST_BUFFER_DATA (buf));
bits_initwrite (&bw, psm_size, data);
/* psm start code */
bits_write (&bw, 24, PSMUX_START_CODE_PREFIX);
@ -471,20 +472,22 @@ psmux_ensure_program_stream_map (PsMux * mux)
psmux_put32 (&pos, crc);
}
GST_MEMDUMP ("Program Stream Map", GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf));
GST_MEMDUMP ("Program Stream Map", data, psm_size);
mux->psm = buf;
mux->psm = gst_buffer_new_wrapped (data, psm_size);
}
static gboolean
psmux_write_program_stream_map (PsMux * mux)
{
GstMapInfo map;
psmux_ensure_program_stream_map (mux);
memcpy (mux->packet_buf, GST_BUFFER_DATA (mux->psm),
GST_BUFFER_SIZE (mux->psm));
mux->packet_bytes_written = GST_BUFFER_SIZE (mux->psm);
gst_buffer_map (mux->psm, &map, GST_MAP_READ);
memcpy (mux->packet_buf, map.data, map.size);
mux->packet_bytes_written = map.size;
gst_buffer_unmap (mux->psm, &map);
return psmux_packet_out (mux);
}

View file

@ -174,8 +174,6 @@ psmux_stream_new (PsMux * mux, PsMuxStreamType stream_type)
stream->cur_pes_payload_size = 0;
stream->buffer_release = NULL;
stream->pts = -1;
stream->dts = -1;
stream->last_pts = -1;
@ -215,31 +213,13 @@ psmux_stream_free (PsMuxStream * stream)
g_slice_free (PsMuxStream, stream);
}
/**
* psmux_stream_set_buffer_release_func:
* @stream: a #PsMuxStream
* @func: the new #PsMuxStreamBufferReleaseFunc
*
* Set the function that will be called when a a piece of data fed to @stream
* with psmux_stream_add_data() can be freed. @func will be called with user
* data as provided with the call to psmux_stream_add_data().
*/
void
psmux_stream_set_buffer_release_func (PsMuxStream * stream,
PsMuxStreamBufferReleaseFunc func)
{
g_return_if_fail (stream != NULL);
stream->buffer_release = func;
}
/* Advance the current packet stream position by len bytes.
* Mustn't consume more than available in the current packet */
static void
psmux_stream_consume (PsMuxStream * stream, guint len)
{
g_assert (stream->cur_buffer != NULL);
g_assert (len <= stream->cur_buffer->size - stream->cur_buffer_consumed);
g_assert (len <= stream->cur_buffer->map.size - stream->cur_buffer_consumed);
stream->cur_buffer_consumed += len;
stream->bytes_avail -= len;
@ -250,15 +230,12 @@ psmux_stream_consume (PsMuxStream * stream, guint len)
if (stream->cur_buffer->pts != -1)
stream->last_pts = stream->cur_buffer->pts;
if (stream->cur_buffer_consumed == stream->cur_buffer->size) {
if (stream->cur_buffer_consumed == stream->cur_buffer->map.size) {
/* Current packet is completed, move along */
stream->buffers = g_list_delete_link (stream->buffers, stream->buffers);
if (stream->buffer_release) {
stream->buffer_release (stream->cur_buffer->data,
stream->cur_buffer->user_data);
}
gst_buffer_unmap (stream->cur_buffer->buf, &stream->cur_buffer->map);
gst_buffer_unref (stream->cur_buffer->buf);
g_slice_free (PsMuxStreamBuffer, stream->cur_buffer);
stream->cur_buffer = NULL;
}
@ -346,8 +323,8 @@ psmux_stream_get_data (PsMuxStream * stream, guint8 * buf, guint len)
}
/* Take as much as we can from the current buffer */
avail = stream->cur_buffer->size - stream->cur_buffer_consumed;
cur = stream->cur_buffer->data + stream->cur_buffer_consumed;
avail = stream->cur_buffer->map.size - stream->cur_buffer_consumed;
cur = stream->cur_buffer->map.data + stream->cur_buffer_consumed;
if (avail < w) {
memcpy (buf, cur, avail);
psmux_stream_consume (stream, avail);
@ -417,7 +394,7 @@ psmux_stream_find_pts_dts_within (PsMuxStream * stream, guint bound,
/* FIXME: This isn't quite correct - if the 'bound' is within this
* buffer, we don't know if the timestamp is before or after the split
* so we shouldn't return it */
if (bound <= curbuf->size) {
if (bound <= curbuf->map.size) {
*pts = curbuf->pts;
*dts = curbuf->dts;
return;
@ -430,7 +407,7 @@ psmux_stream_find_pts_dts_within (PsMuxStream * stream, guint bound,
return;
}
bound -= curbuf->size;
bound -= curbuf->map.size;
}
}
@ -498,9 +475,7 @@ psmux_stream_write_pes_header (PsMuxStream * stream, guint8 * data)
/**
* psmux_stream_add_data:
* @stream: a #PsMuxStream
* @data: data to add
* @len: length of @data
* @user_data: user data to pass to release func
* @buffer: (transfer full): buffer with data to add
* @pts: PTS of access unit in @data
* @dts: DTS of access unit in @data
*
@ -508,21 +483,25 @@ psmux_stream_write_pes_header (PsMuxStream * stream, guint8 * data)
* timestamp (against a 90Hz clock) of the first access unit in @data. A
* timestamp of -1 for @pts or @dts means unknown.
*
* @user_data will be passed to the release function as set with
* psmux_stream_set_buffer_release_func() when @data can be freed.
* This function takes ownership of @buffer.
*/
void
psmux_stream_add_data (PsMuxStream * stream, guint8 * data, guint len,
void *user_data, gint64 pts, gint64 dts, gboolean keyunit)
psmux_stream_add_data (PsMuxStream * stream, GstBuffer * buffer,
gint64 pts, gint64 dts, gboolean keyunit)
{
PsMuxStreamBuffer *packet;
g_return_if_fail (stream != NULL);
packet = g_slice_new (PsMuxStreamBuffer);
packet->data = data;
packet->size = len;
packet->user_data = user_data;
packet->buf = buffer;
if (!gst_buffer_map (packet->buf, &packet->map, GST_MAP_READ)) {
GST_ERROR ("Failed to map buffer for reading");
gst_buffer_unref (packet->buf);
g_slice_free (PsMuxStreamBuffer, packet);
return;
}
packet->keyunit = keyunit;
packet->pts = pts;
@ -531,7 +510,8 @@ psmux_stream_add_data (PsMuxStream * stream, guint8 * data, guint len,
if (stream->bytes_avail == 0)
stream->last_pts = pts;
stream->bytes_avail += len;
stream->bytes_avail += packet->map.size;
/* FIXME: perhaps use GstQueueArray instead? */
stream->buffers = g_list_append (stream->buffers, packet);
}

View file

@ -45,7 +45,7 @@
#ifndef __PSMUXSTREAM_H__
#define __PSMUXSTREAM_H__
#include <glib.h>
#include <gst/gst.h>
#include "psmuxcommon.h"
@ -83,16 +83,14 @@ enum PsMuxStreamType { /* Table 2-29 in spec */
struct PsMuxStreamBuffer
{
guint8 *data;
guint32 size;
gboolean keyunit;
/* PTS & DTS associated with the contents of this buffer */
GstClockTime pts;
GstClockTime dts;
void *user_data;
GstBuffer *buf;
GstMapInfo map;
};
/* PsMuxStream receives elementary streams for parsing.
@ -116,9 +114,6 @@ struct PsMuxStream{
guint16 cur_pes_payload_size;
guint16 pes_bytes_written; /* delete*/
/* Release function */
PsMuxStreamBufferReleaseFunc buffer_release;
/* PTS/DTS to write if the flags in the packet info are set */
gint64 pts; /* TODO: cur_buffer->pts?*/
gint64 dts; /* TODO: cur_buffer->dts?*/
@ -141,14 +136,11 @@ struct PsMuxStream{
PsMuxStream* psmux_stream_new (PsMux * mux, PsMuxStreamType stream_type);
void psmux_stream_free (PsMuxStream *stream);
/* The callback when a buffer is released. Used to unref the buffer in GStreamer */
void psmux_stream_set_buffer_release_func (PsMuxStream *stream,
PsMuxStreamBufferReleaseFunc func);
/* Add a new buffer to the pool of available bytes. If pts or dts are not -1, they
* indicate the PTS or DTS of the first access unit within this packet */
void psmux_stream_add_data (PsMuxStream *stream, guint8 *data, guint len,
void *user_data, gint64 pts, gint64 dts,
void psmux_stream_add_data (PsMuxStream *stream,
GstBuffer * buffer,
gint64 pts, gint64 dts,
gboolean keyunit);
/* total bytes in buffer */