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

View file

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

View file

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

View file

@ -213,7 +213,7 @@ gst_asf_file_info_free (GstAsfFileInfo * info)
guint32 guint32
gst_asf_payload_get_size (AsfPayload * payload) 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_UINT8 (buf + 6, payload->replicated_data_length);
GST_WRITE_UINT32_LE (buf + 7, payload->media_object_size); GST_WRITE_UINT32_LE (buf + 7, payload->media_object_size);
GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time); GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time);
GST_WRITE_UINT16_LE (buf + 15, (guint16) GST_BUFFER_SIZE (payload->data)); GST_WRITE_UINT16_LE (buf + 15, (guint16) gst_buffer_get_size (payload->data));
memcpy (buf + 17, GST_BUFFER_DATA (payload->data), gst_buffer_extract (payload->data, 0, buf + 17,
GST_BUFFER_SIZE (payload->data)); gst_buffer_get_size (payload->data));
payload->packet_count++; 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 + 7, payload->media_object_size);
GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time); GST_WRITE_UINT32_LE (buf + 11, payload->presentation_time);
size -= ASF_MULTIPLE_PAYLOAD_HEADER_SIZE; size -= ASF_MULTIPLE_PAYLOAD_HEADER_SIZE;
payload_size = size < GST_BUFFER_SIZE (payload->data) ? payload_size = size < gst_buffer_get_size (payload->data) ?
size : GST_BUFFER_SIZE (payload->data); size : gst_buffer_get_size (payload->data);
GST_WRITE_UINT16_LE (buf + 15, payload_size); 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 */ /* updates the payload to the remaining data */
payload->offset_in_media_obj += payload_size; payload->offset_in_media_obj += payload_size;
newbuf = gst_buffer_create_sub (payload->data, payload_size, newbuf = gst_buffer_copy_region (payload->data, GST_BUFFER_COPY_ALL,
GST_BUFFER_SIZE (payload->data) - payload_size); payload_size, gst_buffer_get_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);
GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (payload->data); GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (payload->data);
gst_buffer_unref (payload->data); gst_buffer_unref (payload->data);
payload->data = newbuf; 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); 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: * gst_asf_parse_mult_payload:
* @reader: a #GstByteReader ready to read the multiple payload data * @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; guint32 send_time = 0;
guint16 duration = 0; guint16 duration = 0;
gboolean has_keyframe; 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"); GST_WARNING ("ASF packets should be aligned with buffers");
return FALSE; 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)) if (!gst_byte_reader_get_uint8 (reader, &first))
goto error; goto error;
@ -673,6 +699,7 @@ gst_asf_parse_packet (GstBuffer * buffer, GstAsfPacketInfo * packet,
packet->seq_field_type = seq_len_type; packet->seq_field_type = seq_len_type;
packet->err_cor_len = err_length; packet->err_cor_len = err_length;
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader); gst_byte_reader_free (reader);
return ret; return ret;
@ -680,6 +707,7 @@ error:
ret = FALSE; ret = FALSE;
GST_WARNING ("Error while parsing data packet"); GST_WARNING ("Error while parsing data packet");
end: end:
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader); gst_byte_reader_free (reader);
return ret; return ret;
} }
@ -738,16 +766,20 @@ gst_asf_parse_headers (GstBuffer * buffer, GstAsfFileInfo * file_info)
guint32 i; guint32 i;
GstByteReader *reader; GstByteReader *reader;
guint64 object_size; 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])); &(guids[ASF_HEADER_OBJECT_INDEX]));
if (object_size == 0) { if (object_size == 0) {
GST_WARNING ("ASF: Cannot parse, header guid not found at the beginning " GST_WARNING ("ASF: Cannot parse, header guid not found at the beginning "
" of data"); " of data");
gst_buffer_unmap (buffer, &map);
return FALSE; 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)) if (!gst_byte_reader_skip (reader, ASF_GUID_OBJSIZE_SIZE))
goto error; goto error;
@ -785,6 +817,7 @@ error:
ret = FALSE; ret = FALSE;
GST_WARNING ("ASF: Error while parsing headers"); GST_WARNING ("ASF: Error while parsing headers");
end: end:
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader); gst_byte_reader_free (reader);
return ret; return ret;
} }

