asfmux: port to 0.11

This commit is contained in:
Mark Nauwelaerts 2012-04-23 16:55:18 +02:00
parent 1fa5624762
commit e79cae3002
8 changed files with 357 additions and 246 deletions

View file

@ -300,7 +300,7 @@ AG_GST_DEFAULT_ELEMENTS
dnl *** plug-ins to include ***
dnl Non ported plugins (non-dependant, then dependant)
dnl Make sure you have a space before and after all plugins
GST_PLUGINS_NONPORTED=" aiff asfmux \
GST_PLUGINS_NONPORTED=" aiff \
camerabin cdxaparse coloreffects \
dccp faceoverlay festival \
fieldanalysis freeverb freeze frei0r gaudieffects \

View file

@ -73,6 +73,7 @@
#endif
#include <string.h>
#include <stdio.h>
#include <gst/gst-i18n-plugin.h>
#include "gstasfmux.h"
@ -149,12 +150,14 @@ static GstStaticPadTemplate audio_sink_factory =
"audio/mpeg, layer = (int) 3, mpegversion = (int) 1, "
"channels = (int) [1,2], rate = (int) [8000,96000]"));
static void gst_asf_mux_base_init (gpointer g_class);
static void gst_asf_mux_class_init (GstAsfMuxClass * klass);
static void gst_asf_mux_init (GstAsfMux * asfmux);
static gboolean gst_asf_mux_audio_set_caps (GstPad * pad, GstCaps * caps);
static gboolean gst_asf_mux_video_set_caps (GstPad * pad, GstCaps * caps);
static GstPad *gst_asf_mux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name);
GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_asf_mux_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_asf_mux_get_property (GObject * object,
@ -162,7 +165,8 @@ static void gst_asf_mux_get_property (GObject * object,
static GstStateChangeReturn gst_asf_mux_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_asf_mux_sink_event (GstPad * pad, GstEvent * event);
static gboolean gst_asf_mux_sink_event (GstCollectPads * pads,
GstCollectData * cdata, GstEvent * event, GstAsfMux * asfmux);
static void gst_asf_mux_pad_reset (GstAsfPad * data);
static GstFlowReturn gst_asf_mux_collected (GstCollectPads * collect,
@ -178,7 +182,7 @@ gst_asf_mux_get_type (void)
if (!asfmux_type) {
static const GTypeInfo asfmux_info = {
sizeof (GstAsfMuxClass),
gst_asf_mux_base_init,
NULL,
NULL,
(GClassInitFunc) gst_asf_mux_class_init,
NULL,
@ -233,26 +237,6 @@ gst_asf_mux_reset (GstAsfMux * asfmux)
gst_tag_setter_reset_tags (GST_TAG_SETTER (asfmux));
}
static void
gst_asf_mux_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 (&src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&audio_sink_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&video_sink_factory));
gst_element_class_set_details_simple (element_class, "ASF muxer",
"Codec/Muxer",
"Muxes audio and video into an ASF stream",
"Thiago Santos <thiagoss@embedded.ufcg.edu.br>");
GST_DEBUG_CATEGORY_INIT (asfmux_debug, "asfmux", 0, "Muxer for ASF streams");
}
static void
gst_asf_mux_finalize (GObject * object)
{
@ -321,17 +305,26 @@ gst_asf_mux_class_init (GstAsfMuxClass * klass)
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_asf_mux_request_new_pad);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_asf_mux_change_state);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&audio_sink_factory));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&video_sink_factory));
gst_element_class_set_details_simple (gstelement_class, "ASF muxer",
"Codec/Muxer",
"Muxes audio and video into an ASF stream",
"Thiago Santos <thiagoss@embedded.ufcg.edu.br>");
GST_DEBUG_CATEGORY_INIT (asfmux_debug, "asfmux", 0, "Muxer for ASF streams");
}
static void
gst_asf_mux_init (GstAsfMux * asfmux)
{
GstCaps *caps;
asfmux->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
caps = gst_caps_copy (gst_pad_get_pad_template_caps (asfmux->srcpad));
gst_pad_set_caps (asfmux->srcpad, caps);
gst_caps_unref (caps);
gst_pad_use_fixed_caps (asfmux->srcpad);
gst_element_add_pad (GST_ELEMENT (asfmux), asfmux->srcpad);
@ -339,6 +332,9 @@ gst_asf_mux_init (GstAsfMux * asfmux)
gst_collect_pads_set_function (asfmux->collect,
(GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_asf_mux_collected),
asfmux);
gst_collect_pads_set_event_function (asfmux->collect,
(GstCollectPadsEventFunction) GST_DEBUG_FUNCPTR (gst_asf_mux_sink_event),
asfmux);
asfmux->payloads = NULL;
asfmux->prop_packet_size = DEFAULT_PACKET_SIZE;
@ -350,14 +346,26 @@ gst_asf_mux_init (GstAsfMux * asfmux)
}
static gboolean
gst_asf_mux_sink_event (GstPad * pad, GstEvent * event)
gst_asf_mux_sink_event (GstCollectPads * pads, GstCollectData * cdata,
GstEvent * event, GstAsfMux * asfmux)
{
gboolean ret;
GstAsfMux *asfmux;
GstAsfPad *asfpad = (GstAsfPad *) gst_pad_get_element_private (pad);
GstAsfPad *asfpad = (GstAsfPad *) cdata;
gboolean ret = TRUE;
asfmux = GST_ASF_MUX_CAST (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
{
GstCaps *caps;
gst_event_parse_caps (event, &caps);
if (asfpad->is_audio)
ret = gst_asf_mux_audio_set_caps (cdata->pad, caps);
else
ret = gst_asf_mux_video_set_caps (cdata->pad, caps);
gst_event_unref (event);
event = NULL;
break;
}
case GST_EVENT_TAG:{
GST_DEBUG_OBJECT (asfmux, "received tag event");
/* we discard tag events that come after we started
@ -374,7 +382,7 @@ gst_asf_mux_sink_event (GstPad * pad, GstEvent * event)
gst_tag_setter_merge_tags (setter, list, mode);
} else {
if (asfpad->taglist == NULL) {
asfpad->taglist = gst_tag_list_new ();
asfpad->taglist = gst_tag_list_new_empty ();
}
gst_tag_list_insert (asfpad->taglist, list, GST_TAG_MERGE_REPLACE);
}
@ -385,8 +393,9 @@ gst_asf_mux_sink_event (GstPad * pad, GstEvent * event)
break;
}
ret = asfmux->collect_event (pad, event);
gst_object_unref (asfmux);
if (event != NULL)
return gst_collect_pads_event_default (pads, cdata, event, FALSE);
return ret;
}
@ -403,10 +412,9 @@ static GstFlowReturn
gst_asf_mux_push_buffer (GstAsfMux * asfmux, GstBuffer * buf)
{
GstFlowReturn ret;
gst_buffer_set_caps (buf, GST_PAD_CAPS (asfmux->srcpad));
ret = gst_pad_push (asfmux->srcpad, buf);
if (ret == GST_FLOW_OK)
asfmux->file_size += GST_BUFFER_SIZE (buf);
asfmux->file_size += gst_buffer_get_size (buf);
return ret;
}
@ -505,7 +513,7 @@ gst_asf_mux_get_content_description_tags (GstAsfMux * asfmux,
if (asftags->tags != NULL) {
gst_tag_list_free (asftags->tags);
}
asftags->tags = gst_tag_list_new ();
asftags->tags = gst_tag_list_new_empty ();
asftags->cont_desc_size = 0;
asftags->ext_cont_desc_size = 0;
@ -633,7 +641,7 @@ gst_asf_mux_get_headers_size (GstAsfMux * asfmux)
size += ASF_VIDEO_SPECIFIC_DATA_SIZE;
if (asfpad->codec_data)
size += GST_BUFFER_SIZE (asfpad->codec_data);
size += gst_buffer_get_size (asfpad->codec_data);
stream_num++;
}
@ -713,7 +721,7 @@ gst_asf_mux_write_stream_properties (GstAsfMux * asfmux, guint8 ** buf,
/* codec specific data length */
if (asfpad->codec_data)
codec_data_length = GST_BUFFER_SIZE (asfpad->codec_data);
codec_data_length = gst_buffer_get_size (asfpad->codec_data);
if (asfpad->is_audio)
media_specific_data_length = ASF_AUDIO_SPECIFIC_DATA_SIZE;
else
@ -800,7 +808,7 @@ gst_asf_mux_write_stream_properties (GstAsfMux * asfmux, guint8 ** buf,
}
if (codec_data_length > 0)
memcpy (*buf, GST_BUFFER_DATA (asfpad->codec_data), codec_data_length);
gst_buffer_extract (asfpad->codec_data, 0, *buf, codec_data_length);
*buf += codec_data_length;
}
@ -1286,6 +1294,9 @@ gst_asf_mux_start_file (GstAsfMux * asfmux)
GstCaps *caps;
GstStructure *structure;
guint64 padding = asfmux->prop_padding;
GstSegment segment;
GstMapInfo map;
if (padding < ASF_PADDING_OBJECT_SIZE)
padding = 0;
@ -1293,9 +1304,13 @@ gst_asf_mux_start_file (GstAsfMux * asfmux)
GST_INFO_OBJECT (asfmux, "Writing headers");
asfmux->state = GST_ASF_MUX_STATE_HEADERS;
caps = gst_pad_get_pad_template_caps (asfmux->srcpad);
gst_pad_set_caps (asfmux->srcpad, caps);
gst_caps_unref (caps);
/* let downstream know we think in BYTES and expect to do seeking later */
gst_pad_push_event (asfmux->srcpad,
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0));
gst_segment_init (&segment, GST_FORMAT_BYTES);
gst_pad_push_event (asfmux->srcpad, gst_event_new_segment (&segment));
gst_asf_generate_file_id (&asfmux->file_id);
@ -1318,14 +1333,16 @@ gst_asf_mux_start_file (GstAsfMux * asfmux)
asftags->cont_desc_size +
asftags->ext_cont_desc_size +
metadata_obj_size + padding + ASF_DATA_OBJECT_SIZE);
bufdata = GST_BUFFER_DATA (buf);
gst_asf_mux_write_header_object (asfmux, &bufdata, GST_BUFFER_SIZE (buf) -
gst_buffer_map (buf, &map, GST_MAP_WRITE);
bufdata = map.data;
gst_asf_mux_write_header_object (asfmux, &bufdata, map.size -
ASF_DATA_OBJECT_SIZE, 2 + stream_num);
/* get the position of the file properties object for
* updating it in gst_asf_mux_stop_file */
asfmux->file_properties_object_position = bufdata - GST_BUFFER_DATA (buf);
asfmux->file_properties_object_position = bufdata - map.data;
gst_asf_mux_write_file_properties (asfmux, &bufdata);
for (walk = asfmux->collect->data; walk; walk = g_slist_next (walk)) {
@ -1361,7 +1378,7 @@ gst_asf_mux_start_file (GstAsfMux * asfmux)
gst_asf_mux_write_padding_object (asfmux, &bufdata, padding);
/* store data object position for later updating some fields */
asfmux->data_object_position = bufdata - GST_BUFFER_DATA (buf);
asfmux->data_object_position = bufdata - map.data;
gst_asf_mux_write_data_object (asfmux, &bufdata);
/* set streamheader in source pad if 'streamable' */
@ -1369,17 +1386,18 @@ gst_asf_mux_start_file (GstAsfMux * asfmux)
g_value_init (&streamheader, GST_TYPE_ARRAY);
gst_asf_mux_put_buffer_in_streamheader (&streamheader, buf);
caps = gst_caps_ref (GST_PAD_CAPS (asfmux->srcpad));
caps = gst_pad_get_current_caps (asfmux->srcpad);
caps = gst_caps_make_writable (caps);
structure = gst_caps_get_structure (caps, 0);
gst_structure_set_value (structure, "streamheader", &streamheader);
gst_pad_set_caps (asfmux->srcpad, caps);
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
g_value_unset (&streamheader);
gst_caps_unref (caps);
}
g_assert (bufdata - GST_BUFFER_DATA (buf) == GST_BUFFER_SIZE (buf));
g_assert (bufdata - map.data == map.size);
gst_buffer_unmap (buf, &map);
return gst_asf_mux_push_buffer (asfmux, buf);
}
@ -1423,11 +1441,11 @@ gst_asf_mux_add_simple_index_entry (GstAsfMux * asfmux,
static GstFlowReturn
gst_asf_mux_send_packet (GstAsfMux * asfmux, GstBuffer * buf)
{
g_assert (GST_BUFFER_SIZE (buf) == asfmux->packet_size);
g_assert (gst_buffer_get_size (buf) == asfmux->packet_size);
asfmux->total_data_packets++;
GST_LOG_OBJECT (asfmux,
"Pushing a packet of size %u and timestamp %" G_GUINT64_FORMAT,
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
gst_buffer_get_size (buf), GST_BUFFER_TIMESTAMP (buf));
GST_LOG_OBJECT (asfmux, "Total data packets: %" G_GUINT64_FORMAT,
asfmux->total_data_packets);
return gst_asf_mux_push_buffer (asfmux, buf);
@ -1457,6 +1475,7 @@ gst_asf_mux_flush_payloads (GstAsfMux * asfmux)
AsfPayload *payload;
guint32 payload_size;
guint offset;
GstMapInfo map;
if (asfmux->payloads == NULL)
return GST_FLOW_OK; /* nothing to send is ok */
@ -1464,10 +1483,11 @@ gst_asf_mux_flush_payloads (GstAsfMux * asfmux)
GST_LOG_OBJECT (asfmux, "Flushing payloads");
buf = gst_buffer_new_and_alloc (asfmux->packet_size);
memset (GST_BUFFER_DATA (buf), 0, asfmux->packet_size);
gst_buffer_map (buf, &map, GST_MAP_WRITE);
memset (map.data, 0, asfmux->packet_size);
/* 1 for the multiple payload flags */
data = GST_BUFFER_DATA (buf) + asfmux->payload_parsing_info_size + 1;
data = map.data + asfmux->payload_parsing_info_size + 1;
size_left = asfmux->packet_size - asfmux->payload_parsing_info_size - 1;
has_keyframe = FALSE;
@ -1509,7 +1529,7 @@ gst_asf_mux_flush_payloads (GstAsfMux * asfmux)
GST_DEBUG_OBJECT (asfmux, "replicated data length: %d",
(gint) payload->replicated_data_length);
GST_DEBUG_OBJECT (asfmux, "payload size: %u",
GST_BUFFER_SIZE (payload->data));
gst_buffer_get_size (payload->data));
GST_DEBUG_OBJECT (asfmux, "presentation time: %" G_GUINT32_FORMAT " (%"
GST_TIME_FORMAT ")", payload->presentation_time,
GST_TIME_ARGS (payload->presentation_time * GST_MSECOND));
@ -1554,7 +1574,8 @@ gst_asf_mux_flush_payloads (GstAsfMux * asfmux)
payload = (AsfPayload *) aux->data;
asfmux->payloads = g_slist_remove (asfmux->payloads, payload);
asfmux->payload_data_size -=
(GST_BUFFER_SIZE (payload->data) + ASF_MULTIPLE_PAYLOAD_HEADER_SIZE);
(gst_buffer_get_size (payload->data) +
ASF_MULTIPLE_PAYLOAD_HEADER_SIZE);
gst_asf_payload_free (payload);
}
@ -1586,7 +1607,7 @@ gst_asf_mux_flush_payloads (GstAsfMux * asfmux)
asfmux->payload_data_size);
/* fill payload parsing info */
data = GST_BUFFER_DATA (buf);
data = map.data;
/* flags */
GST_WRITE_UINT8 (data, (0x0 << 7) | /* no error correction */
(ASF_FIELD_TYPE_DWORD << 5) | /* packet length type */
@ -1637,11 +1658,12 @@ gst_asf_mux_flush_payloads (GstAsfMux * asfmux)
/* multiple payloads flags */
GST_WRITE_UINT8 (data + offset, 0x2 << 6 | payloads_count);
gst_buffer_unmap (buf, &map);
if (payloads_count == 0) {
GST_WARNING_OBJECT (asfmux, "Sending packet without any payload");
}
asfmux->data_object_size += GST_BUFFER_SIZE (buf);
asfmux->data_object_size += gst_buffer_get_size (buf);
if (!has_keyframe)
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
return gst_asf_mux_send_packet (asfmux, buf);
@ -1671,8 +1693,12 @@ gst_asf_mux_push_simple_index (GstAsfMux * asfmux, GstAsfVideoPad * pad)
g_slist_length (pad->simple_index) * ASF_SIMPLE_INDEX_ENTRY_SIZE;
GstBuffer *buf = gst_buffer_new_and_alloc (object_size);
GSList *walk;
guint8 *data = GST_BUFFER_DATA (buf);
guint8 *data;
guint32 entries_count = g_slist_length (pad->simple_index);
GstMapInfo map;
gst_buffer_map (buf, &map, GST_MAP_WRITE);
data = map.data;
gst_asf_put_guid (data, guids[ASF_SIMPLE_INDEX_OBJECT_INDEX]);
GST_WRITE_UINT64_LE (data + 16, object_size);
@ -1699,7 +1725,8 @@ gst_asf_mux_push_simple_index (GstAsfMux * asfmux, GstAsfVideoPad * pad)
}
GST_DEBUG_OBJECT (asfmux, "Pushing the simple index");
g_assert (data - GST_BUFFER_DATA (buf) == object_size);
g_assert (data - map.data == object_size);
gst_buffer_unmap (buf, &map);
return gst_asf_mux_push_buffer (asfmux, buf);
}
@ -1751,6 +1778,9 @@ gst_asf_mux_stop_file (GstAsfMux * asfmux)
GSList *walk;
GstClockTime play_duration = 0;
guint32 bitrate = 0;
GstSegment segment;
GstMapInfo map;
guint8 *data;
/* write indexes */
ret = gst_asf_mux_write_indexes (asfmux);
@ -1771,22 +1801,25 @@ gst_asf_mux_stop_file (GstAsfMux * asfmux)
* values we didn't know back then */
GST_DEBUG_OBJECT (asfmux,
"Sending new segment to file properties object position");
event =
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
asfmux->file_properties_object_position + 40, GST_CLOCK_TIME_NONE, 0);
gst_segment_init (&segment, GST_FORMAT_BYTES);
segment.start = segment.position =
asfmux->file_properties_object_position + 40;
event = gst_event_new_segment (&segment);
if (!gst_pad_push_event (asfmux->srcpad, event)) {
GST_ERROR_OBJECT (asfmux, "Failed to update file properties object");
return GST_FLOW_ERROR;
}
/* All file properties fields except the first 40 bytes */
buf = gst_buffer_new_and_alloc (ASF_FILE_PROPERTIES_OBJECT_SIZE - 40);
gst_buffer_map (buf, &map, GST_MAP_WRITE);
data = map.data;
GST_WRITE_UINT64_LE (GST_BUFFER_DATA (buf), asfmux->file_size);
gst_asf_put_time (GST_BUFFER_DATA (buf) + 8, gst_asf_get_current_time ());
GST_WRITE_UINT64_LE (GST_BUFFER_DATA (buf) + 16, asfmux->total_data_packets);
GST_WRITE_UINT64_LE (GST_BUFFER_DATA (buf) + 24, (play_duration / 100) +
GST_WRITE_UINT64_LE (data, asfmux->file_size);
gst_asf_put_time (data + 8, gst_asf_get_current_time ());
GST_WRITE_UINT64_LE (data + 16, asfmux->total_data_packets);
GST_WRITE_UINT64_LE (data + 24, (play_duration / 100) +
ASF_MILI_TO_100NANO (asfmux->preroll));
GST_WRITE_UINT64_LE (GST_BUFFER_DATA (buf) + 32, (play_duration / 100)); /* TODO send duration */
GST_WRITE_UINT64_LE (data + 32, (play_duration / 100)); /* TODO send duration */
/* if play duration is smaller then preroll, player might have problems */
if (asfmux->preroll > play_duration / GST_MSECOND) {
@ -1795,13 +1828,14 @@ gst_asf_mux_stop_file (GstAsfMux * asfmux)
("Preroll time larger than streams duration, "
"try setting a smaller preroll value next time"));
}
GST_WRITE_UINT64_LE (GST_BUFFER_DATA (buf) + 40, asfmux->preroll);
GST_WRITE_UINT32_LE (GST_BUFFER_DATA (buf) + 48, 0x2); /* flags - seekable */
GST_WRITE_UINT32_LE (GST_BUFFER_DATA (buf) + 52, asfmux->packet_size);
GST_WRITE_UINT32_LE (GST_BUFFER_DATA (buf) + 56, asfmux->packet_size);
GST_WRITE_UINT64_LE (data + 40, asfmux->preroll);
GST_WRITE_UINT32_LE (data + 48, 0x2); /* flags - seekable */
GST_WRITE_UINT32_LE (data + 52, asfmux->packet_size);
GST_WRITE_UINT32_LE (data + 56, asfmux->packet_size);
/* FIXME - we want the max instantaneous bitrate, for vbr streams, we can't
* get it this way, this would be the average, right? */
GST_WRITE_UINT32_LE (GST_BUFFER_DATA (buf) + 60, bitrate); /* max bitrate */
GST_WRITE_UINT32_LE (data + 60, bitrate); /* max bitrate */
gst_buffer_unmap (buf, &map);
/* we don't use gst_asf_mux_push_buffer because we are overwriting
* already sent data */
@ -1814,19 +1848,20 @@ gst_asf_mux_stop_file (GstAsfMux * asfmux)
GST_DEBUG_OBJECT (asfmux, "Seeking back to data object");
/* seek back to the data object */
event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
asfmux->data_object_position + 16, GST_CLOCK_TIME_NONE, 0);
segment.start = segment.position = asfmux->data_object_position + 16;
event = gst_event_new_segment (&segment);
if (!gst_pad_push_event (asfmux->srcpad, event)) {
GST_ERROR_OBJECT (asfmux, "Seek to update data object failed");
return GST_FLOW_ERROR;
}
buf = gst_buffer_new_and_alloc (32); /* qword+guid+qword */
GST_WRITE_UINT64_LE (GST_BUFFER_DATA (buf), asfmux->data_object_size +
ASF_DATA_OBJECT_SIZE);
gst_asf_put_guid (GST_BUFFER_DATA (buf) + 8, asfmux->file_id);
GST_WRITE_UINT64_LE (GST_BUFFER_DATA (buf) + 24, asfmux->total_data_packets);
gst_buffer_map (buf, &map, GST_MAP_WRITE);
data = map.data;
GST_WRITE_UINT64_LE (data, asfmux->data_object_size + ASF_DATA_OBJECT_SIZE);
gst_asf_put_guid (data + 8, asfmux->file_id);
GST_WRITE_UINT64_LE (data + 24, asfmux->total_data_packets);
gst_buffer_unmap (buf, &map);
return gst_pad_push (asfmux->srcpad, buf);
}
@ -1871,7 +1906,7 @@ gst_asf_mux_process_buffer (GstAsfMux * asfmux, GstAsfPad * pad,
payload->replicated_data_length = 8;
/* replicated data - 1) media object size */
payload->media_object_size = GST_BUFFER_SIZE (buf);
payload->media_object_size = gst_buffer_get_size (buf);
/* replicated data - 2) presentation time */
if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) {
GST_ERROR_OBJECT (asfmux, "Received buffer without timestamp");
@ -1896,7 +1931,7 @@ gst_asf_mux_process_buffer (GstAsfMux * asfmux, GstAsfPad * pad,
asfmux->payloads = g_slist_append (asfmux->payloads, payload);
asfmux->payload_data_size +=
GST_BUFFER_SIZE (buf) + ASF_MULTIPLE_PAYLOAD_HEADER_SIZE;
gst_buffer_get_size (buf) + ASF_MULTIPLE_PAYLOAD_HEADER_SIZE;
GST_LOG_OBJECT (asfmux, "Payload data size: %" G_GUINT32_FORMAT,
asfmux->payload_data_size);
@ -1931,7 +1966,7 @@ gst_asf_mux_collected (GstCollectPads * collect, gpointer data)
}
if (G_UNLIKELY (asfmux->state == GST_ASF_MUX_STATE_EOS))
return GST_FLOW_UNEXPECTED;
return GST_FLOW_EOS;
/* select the earliest buffer */
walk = asfmux->collect->data;
@ -1999,7 +2034,7 @@ gst_asf_mux_collected (GstCollectPads * collect, gpointer data)
}
if (ret == GST_FLOW_OK) {
gst_pad_push_event (asfmux->srcpad, gst_event_new_eos ());
ret = GST_FLOW_UNEXPECTED;
ret = GST_FLOW_EOS;
}
asfmux->state = GST_ASF_MUX_STATE_EOS;
}
@ -2201,7 +2236,7 @@ gst_asf_mux_video_set_caps (GstPad * pad, GstCaps * caps)
videopad->vidinfo.bit_cnt = 24;
/* in case we have a fourcc, we use it */
if (gst_structure_get_fourcc (structure, "format", &fourcc)) {
if (gst_structure_get_uint (structure, "format", &fourcc)) {
videopad->vidinfo.compression = fourcc;
} else {
gint version;
@ -2233,7 +2268,7 @@ refuse_caps:
static GstPad *
gst_asf_mux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * req_name)
GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
{
GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
GstAsfMux *asfmux = GST_ASF_MUX_CAST (element);
@ -2241,7 +2276,9 @@ gst_asf_mux_request_new_pad (GstElement * element,
GstAsfPad *collect_pad;
gboolean is_audio;
guint collect_size = 0;
gchar *name;
gchar *name = NULL;
const gchar *pad_name = NULL;
gint pad_id;
GST_DEBUG_OBJECT (asfmux, "Requested pad: %s", GST_STR_NULL (req_name));
@ -2251,27 +2288,37 @@ gst_asf_mux_request_new_pad (GstElement * element,
return NULL;
}
if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
name = g_strdup_printf ("audio_%02d", asfmux->stream_number + 1);
if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
/* don't mix named and unnamed pads, if the pad already exists we fail when
* trying to add it */
if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
pad_name = req_name;
} else {
name = g_strdup_printf ("audio_%u", asfmux->stream_number + 1);
pad_name = name;
}
GST_DEBUG_OBJECT (asfmux, "Adding new pad %s", name);
newpad = gst_pad_new_from_template (templ, name);
g_free (name);
newpad = gst_pad_new_from_template (templ, pad_name);
is_audio = TRUE;
gst_pad_set_setcaps_function (newpad,
GST_DEBUG_FUNCPTR (gst_asf_mux_audio_set_caps));
} else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
name = g_strdup_printf ("video_%02d", asfmux->stream_number + 1);
} else if (templ == gst_element_class_get_pad_template (klass, "video_%u")) {
/* don't mix named and unnamed pads, if the pad already exists we fail when
* trying to add it */
if (req_name != NULL && sscanf (req_name, "video_%u", &pad_id) == 1) {
pad_name = req_name;
} else {
name = g_strdup_printf ("video_%u", asfmux->stream_number + 1);
pad_name = name;
}
GST_DEBUG_OBJECT (asfmux, "Adding new pad %s", name);
newpad = gst_pad_new_from_template (templ, name);
g_free (name);
is_audio = FALSE;
gst_pad_set_setcaps_function (newpad,
GST_DEBUG_FUNCPTR (gst_asf_mux_video_set_caps));
} else {
GST_WARNING_OBJECT (asfmux, "This is not our template!");
return NULL;
}
g_free (name);
/* add pad to collections */
if (is_audio) {
collect_size = sizeof (GstAsfAudioPad);
@ -2293,14 +2340,6 @@ gst_asf_mux_request_new_pad (GstElement * element,
asfmux->stream_number += 1;
collect_pad->stream_number = asfmux->stream_number;
/* FIXME: hacked way to override/extend the event function of
* GstCollectPads; because it sets its own event function giving
* the element no access to events.
*/
asfmux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
gst_pad_set_event_function (newpad,
GST_DEBUG_FUNCPTR (gst_asf_mux_sink_event));
gst_pad_set_active (newpad, TRUE);
gst_element_add_pad (element, newpad);

View file

@ -144,7 +144,6 @@ struct _GstAsfMux
GstPad *srcpad;
GstCollectPads *collect;
GstPadEventFunction collect_event;
};
struct _GstAsfMuxClass

View file

@ -213,7 +213,7 @@ gst_asf_file_info_free (GstAsfFileInfo * info)
guint32
gst_asf_payload_get_size (AsfPayload * payload)
{
return ASF_MULTIPLE_PAYLOAD_HEADER_SIZE + GST_BUFFER_SIZE (payload->data);
return ASF_MULTIPLE_PAYLOAD_HEADER_SIZE + gst_buffer_get_size (payload->data);
}
/**
@ -338,9 +338,9 @@ gst_asf_put_payload (guint8 * buf, AsfPayload * payload)
GST_WRITE_UINT8 (buf + 6, payload->replicated_data_length);
GST_WRITE_UINT32_LE (buf + 7, payload->media_object_size);
GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time);
GST_WRITE_UINT16_LE (buf + 15, (guint16) GST_BUFFER_SIZE (payload->data));
memcpy (buf + 17, GST_BUFFER_DATA (payload->data),
GST_BUFFER_SIZE (payload->data));
GST_WRITE_UINT16_LE (buf + 15, (guint16) gst_buffer_get_size (payload->data));
gst_buffer_extract (payload->data, 0, buf + 17,
gst_buffer_get_size (payload->data));
payload->packet_count++;
}
@ -377,18 +377,15 @@ gst_asf_put_subpayload (guint8 * buf, AsfPayload * payload, guint16 size)
GST_WRITE_UINT32_LE (buf + 7, payload->media_object_size);
GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time);
size -= ASF_MULTIPLE_PAYLOAD_HEADER_SIZE;
payload_size = size < GST_BUFFER_SIZE (payload->data) ?
size : GST_BUFFER_SIZE (payload->data);
payload_size = size < gst_buffer_get_size (payload->data) ?
size : gst_buffer_get_size (payload->data);
GST_WRITE_UINT16_LE (buf + 15, payload_size);
memcpy (buf + 17, GST_BUFFER_DATA (payload->data), payload_size);
gst_buffer_extract (payload->data, 0, buf + 17, payload_size);
/* updates the payload to the remaining data */
payload->offset_in_media_obj += payload_size;
newbuf = gst_buffer_create_sub (payload->data, payload_size,
GST_BUFFER_SIZE (payload->data) - payload_size);
payload->data = gst_buffer_make_metadata_writable (payload->data);
gst_buffer_copy_metadata (payload->data, newbuf, GST_BUFFER_COPY_FLAGS |
GST_BUFFER_COPY_CAPS);
newbuf = gst_buffer_copy_region (payload->data, GST_BUFFER_COPY_ALL,
payload_size, gst_buffer_get_size (payload->data) - payload_size);
GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (payload->data);
gst_buffer_unref (payload->data);
payload->data = newbuf;
@ -424,6 +421,33 @@ gst_asf_match_and_peek_obj_size (const guint8 * data, const Guid * guid)
return GST_READ_UINT64_LE (data + ASF_GUID_SIZE);
}
/**
* gst_asf_match_and_peek_obj_size_buf:
* @buf: buffer to be peeked at
* @guid: pointer to a guid
*
* Compares the first bytes of buf against the guid parameter and
* if they match gets the object size (that are right after the guid in
* asf objects).
*
* In case the guids don't match, 0 is returned.
* If the guid is NULL the match is assumed to be true.
*
* Returns: The size of the object in case the guid matches, 0 otherwise
*/
guint64
gst_asf_match_and_peek_obj_size_buf (GstBuffer * buf, const Guid * guid)
{
GstMapInfo map;
guint64 res;
gst_buffer_map (buf, &map, GST_MAP_READ);
res = gst_asf_match_and_peek_obj_size (map.data, guid);
gst_buffer_unmap (buf, &map);
return res;
}
/**
* gst_asf_parse_mult_payload:
* @reader: a #GstByteReader ready to read the multiple payload data
@ -539,15 +563,17 @@ gst_asf_parse_packet (GstBuffer * buffer, GstAsfPacketInfo * packet,
guint32 send_time = 0;
guint16 duration = 0;
gboolean has_keyframe;
GstMapInfo map;
if (packet_size != 0 && GST_BUFFER_SIZE (buffer) != packet_size) {
if (packet_size != 0 && gst_buffer_get_size (buffer) != packet_size) {
GST_WARNING ("ASF packets should be aligned with buffers");
return FALSE;
}
reader = gst_byte_reader_new_from_buffer (buffer);
gst_buffer_map (buffer, &map, GST_MAP_READ);
reader = gst_byte_reader_new (map.data, map.size);
GST_LOG ("Starting packet parsing, size: %u", GST_BUFFER_SIZE (buffer));
GST_LOG ("Starting packet parsing, size: %u", gst_buffer_get_size (buffer));
if (!gst_byte_reader_get_uint8 (reader, &first))
goto error;
@ -673,6 +699,7 @@ gst_asf_parse_packet (GstBuffer * buffer, GstAsfPacketInfo * packet,
packet->seq_field_type = seq_len_type;
packet->err_cor_len = err_length;
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader);
return ret;
@ -680,6 +707,7 @@ error:
ret = FALSE;
GST_WARNING ("Error while parsing data packet");
end:
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader);
return ret;
}
@ -738,16 +766,20 @@ gst_asf_parse_headers (GstBuffer * buffer, GstAsfFileInfo * file_info)
guint32 i;
GstByteReader *reader;
guint64 object_size;
GstMapInfo map;
object_size = gst_asf_match_and_peek_obj_size (GST_BUFFER_DATA (buffer),
gst_buffer_map (buffer, &map, GST_MAP_READ);
object_size = gst_asf_match_and_peek_obj_size (map.data,
&(guids[ASF_HEADER_OBJECT_INDEX]));
if (object_size == 0) {
GST_WARNING ("ASF: Cannot parse, header guid not found at the beginning "
" of data");
gst_buffer_unmap (buffer, &map);
return FALSE;
}
reader = gst_byte_reader_new_from_buffer (buffer);
reader = gst_byte_reader_new (map.data, map.size);
if (!gst_byte_reader_skip (reader, ASF_GUID_OBJSIZE_SIZE))
goto error;
@ -785,6 +817,7 @@ error:
ret = FALSE;
GST_WARNING ("ASF: Error while parsing headers");
end:
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader);
return ret;
}

View file

@ -112,6 +112,8 @@ gboolean gst_asf_parse_packet (GstBuffer * buffer, GstAsfPacketInfo * packet,
gboolean trust_delta_flag, guint packet_size);
guint64 gst_asf_match_and_peek_obj_size (const guint8 * data,
const Guid * guid);
guint64 gst_asf_match_and_peek_obj_size_buf (GstBuffer * buf,
const Guid * guid);
gboolean gst_asf_parse_headers (GstBuffer * buffer, GstAsfFileInfo * file_info);
/* ASF tags

View file

@ -46,7 +46,8 @@ static GstStateChangeReturn gst_asf_parse_change_state (GstElement * element,
GstStateChange transition);
static void gst_asf_parse_loop (GstPad * pad);
GST_BOILERPLATE (GstAsfParse, gst_asf_parse, GstElement, GST_TYPE_ELEMENT);
#define gst_asf_parse_parent_class parent_class
G_DEFINE_TYPE (GstAsfParse, gst_asf_parse, GST_TYPE_ELEMENT);
static void
gst_asf_parse_reset (GstAsfParse * asfparse)
@ -61,29 +62,62 @@ gst_asf_parse_reset (GstAsfParse * asfparse)
}
static gboolean
gst_asf_parse_sink_activate (GstPad * pad)
gst_asf_parse_sink_activate (GstPad * sinkpad, GstObject * parent)
{
if (gst_pad_check_pull_range (pad)) {
return gst_pad_activate_pull (pad, TRUE);
} else {
return gst_pad_activate_push (pad, TRUE);
GstQuery *query;
gboolean pull_mode;
query = gst_query_new_scheduling ();
if (!gst_pad_peer_query (sinkpad, query)) {
gst_query_unref (query);
goto activate_push;
}
pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
gst_query_unref (query);
if (!pull_mode)
goto activate_push;
GST_DEBUG_OBJECT (sinkpad, "activating pull");
return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
activate_push:
{
GST_DEBUG_OBJECT (sinkpad, "activating push");
return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
}
}
static gboolean
gst_asf_parse_sink_activate_pull (GstPad * pad, gboolean active)
gst_asf_parse_sink_activate_mode (GstPad * pad, GstObject * parent,
GstPadMode mode, gboolean active)
{
if (active) {
return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_parse_loop, pad);
} else {
return gst_pad_stop_task (pad);
gboolean res;
switch (mode) {
case GST_PAD_MODE_PULL:
if (active) {
res =
gst_pad_start_task (pad, (GstTaskFunction) gst_asf_parse_loop, pad);
} else {
res = gst_pad_stop_task (pad);
}
case GST_PAD_MODE_PUSH:
res = TRUE;
break;
default:
res = FALSE;
break;
}
return res;
}
static GstFlowReturn
gst_asf_parse_push (GstAsfParse * asfparse, GstBuffer * buf)
{
gst_buffer_set_caps (buf, asfparse->outcaps);
return gst_pad_push (asfparse->srcpad, buf);
}
@ -93,10 +127,12 @@ gst_asf_parse_parse_data_object (GstAsfParse * asfparse, GstBuffer * buffer)
GstByteReader *reader;
GstFlowReturn ret = GST_FLOW_OK;
guint64 packet_count = 0;
GstMapInfo map;
GST_DEBUG_OBJECT (asfparse, "Parsing data object");
reader = gst_byte_reader_new_from_buffer (buffer);
gst_buffer_map (buffer, &map, GST_MAP_READ);
reader = gst_byte_reader_new (map.data, map.size);
/* skip to packet count */
if (!gst_byte_reader_skip (reader, 40))
goto error;
@ -112,12 +148,14 @@ gst_asf_parse_parse_data_object (GstAsfParse * asfparse, GstBuffer * buffer)
packet_count);
}
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader);
return gst_asf_parse_push (asfparse, buffer);
error:
ret = GST_FLOW_ERROR;
GST_ERROR_OBJECT (asfparse, "Error while parsing data object headers");
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader);
return ret;
}
@ -161,6 +199,7 @@ gst_asf_parse_pull_headers (GstAsfParse * asfparse)
GstBuffer *headers = NULL;
guint64 size;
GstFlowReturn ret;
GstMapInfo map;
if ((ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset,
ASF_GUID_OBJSIZE_SIZE, &guid_and_size)) != GST_FLOW_OK) {
@ -168,8 +207,10 @@ gst_asf_parse_pull_headers (GstAsfParse * asfparse)
goto leave;
}
asfparse->offset += ASF_GUID_OBJSIZE_SIZE;
size = gst_asf_match_and_peek_obj_size (GST_BUFFER_DATA (guid_and_size),
gst_buffer_map (guid_and_size, &map, GST_MAP_READ);
size = gst_asf_match_and_peek_obj_size (map.data,
&(guids[ASF_HEADER_OBJECT_INDEX]));
gst_buffer_unmap (guid_and_size, &map);
if (size == 0) {
GST_ERROR_OBJECT (asfparse, "ASF starting identifier missing");
@ -209,7 +250,7 @@ gst_asf_parse_pull_data_header (GstAsfParse * asfparse)
return ret;
}
asfparse->offset += ASF_DATA_OBJECT_SIZE;
asfparse->data_size = gst_asf_match_and_peek_obj_size (GST_BUFFER_DATA (buf),
asfparse->data_size = gst_asf_match_and_peek_obj_size_buf (buf,
&(guids[ASF_DATA_OBJECT_INDEX]));
if (asfparse->data_size == 0) {
GST_ERROR_OBJECT (asfparse, "Unexpected object, was expecting data object");
@ -262,8 +303,7 @@ gst_asf_parse_pull_indexes (GstAsfParse * asfparse)
if (ret != GST_FLOW_OK)
break;
/* we can peek at the object size */
obj_size =
gst_asf_match_and_peek_obj_size (GST_BUFFER_DATA (guid_and_size), NULL);
obj_size = gst_asf_match_and_peek_obj_size_buf (guid_and_size, NULL);
if (obj_size == 0) {
GST_ERROR_OBJECT (asfparse, "Incomplete object found");
gst_buffer_unref (guid_and_size);
@ -346,9 +386,9 @@ pause:
GST_INFO_OBJECT (asfparse, "Pausing sinkpad task");
gst_pad_pause_task (pad);
if (ret == GST_FLOW_UNEXPECTED) {
if (ret == GST_FLOW_EOS) {
gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ());
} else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
} else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
GST_ELEMENT_ERROR (asfparse, STREAM, FAILED,
(NULL), ("streaming task paused, reason %s (%d)", reason, ret));
gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ());
@ -357,12 +397,12 @@ pause:
}
static GstFlowReturn
gst_asf_parse_chain (GstPad * pad, GstBuffer * buffer)
gst_asf_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
GstAsfParse *asfparse;
GstFlowReturn ret = GST_FLOW_OK;
asfparse = GST_ASF_PARSE (GST_PAD_PARENT (pad));
asfparse = GST_ASF_PARSE (parent);
gst_adapter_push (asfparse->adapter, buffer);
switch (asfparse->parse_state) {
@ -372,9 +412,10 @@ gst_asf_parse_chain (GstPad * pad, GstBuffer * buffer)
/* we can peek at the object size */
asfparse->headers_size =
gst_asf_match_and_peek_obj_size (gst_adapter_peek
gst_asf_match_and_peek_obj_size (gst_adapter_map
(asfparse->adapter, ASF_GUID_OBJSIZE_SIZE),
&(guids[ASF_HEADER_OBJECT_INDEX]));
gst_adapter_unmap (asfparse->adapter);
if (asfparse->headers_size == 0) {
/* something is wrong, this probably ain't an ASF stream */
@ -401,9 +442,10 @@ gst_asf_parse_chain (GstPad * pad, GstBuffer * buffer)
/* we can peek at the object size */
asfparse->data_size =
gst_asf_match_and_peek_obj_size (gst_adapter_peek
gst_asf_match_and_peek_obj_size (gst_adapter_map
(asfparse->adapter, ASF_GUID_OBJSIZE_SIZE),
&(guids[ASF_DATA_OBJECT_INDEX]));
gst_adapter_unmap (asfparse->adapter);
if (asfparse->data_size == 0) {
/* something is wrong */
@ -447,8 +489,9 @@ gst_asf_parse_chain (GstPad * pad, GstBuffer * buffer)
if (gst_adapter_available (asfparse->adapter) >= ASF_GUID_OBJSIZE_SIZE) {
guint64 obj_size;
/* we can peek at the object size */
obj_size = gst_asf_match_and_peek_obj_size (gst_adapter_peek
obj_size = gst_asf_match_and_peek_obj_size (gst_adapter_map
(asfparse->adapter, ASF_GUID_OBJSIZE_SIZE), NULL);
gst_adapter_unmap (asfparse->adapter);
if (gst_adapter_available (asfparse->adapter) >= obj_size) {
GST_DEBUG_OBJECT (asfparse, "Skiping object");
ret = gst_asf_parse_push (asfparse,
@ -467,23 +510,6 @@ end:
return ret;
}
static void
gst_asf_parse_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 (&src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details_simple (element_class, "ASF parser",
"Parser", "Parses ASF", "Thiago Santos <thiagoss@embedded.ufcg.edu.br>");
GST_DEBUG_CATEGORY_INIT (asfparse_debug, "asfparse", 0,
"Parser for ASF streams");
}
static void
gst_asf_parse_finalize (GObject * object)
{
@ -511,17 +537,28 @@ gst_asf_parse_class_init (GstAsfParseClass * klass)
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_asf_parse_change_state);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&src_factory));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details_simple (gstelement_class, "ASF parser",
"Parser", "Parses ASF", "Thiago Santos <thiagoss@embedded.ufcg.edu.br>");
GST_DEBUG_CATEGORY_INIT (asfparse_debug, "asfparse", 0,
"Parser for ASF streams");
}
static void
gst_asf_parse_init (GstAsfParse * asfparse, GstAsfParseClass * klass)
gst_asf_parse_init (GstAsfParse * asfparse)
{
asfparse->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
gst_pad_set_chain_function (asfparse->sinkpad, gst_asf_parse_chain);
gst_pad_set_activate_function (asfparse->sinkpad,
gst_asf_parse_sink_activate);
gst_pad_set_activatepull_function (asfparse->sinkpad,
gst_asf_parse_sink_activate_pull);
gst_pad_set_activatemode_function (asfparse->sinkpad,
gst_asf_parse_sink_activate_mode);
gst_element_add_pad (GST_ELEMENT (asfparse), asfparse->sinkpad);
asfparse->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
@ -529,7 +566,7 @@ gst_asf_parse_init (GstAsfParse * asfparse, GstAsfParseClass * klass)
gst_element_add_pad (GST_ELEMENT (asfparse), asfparse->srcpad);
asfparse->adapter = gst_adapter_new ();
asfparse->outcaps = gst_caps_new_simple ("video/x-ms-asf", NULL);
asfparse->outcaps = gst_caps_new_empty_simple ("video/x-ms-asf");
asfparse->asfinfo = gst_asf_file_info_new ();
asfparse->packetinfo = g_new0 (GstAsfPacketInfo, 1);
gst_asf_parse_reset (asfparse);

View file

@ -51,15 +51,15 @@ GST_STATIC_PAD_TEMPLATE ("src",
);
static GstFlowReturn
gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer);
gst_rtp_asf_pay_handle_buffer (GstRTPBasePayload * rtppay, GstBuffer * buffer);
static gboolean
gst_rtp_asf_pay_set_caps (GstBaseRTPPayload * rtppay, GstCaps * caps);
gst_rtp_asf_pay_set_caps (GstRTPBasePayload * rtppay, GstCaps * caps);
GST_BOILERPLATE (GstRtpAsfPay, gst_rtp_asf_pay, GstBaseRTPPayload,
GST_TYPE_BASE_RTP_PAYLOAD);
#define gst_rtp_asf_pay_parent_class parent_class
G_DEFINE_TYPE (GstRtpAsfPay, gst_rtp_asf_pay, GST_TYPE_RTP_BASE_PAYLOAD);
static void
gst_rtp_asf_pay_init (GstRtpAsfPay * rtpasfpay, GstRtpAsfPayClass * klass)
gst_rtp_asf_pay_init (GstRtpAsfPay * rtpasfpay)
{
rtpasfpay->first_ts = 0;
rtpasfpay->config = NULL;
@ -80,44 +80,40 @@ gst_rtp_asf_pay_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_rtp_asf_pay_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_rtp_asf_pay_sink_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_rtp_asf_pay_src_template));
gst_element_class_set_details_simple (element_class, "RTP ASF payloader",
"Codec/Payloader/Network",
"Payload-encodes ASF into RTP packets (MS_RTSP)",
"Thiago Santos <thiagoss@embedded.ufcg.edu.br>");
}
static void
gst_rtp_asf_pay_class_init (GstRtpAsfPayClass * klass)
{
GObjectClass *gobject_class;
GstBaseRTPPayloadClass *gstbasertppayload_class;
GstElementClass *gstelement_class;
GstRTPBasePayloadClass *gstbasertppayload_class;
gobject_class = (GObjectClass *) klass;
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasertppayload_class = (GstRTPBasePayloadClass *) klass;
gobject_class->finalize = gst_rtp_asf_pay_finalize;
gstbasertppayload_class->handle_buffer = gst_rtp_asf_pay_handle_buffer;
gstbasertppayload_class->set_caps = gst_rtp_asf_pay_set_caps;
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_rtp_asf_pay_sink_template));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_rtp_asf_pay_src_template));
gst_element_class_set_details_simple (gstelement_class, "RTP ASF payloader",
"Codec/Payloader/Network",
"Payload-encodes ASF into RTP packets (MS_RTSP)",
"Thiago Santos <thiagoss@embedded.ufcg.edu.br>");
GST_DEBUG_CATEGORY_INIT (rtpasfpay_debug, "rtpasfpay", 0,
"ASF RTP Payloader");
}
static gboolean
gst_rtp_asf_pay_set_caps (GstBaseRTPPayload * rtppay, GstCaps * caps)
gst_rtp_asf_pay_set_caps (GstRTPBasePayload * rtppay, GstCaps * caps)
{
/* FIXME change application for the actual content */
gst_basertppayload_set_options (rtppay, "application", TRUE, "X-ASF-PF",
gst_rtp_base_payload_set_options (rtppay, "application", TRUE, "X-ASF-PF",
1000);
return TRUE;
}
@ -125,7 +121,7 @@ gst_rtp_asf_pay_set_caps (GstBaseRTPPayload * rtppay, GstCaps * caps)
static GstFlowReturn
gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
{
GstBaseRTPPayload *rtppay;
GstRTPBasePayload *rtppay;
GstAsfPacketInfo *packetinfo;
guint8 flags;
guint8 *data;
@ -134,7 +130,7 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
guint32 size_left;
GstFlowReturn ret = GST_FLOW_OK;
rtppay = GST_BASE_RTP_PAYLOAD (rtpasfpay);
rtppay = GST_RTP_BASE_PAYLOAD (rtpasfpay);
packetinfo = &rtpasfpay->packetinfo;
if (!gst_asf_parse_packet (buffer, packetinfo, TRUE,
@ -161,13 +157,13 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
buffer = gst_buffer_make_writable (buffer);
switch (packetinfo->padd_field_type) {
case ASF_FIELD_TYPE_DWORD:
GST_WRITE_UINT32_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0);
gst_buffer_memset (buffer, offset, 0, 4);
break;
case ASF_FIELD_TYPE_WORD:
GST_WRITE_UINT16_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0);
gst_buffer_memset (buffer, offset, 0, 2);
break;
case ASF_FIELD_TYPE_BYTE:
GST_BUFFER_DATA (buffer)[offset] = 0;
gst_buffer_memset (buffer, offset, 0, 1);
break;
case ASF_FIELD_TYPE_NONE:
default:
@ -189,23 +185,26 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
* This flag tells us to push the packet.
*/
gboolean force_push = FALSE;
GstRTPBuffer rtp;
/* we have no output buffer pending, create one */
if (rtpasfpay->current == NULL) {
GST_LOG_OBJECT (rtpasfpay, "Creating new output buffer");
rtpasfpay->current =
gst_rtp_buffer_new_allocate_len (GST_BASE_RTP_PAYLOAD_MTU (rtpasfpay),
gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU (rtpasfpay),
0, 0);
rtpasfpay->cur_off = gst_rtp_buffer_get_header_len (rtpasfpay->current);
rtpasfpay->cur_off = 0;
rtpasfpay->has_ts = FALSE;
rtpasfpay->marker = FALSE;
}
data = GST_BUFFER_DATA (rtpasfpay->current) + rtpasfpay->cur_off;
size_left = GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off;
gst_rtp_buffer_map (rtpasfpay->current, GST_MAP_READWRITE, &rtp);
data = gst_rtp_buffer_get_payload (&rtp);
data += rtpasfpay->cur_off;
size_left = gst_rtp_buffer_get_payload_len (&rtp) - rtpasfpay->cur_off;
GST_DEBUG_OBJECT (rtpasfpay, "Input buffer bytes consumed: %"
G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, packet_offset,
GST_BUFFER_SIZE (buffer));
gst_buffer_get_size (buffer));
GST_DEBUG_OBJECT (rtpasfpay, "Output rtpbuffer status");
GST_DEBUG_OBJECT (rtpasfpay, "Current offset: %" G_GUINT32_FORMAT,
@ -230,8 +229,7 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
rtpasfpay->ts = packetinfo->send_time;
}
if (GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off >=
packet_util_size + 8) {
if (size_left >= packet_util_size + 8) {
/* enough space for the rest of the packet */
if (packet_offset == 0) {
flags = flags | 0x40;
@ -243,8 +241,7 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
data[0] = flags;
GST_WRITE_UINT32_BE (data + 4,
(gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset,
packet_util_size);
gst_buffer_extract (buffer, packet_offset, data + 8, packet_util_size);
/* updating status variables */
rtpasfpay->cur_off += 8 + packet_util_size;
@ -258,8 +255,7 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
GST_WRITE_UINT24_BE (data + 1, packet_offset);
GST_WRITE_UINT32_BE (data + 4,
(gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset,
size_left - 8);
gst_buffer_extract (buffer, packet_offset, data + 8, size_left - 8);
/* updating status variables */
rtpasfpay->cur_off += size_left;
@ -272,31 +268,27 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
/* there is not enough room for any more buffers */
if (force_push || size_left <= 8) {
gst_rtp_buffer_set_ssrc (&rtp, rtppay->current_ssrc);
gst_rtp_buffer_set_marker (&rtp, rtpasfpay->marker);
gst_rtp_buffer_set_payload_type (&rtp, GST_RTP_BASE_PAYLOAD_PT (rtppay));
gst_rtp_buffer_set_seq (&rtp, rtppay->seqnum + 1);
gst_rtp_buffer_set_timestamp (&rtp, packetinfo->send_time);
gst_rtp_buffer_unmap (&rtp);
/* trim remaining bytes not used */
if (size_left != 0) {
/* trim remaining bytes not used */
GstBuffer *aux = gst_buffer_create_sub (rtpasfpay->current, 0,
GST_BUFFER_SIZE (rtpasfpay->current) - size_left);
gst_buffer_unref (rtpasfpay->current);
rtpasfpay->current = aux;
gst_buffer_set_size (rtpasfpay->current,
gst_buffer_get_size (rtpasfpay->current) - size_left);
}
gst_rtp_buffer_set_ssrc (rtpasfpay->current, rtppay->current_ssrc);
gst_rtp_buffer_set_marker (rtpasfpay->current, rtpasfpay->marker);
gst_rtp_buffer_set_payload_type (rtpasfpay->current,
GST_BASE_RTP_PAYLOAD_PT (rtppay));
gst_rtp_buffer_set_seq (rtpasfpay->current, rtppay->seqnum + 1);
gst_rtp_buffer_set_timestamp (rtpasfpay->current, packetinfo->send_time);
GST_BUFFER_TIMESTAMP (rtpasfpay->current) = GST_BUFFER_TIMESTAMP (buffer);
gst_buffer_set_caps (rtpasfpay->current,
GST_PAD_CAPS (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay)));
rtppay->seqnum++;
rtppay->timestamp = packetinfo->send_time;
GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer");
ret =
gst_pad_push (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay),
gst_pad_push (GST_RTP_BASE_PAYLOAD_SRCPAD (rtppay),
rtpasfpay->current);
rtpasfpay->current = NULL;
if (ret != GST_FLOW_OK) {
@ -313,6 +305,8 @@ static GstFlowReturn
gst_rtp_asf_pay_parse_headers (GstRtpAsfPay * rtpasfpay)
{
gchar *maxps;
GstMapInfo map;
g_return_val_if_fail (rtpasfpay->headers, GST_FLOW_ERROR);
if (!gst_asf_parse_headers (rtpasfpay->headers, &rtpasfpay->asfinfo))
@ -327,8 +321,9 @@ gst_rtp_asf_pay_parse_headers (GstRtpAsfPay * rtpasfpay)
/* get the config for caps */
g_free (rtpasfpay->config);
rtpasfpay->config = g_base64_encode (GST_BUFFER_DATA (rtpasfpay->headers),
GST_BUFFER_SIZE (rtpasfpay->headers));
gst_buffer_map (rtpasfpay->headers, &map, GST_MAP_READ);
rtpasfpay->config = g_base64_encode (map.data, map.size);
gst_buffer_unmap (rtpasfpay->headers, &map);
GST_DEBUG_OBJECT (rtpasfpay, "Serialized headers to base64 string %s",
rtpasfpay->config);
@ -338,7 +333,7 @@ gst_rtp_asf_pay_parse_headers (GstRtpAsfPay * rtpasfpay)
rtpasfpay->config);
maxps =
g_strdup_printf ("%" G_GUINT32_FORMAT, rtpasfpay->asfinfo.packet_size);
gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpasfpay), "maxps",
gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpasfpay), "maxps",
G_TYPE_STRING, maxps, "config", G_TYPE_STRING, rtpasfpay->config, NULL);
g_free (maxps);
@ -353,7 +348,7 @@ error:
}
static GstFlowReturn
gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer)
gst_rtp_asf_pay_handle_buffer (GstRTPBasePayload * rtppay, GstBuffer * buffer)
{
GstRtpAsfPay *rtpasfpay = GST_RTP_ASF_PAY_CAST (rtppay);
@ -361,7 +356,7 @@ gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer)
GST_LOG_OBJECT (rtpasfpay,
"Dropping buffer as we already pushed all packets");
gst_buffer_unref (buffer);
return GST_FLOW_UNEXPECTED; /* we already finished our job */
return GST_FLOW_EOS; /* we already finished our job */
}
/* receive headers
@ -369,20 +364,20 @@ gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer)
if (G_UNLIKELY (rtpasfpay->state == ASF_NOT_STARTED)) {
guint64 header_size;
if (GST_BUFFER_SIZE (buffer) < 24) { /* guid+object size size */
if (gst_buffer_get_size (buffer) < 24) { /* guid+object size size */
GST_ERROR_OBJECT (rtpasfpay,
"Buffer too small, smaller than a Guid and object size");
gst_buffer_unref (buffer);
return GST_FLOW_ERROR;
}
header_size = gst_asf_match_and_peek_obj_size (GST_BUFFER_DATA (buffer),
header_size = gst_asf_match_and_peek_obj_size_buf (buffer,
&(guids[ASF_HEADER_OBJECT_INDEX]));
if (header_size > 0) {
GST_DEBUG_OBJECT (rtpasfpay, "ASF header guid received, size %"
G_GUINT64_FORMAT, header_size);
if (GST_BUFFER_SIZE (buffer) < header_size) {
if (gst_buffer_get_size (buffer) < header_size) {
GST_ERROR_OBJECT (rtpasfpay, "Headers should be contained in a single"
" buffer");
gst_buffer_unref (buffer);
@ -396,14 +391,16 @@ gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer)
}
GST_DEBUG_OBJECT (rtpasfpay, "Storing headers");
if (GST_BUFFER_SIZE (buffer) == header_size) {
if (gst_buffer_get_size (buffer) == header_size) {
rtpasfpay->headers = buffer;
return GST_FLOW_OK;
} else {
/* headers are a subbuffer of thie buffer */
GstBuffer *aux = gst_buffer_create_sub (buffer, header_size,
GST_BUFFER_SIZE (buffer) - header_size);
rtpasfpay->headers = gst_buffer_create_sub (buffer, 0, header_size);
GstBuffer *aux = gst_buffer_copy_region (buffer,
GST_BUFFER_COPY_ALL, header_size,
gst_buffer_get_size (buffer) - header_size);
rtpasfpay->headers = gst_buffer_copy_region (buffer,
GST_BUFFER_COPY_ALL, 0, header_size);
gst_buffer_replace (&buffer, aux);
}
}
@ -415,21 +412,25 @@ gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer)
}
if (G_UNLIKELY (rtpasfpay->state == ASF_DATA_OBJECT)) {
if (GST_BUFFER_SIZE (buffer) != ASF_DATA_OBJECT_SIZE) {
GstMapInfo map;
if (gst_buffer_get_size (buffer) != ASF_DATA_OBJECT_SIZE) {
GST_ERROR_OBJECT (rtpasfpay, "Received buffer of different size of "
"the data object header");
gst_buffer_unref (buffer);
return GST_FLOW_ERROR;
}
if (gst_asf_match_guid (GST_BUFFER_DATA (buffer),
&(guids[ASF_DATA_OBJECT_INDEX]))) {
gst_buffer_map (buffer, &map, GST_MAP_READ);
if (gst_asf_match_guid (map.data, &(guids[ASF_DATA_OBJECT_INDEX]))) {
gst_buffer_unmap (buffer, &map);
GST_DEBUG_OBJECT (rtpasfpay, "Received data object header");
rtpasfpay->headers = gst_buffer_append (rtpasfpay->headers, buffer);
rtpasfpay->state = ASF_PACKETS;
return gst_rtp_asf_pay_parse_headers (rtpasfpay);
} else {
gst_buffer_unmap (buffer, &map);
GST_ERROR_OBJECT (rtpasfpay, "Unexpected object received (was expecting "
"data object)");
gst_buffer_unref (buffer);
@ -454,7 +455,7 @@ gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer)
GST_INFO_OBJECT (rtpasfpay, "Packets ended");
rtpasfpay->state = ASF_END;
gst_buffer_unref (buffer);
return GST_FLOW_UNEXPECTED;
return GST_FLOW_EOS;
}
}

View file

@ -22,7 +22,7 @@
#define __GST_RTP_ASF_PAY_H__
#include <gst/gst.h>
#include <gst/rtp/gstbasertppayload.h>
#include <gst/rtp/gstrtpbasepayload.h>
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/base/gstadapter.h>
@ -53,7 +53,7 @@ typedef struct _GstRtpAsfPayClass GstRtpAsfPayClass;
struct _GstRtpAsfPay
{
GstBaseRTPPayload rtppay;
GstRTPBasePayload rtppay;
enum GstRtpAsfPayState state;
@ -77,7 +77,7 @@ struct _GstRtpAsfPay
struct _GstRtpAsfPayClass
{
GstBaseRTPPayloadClass parent_class;
GstRTPBasePayloadClass parent_class;
};
GType gst_rtp_asf_pay_get_type (void);