View file

@ -112,6 +112,8 @@ gboolean gst_asf_parse_packet (GstBuffer * buffer, GstAsfPacketInfo * packet,
gboolean trust_delta_flag, guint packet_size); gboolean trust_delta_flag, guint packet_size);
guint64 gst_asf_match_and_peek_obj_size (const guint8 * data, guint64 gst_asf_match_and_peek_obj_size (const guint8 * data,
const Guid * guid); 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); gboolean gst_asf_parse_headers (GstBuffer * buffer, GstAsfFileInfo * file_info);
/* ASF tags /* ASF tags

View file

@ -46,7 +46,8 @@ static GstStateChangeReturn gst_asf_parse_change_state (GstElement * element,
GstStateChange transition); GstStateChange transition);
static void gst_asf_parse_loop (GstPad * pad); 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 static void
gst_asf_parse_reset (GstAsfParse * asfparse) gst_asf_parse_reset (GstAsfParse * asfparse)
@ -61,29 +62,62 @@ gst_asf_parse_reset (GstAsfParse * asfparse)
} }
static gboolean 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)) { GstQuery *query;
return gst_pad_activate_pull (pad, TRUE); gboolean pull_mode;
} else {
return gst_pad_activate_push (pad, TRUE); 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 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) { gboolean res;
return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_parse_loop, pad);
} else { switch (mode) {
return gst_pad_stop_task (pad); 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 static GstFlowReturn
gst_asf_parse_push (GstAsfParse * asfparse, GstBuffer * buf) gst_asf_parse_push (GstAsfParse * asfparse, GstBuffer * buf)
{ {
gst_buffer_set_caps (buf, asfparse->outcaps);
return gst_pad_push (asfparse->srcpad, buf); return gst_pad_push (asfparse->srcpad, buf);
} }
@ -93,10 +127,12 @@ gst_asf_parse_parse_data_object (GstAsfParse * asfparse, GstBuffer * buffer)
GstByteReader *reader; GstByteReader *reader;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
guint64 packet_count = 0; guint64 packet_count = 0;
GstMapInfo map;
GST_DEBUG_OBJECT (asfparse, "Parsing data object"); 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 */ /* skip to packet count */
if (!gst_byte_reader_skip (reader, 40)) if (!gst_byte_reader_skip (reader, 40))
goto error; goto error;
@ -112,12 +148,14 @@ gst_asf_parse_parse_data_object (GstAsfParse * asfparse, GstBuffer * buffer)
packet_count); packet_count);
} }
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader); gst_byte_reader_free (reader);
return gst_asf_parse_push (asfparse, buffer); return gst_asf_parse_push (asfparse, buffer);
error: error:
ret = GST_FLOW_ERROR; ret = GST_FLOW_ERROR;
GST_ERROR_OBJECT (asfparse, "Error while parsing data object headers"); GST_ERROR_OBJECT (asfparse, "Error while parsing data object headers");
gst_buffer_unmap (buffer, &map);
gst_byte_reader_free (reader); gst_byte_reader_free (reader);
return ret; return ret;
} }
@ -161,6 +199,7 @@ gst_asf_parse_pull_headers (GstAsfParse * asfparse)
GstBuffer *headers = NULL; GstBuffer *headers = NULL;
guint64 size; guint64 size;
GstFlowReturn ret; GstFlowReturn ret;
GstMapInfo map;
if ((ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset, if ((ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset,
ASF_GUID_OBJSIZE_SIZE, &guid_and_size)) != GST_FLOW_OK) { ASF_GUID_OBJSIZE_SIZE, &guid_and_size)) != GST_FLOW_OK) {
@ -168,8 +207,10 @@ gst_asf_parse_pull_headers (GstAsfParse * asfparse)
goto leave; goto leave;
} }
asfparse->offset += ASF_GUID_OBJSIZE_SIZE; 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])); &(guids[ASF_HEADER_OBJECT_INDEX]));
gst_buffer_unmap (guid_and_size, &map);
if (size == 0) { if (size == 0) {
GST_ERROR_OBJECT (asfparse, "ASF starting identifier missing"); GST_ERROR_OBJECT (asfparse, "ASF starting identifier missing");
@ -209,7 +250,7 @@ gst_asf_parse_pull_data_header (GstAsfParse * asfparse)
return ret; return ret;
} }
asfparse->offset += ASF_DATA_OBJECT_SIZE; 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])); &(guids[ASF_DATA_OBJECT_INDEX]));
if (asfparse->data_size == 0) { if (asfparse->data_size == 0) {
GST_ERROR_OBJECT (asfparse, "Unexpected object, was expecting data object"); 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) if (ret != GST_FLOW_OK)
break; break;
/* we can peek at the object size */ /* we can peek at the object size */
obj_size = obj_size = gst_asf_match_and_peek_obj_size_buf (guid_and_size, NULL);
gst_asf_match_and_peek_obj_size (GST_BUFFER_DATA (guid_and_size), NULL);
if (obj_size == 0) { if (obj_size == 0) {
GST_ERROR_OBJECT (asfparse, "Incomplete object found"); GST_ERROR_OBJECT (asfparse, "Incomplete object found");
gst_buffer_unref (guid_and_size); gst_buffer_unref (guid_and_size);
@ -346,9 +386,9 @@ pause:
GST_INFO_OBJECT (asfparse, "Pausing sinkpad task"); GST_INFO_OBJECT (asfparse, "Pausing sinkpad task");
gst_pad_pause_task (pad); 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 ()); 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, GST_ELEMENT_ERROR (asfparse, STREAM, FAILED,
(NULL), ("streaming task paused, reason %s (%d)", reason, ret)); (NULL), ("streaming task paused, reason %s (%d)", reason, ret));
gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ()); gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ());
@ -357,12 +397,12 @@ pause:
} }
static GstFlowReturn static GstFlowReturn
gst_asf_parse_chain (GstPad * pad, GstBuffer * buffer) gst_asf_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{ {
GstAsfParse *asfparse; GstAsfParse *asfparse;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
asfparse = GST_ASF_PARSE (GST_PAD_PARENT (pad)); asfparse = GST_ASF_PARSE (parent);
gst_adapter_push (asfparse->adapter, buffer); gst_adapter_push (asfparse->adapter, buffer);
switch (asfparse->parse_state) { switch (asfparse->parse_state) {
@ -372,9 +412,10 @@ gst_asf_parse_chain (GstPad * pad, GstBuffer * buffer)
/* we can peek at the object size */ /* we can peek at the object size */
asfparse->headers_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), (asfparse->adapter, ASF_GUID_OBJSIZE_SIZE),
&(guids[ASF_HEADER_OBJECT_INDEX])); &(guids[ASF_HEADER_OBJECT_INDEX]));
gst_adapter_unmap (asfparse->adapter);
if (asfparse->headers_size == 0) { if (asfparse->headers_size == 0) {
/* something is wrong, this probably ain't an ASF stream */ /* 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 */ /* we can peek at the object size */
asfparse->data_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), (asfparse->adapter, ASF_GUID_OBJSIZE_SIZE),
&(guids[ASF_DATA_OBJECT_INDEX])); &(guids[ASF_DATA_OBJECT_INDEX]));
gst_adapter_unmap (asfparse->adapter);
if (asfparse->data_size == 0) { if (asfparse->data_size == 0) {
/* something is wrong */ /* 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) { if (gst_adapter_available (asfparse->adapter) >= ASF_GUID_OBJSIZE_SIZE) {
guint64 obj_size; guint64 obj_size;
/* we can peek at the object 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); (asfparse->adapter, ASF_GUID_OBJSIZE_SIZE), NULL);
gst_adapter_unmap (asfparse->adapter);
if (gst_adapter_available (asfparse->adapter) >= obj_size) { if (gst_adapter_available (asfparse->adapter) >= obj_size) {
GST_DEBUG_OBJECT (asfparse, "Skiping object"); GST_DEBUG_OBJECT (asfparse, "Skiping object");
ret = gst_asf_parse_push (asfparse, ret = gst_asf_parse_push (asfparse,
@ -467,23 +510,6 @@ end:
return ret; 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 static void
gst_asf_parse_finalize (GObject * object) gst_asf_parse_finalize (GObject * object)
{ {
@ -511,17 +537,28 @@ gst_asf_parse_class_init (GstAsfParseClass * klass)
gstelement_class->change_state = gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_asf_parse_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 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"); 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_chain_function (asfparse->sinkpad, gst_asf_parse_chain);
gst_pad_set_activate_function (asfparse->sinkpad, gst_pad_set_activate_function (asfparse->sinkpad,
gst_asf_parse_sink_activate); gst_asf_parse_sink_activate);
gst_pad_set_activatepull_function (asfparse->sinkpad, gst_pad_set_activatemode_function (asfparse->sinkpad,
gst_asf_parse_sink_activate_pull); gst_asf_parse_sink_activate_mode);
gst_element_add_pad (GST_ELEMENT (asfparse), asfparse->sinkpad); gst_element_add_pad (GST_ELEMENT (asfparse), asfparse->sinkpad);
asfparse->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); 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); gst_element_add_pad (GST_ELEMENT (asfparse), asfparse->srcpad);
asfparse->adapter = gst_adapter_new (); 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->asfinfo = gst_asf_file_info_new ();
asfparse->packetinfo = g_new0 (GstAsfPacketInfo, 1); asfparse->packetinfo = g_new0 (GstAsfPacketInfo, 1);
gst_asf_parse_reset (asfparse); gst_asf_parse_reset (asfparse);

View file

@ -51,15 +51,15 @@ GST_STATIC_PAD_TEMPLATE ("src",
); );
static GstFlowReturn static GstFlowReturn
gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer); gst_rtp_asf_pay_handle_buffer (GstRTPBasePayload * rtppay, GstBuffer * buffer);
static gboolean 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, #define gst_rtp_asf_pay_parent_class parent_class
GST_TYPE_BASE_RTP_PAYLOAD); G_DEFINE_TYPE (GstRtpAsfPay, gst_rtp_asf_pay, GST_TYPE_RTP_BASE_PAYLOAD);
static void static void
gst_rtp_asf_pay_init (GstRtpAsfPay * rtpasfpay, GstRtpAsfPayClass * klass) gst_rtp_asf_pay_init (GstRtpAsfPay * rtpasfpay)
{ {
rtpasfpay->first_ts = 0; rtpasfpay->first_ts = 0;
rtpasfpay->config = NULL; rtpasfpay->config = NULL;
@ -80,44 +80,40 @@ gst_rtp_asf_pay_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (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 static void
gst_rtp_asf_pay_class_init (GstRtpAsfPayClass * klass) gst_rtp_asf_pay_class_init (GstRtpAsfPayClass * klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class;
GstBaseRTPPayloadClass *gstbasertppayload_class; GstElementClass *gstelement_class;
GstRTPBasePayloadClass *gstbasertppayload_class;
gobject_class = (GObjectClass *) klass; gobject_class = (GObjectClass *) klass;
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass; gstelement_class = (GstElementClass *) klass;
gstbasertppayload_class = (GstRTPBasePayloadClass *) klass;
gobject_class->finalize = gst_rtp_asf_pay_finalize; gobject_class->finalize = gst_rtp_asf_pay_finalize;
gstbasertppayload_class->handle_buffer = gst_rtp_asf_pay_handle_buffer; gstbasertppayload_class->handle_buffer = gst_rtp_asf_pay_handle_buffer;
gstbasertppayload_class->set_caps = gst_rtp_asf_pay_set_caps; 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, GST_DEBUG_CATEGORY_INIT (rtpasfpay_debug, "rtpasfpay", 0,
"ASF RTP Payloader"); "ASF RTP Payloader");
} }
static gboolean 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 */ /* 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); 1000);
return TRUE; return TRUE;
} }
@ -125,7 +121,7 @@ gst_rtp_asf_pay_set_caps (GstBaseRTPPayload * rtppay, GstCaps * caps)
static GstFlowReturn static GstFlowReturn
gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer) gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
{ {
GstBaseRTPPayload *rtppay; GstRTPBasePayload *rtppay;
GstAsfPacketInfo *packetinfo; GstAsfPacketInfo *packetinfo;
guint8 flags; guint8 flags;
guint8 *data; guint8 *data;
@ -134,7 +130,7 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
guint32 size_left; guint32 size_left;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
rtppay = GST_BASE_RTP_PAYLOAD (rtpasfpay); rtppay = GST_RTP_BASE_PAYLOAD (rtpasfpay);
packetinfo = &rtpasfpay->packetinfo; packetinfo = &rtpasfpay->packetinfo;
if (!gst_asf_parse_packet (buffer, packetinfo, TRUE, 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); buffer = gst_buffer_make_writable (buffer);
switch (packetinfo->padd_field_type) { switch (packetinfo->padd_field_type) {
case ASF_FIELD_TYPE_DWORD: case ASF_FIELD_TYPE_DWORD:
GST_WRITE_UINT32_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0); gst_buffer_memset (buffer, offset, 0, 4);
break; break;
case ASF_FIELD_TYPE_WORD: case ASF_FIELD_TYPE_WORD:
GST_WRITE_UINT16_LE (&(GST_BUFFER_DATA (buffer)[offset]), 0); gst_buffer_memset (buffer, offset, 0, 2);
break; break;
case ASF_FIELD_TYPE_BYTE: case ASF_FIELD_TYPE_BYTE:
GST_BUFFER_DATA (buffer)[offset] = 0; gst_buffer_memset (buffer, offset, 0, 1);
break; break;
case ASF_FIELD_TYPE_NONE: case ASF_FIELD_TYPE_NONE:
default: default:
@ -189,23 +185,26 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
* This flag tells us to push the packet. * This flag tells us to push the packet.
*/ */
gboolean force_push = FALSE; gboolean force_push = FALSE;
GstRTPBuffer rtp;
/* we have no output buffer pending, create one */ /* we have no output buffer pending, create one */
if (rtpasfpay->current == NULL) { if (rtpasfpay->current == NULL) {
GST_LOG_OBJECT (rtpasfpay, "Creating new output buffer"); GST_LOG_OBJECT (rtpasfpay, "Creating new output buffer");
rtpasfpay->current = 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); 0, 0);
rtpasfpay->cur_off = gst_rtp_buffer_get_header_len (rtpasfpay->current); rtpasfpay->cur_off = 0;
rtpasfpay->has_ts = FALSE; rtpasfpay->has_ts = FALSE;
rtpasfpay->marker = FALSE; rtpasfpay->marker = FALSE;
} }
data = GST_BUFFER_DATA (rtpasfpay->current) + rtpasfpay->cur_off; gst_rtp_buffer_map (rtpasfpay->current, GST_MAP_READWRITE, &rtp);
size_left = GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off; 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: %" GST_DEBUG_OBJECT (rtpasfpay, "Input buffer bytes consumed: %"
G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT, packet_offset, 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, "Output rtpbuffer status");
GST_DEBUG_OBJECT (rtpasfpay, "Current offset: %" G_GUINT32_FORMAT, 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; rtpasfpay->ts = packetinfo->send_time;
} }
if (GST_BUFFER_SIZE (rtpasfpay->current) - rtpasfpay->cur_off >= if (size_left >= packet_util_size + 8) {
packet_util_size + 8) {
/* enough space for the rest of the packet */ /* enough space for the rest of the packet */
if (packet_offset == 0) { if (packet_offset == 0) {
flags = flags | 0x40; flags = flags | 0x40;
@ -243,8 +241,7 @@ gst_rtp_asf_pay_handle_packet (GstRtpAsfPay * rtpasfpay, GstBuffer * buffer)
data[0] = flags; data[0] = flags;
GST_WRITE_UINT32_BE (data + 4, GST_WRITE_UINT32_BE (data + 4,
(gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts); (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset, gst_buffer_extract (buffer, packet_offset, data + 8, packet_util_size);
packet_util_size);
/* updating status variables */ /* updating status variables */
rtpasfpay->cur_off += 8 + packet_util_size; 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_UINT24_BE (data + 1, packet_offset);
GST_WRITE_UINT32_BE (data + 4, GST_WRITE_UINT32_BE (data + 4,
(gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts); (gint32) (packetinfo->send_time) - (gint32) rtpasfpay->ts);
memcpy (data + 8, GST_BUFFER_DATA (buffer) + packet_offset, gst_buffer_extract (buffer, packet_offset, data + 8, size_left - 8);
size_left - 8);
/* updating status variables */ /* updating status variables */
rtpasfpay->cur_off += size_left; 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 */ /* there is not enough room for any more buffers */
if (force_push || size_left <= 8) { 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) { if (size_left != 0) {
/* trim remaining bytes not used */ gst_buffer_set_size (rtpasfpay->current,
GstBuffer *aux = gst_buffer_create_sub (rtpasfpay->current, 0, gst_buffer_get_size (rtpasfpay->current) - size_left);
GST_BUFFER_SIZE (rtpasfpay->current) - size_left);
gst_buffer_unref (rtpasfpay->current);
rtpasfpay->current = aux;
} }
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_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->seqnum++;
rtppay->timestamp = packetinfo->send_time; rtppay->timestamp = packetinfo->send_time;
GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer"); GST_DEBUG_OBJECT (rtpasfpay, "Pushing rtp buffer");
ret = ret =
gst_pad_push (GST_BASE_RTP_PAYLOAD_SRCPAD (rtppay), gst_pad_push (GST_RTP_BASE_PAYLOAD_SRCPAD (rtppay),
rtpasfpay->current); rtpasfpay->current);
rtpasfpay->current = NULL; rtpasfpay->current = NULL;
if (ret != GST_FLOW_OK) { if (ret != GST_FLOW_OK) {
@ -313,6 +305,8 @@ static GstFlowReturn
gst_rtp_asf_pay_parse_headers (GstRtpAsfPay * rtpasfpay) gst_rtp_asf_pay_parse_headers (GstRtpAsfPay * rtpasfpay)
{ {
gchar *maxps; gchar *maxps;
GstMapInfo map;
g_return_val_if_fail (rtpasfpay->headers, GST_FLOW_ERROR); g_return_val_if_fail (rtpasfpay->headers, GST_FLOW_ERROR);
if (!gst_asf_parse_headers (rtpasfpay->headers, &rtpasfpay->asfinfo)) 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 */ /* get the config for caps */
g_free (rtpasfpay->config); g_free (rtpasfpay->config);
rtpasfpay->config = g_base64_encode (GST_BUFFER_DATA (rtpasfpay->headers), gst_buffer_map (rtpasfpay->headers, &map, GST_MAP_READ);
GST_BUFFER_SIZE (rtpasfpay->headers)); 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", GST_DEBUG_OBJECT (rtpasfpay, "Serialized headers to base64 string %s",
rtpasfpay->config); rtpasfpay->config);
@ -338,7 +333,7 @@ gst_rtp_asf_pay_parse_headers (GstRtpAsfPay * rtpasfpay)
rtpasfpay->config); rtpasfpay->config);
maxps = maxps =
g_strdup_printf ("%" G_GUINT32_FORMAT, rtpasfpay->asfinfo.packet_size); 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_TYPE_STRING, maxps, "config", G_TYPE_STRING, rtpasfpay->config, NULL);
g_free (maxps); g_free (maxps);
@ -353,7 +348,7 @@ error:
} }
static GstFlowReturn 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); 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, GST_LOG_OBJECT (rtpasfpay,
"Dropping buffer as we already pushed all packets"); "Dropping buffer as we already pushed all packets");
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
return GST_FLOW_UNEXPECTED; /* we already finished our job */ return GST_FLOW_EOS; /* we already finished our job */
} }
/* receive headers /* receive headers
@ -369,20 +364,20 @@ gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer)
if (G_UNLIKELY (rtpasfpay->state == ASF_NOT_STARTED)) { if (G_UNLIKELY (rtpasfpay->state == ASF_NOT_STARTED)) {
guint64 header_size; 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, GST_ERROR_OBJECT (rtpasfpay,
"Buffer too small, smaller than a Guid and object size"); "Buffer too small, smaller than a Guid and object size");
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
return GST_FLOW_ERROR; 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])); &(guids[ASF_HEADER_OBJECT_INDEX]));
if (header_size > 0) { if (header_size > 0) {
GST_DEBUG_OBJECT (rtpasfpay, "ASF header guid received, size %" GST_DEBUG_OBJECT (rtpasfpay, "ASF header guid received, size %"
G_GUINT64_FORMAT, header_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" GST_ERROR_OBJECT (rtpasfpay, "Headers should be contained in a single"
" buffer"); " buffer");
gst_buffer_unref (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"); GST_DEBUG_OBJECT (rtpasfpay, "Storing headers");
if (GST_BUFFER_SIZE (buffer) == header_size) { if (gst_buffer_get_size (buffer) == header_size) {
rtpasfpay->headers = buffer; rtpasfpay->headers = buffer;
return GST_FLOW_OK; return GST_FLOW_OK;
} else { } else {
/* headers are a subbuffer of thie buffer */ /* headers are a subbuffer of thie buffer */
GstBuffer *aux = gst_buffer_create_sub (buffer, header_size, GstBuffer *aux = gst_buffer_copy_region (buffer,
GST_BUFFER_SIZE (buffer) - header_size); GST_BUFFER_COPY_ALL, header_size,
rtpasfpay->headers = gst_buffer_create_sub (buffer, 0, 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); 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 (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 " GST_ERROR_OBJECT (rtpasfpay, "Received buffer of different size of "
"the data object header"); "the data object header");
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
if (gst_asf_match_guid (GST_BUFFER_DATA (buffer), gst_buffer_map (buffer, &map, GST_MAP_READ);
&(guids[ASF_DATA_OBJECT_INDEX]))) { 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"); GST_DEBUG_OBJECT (rtpasfpay, "Received data object header");
rtpasfpay->headers = gst_buffer_append (rtpasfpay->headers, buffer); rtpasfpay->headers = gst_buffer_append (rtpasfpay->headers, buffer);
rtpasfpay->state = ASF_PACKETS; rtpasfpay->state = ASF_PACKETS;
return gst_rtp_asf_pay_parse_headers (rtpasfpay); return gst_rtp_asf_pay_parse_headers (rtpasfpay);
} else { } else {
gst_buffer_unmap (buffer, &map);
GST_ERROR_OBJECT (rtpasfpay, "Unexpected object received (was expecting " GST_ERROR_OBJECT (rtpasfpay, "Unexpected object received (was expecting "
"data object)"); "data object)");
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
@ -454,7 +455,7 @@ gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer)
GST_INFO_OBJECT (rtpasfpay, "Packets ended"); GST_INFO_OBJECT (rtpasfpay, "Packets ended");
rtpasfpay->state = ASF_END; rtpasfpay->state = ASF_END;
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
return GST_FLOW_UNEXPECTED; return GST_FLOW_EOS;
} }
} }

View file

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