1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
45 #include "gstasfdemux.h"
46 #include "asfheaders.h"
47 #include "asfpacket.h"
49 static GstStaticPadTemplate gst_asf_demux_sink_template =
50 GST_STATIC_PAD_TEMPLATE ("sink",
53 GST_STATIC_CAPS ("video/x-ms-asf")
56 static GstStaticPadTemplate audio_src_template =
57 GST_STATIC_PAD_TEMPLATE ("audio_%u",
62 static GstStaticPadTemplate video_src_template =
63 GST_STATIC_PAD_TEMPLATE ("video_%u",
68 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
69 #define ASF_OBJECT_HEADER_SIZE (16+8)
71 /* FIXME: get rid of this */
72 /* abuse this GstFlowReturn enum for internal usage */
73 #define ASF_FLOW_NEED_MORE_DATA 99
75 #define gst_asf_get_flow_name(flow) \
76 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
77 "need-more-data" : gst_flow_get_name (flow)
79 GST_DEBUG_CATEGORY (asfdemux_dbg);
81 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
82 GstStateChange transition);
83 static gboolean gst_asf_demux_element_send_event (GstElement * element,
85 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
87 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
88 GstObject * parent, GstQuery * query);
89 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
91 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
93 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
94 guint8 ** p_data, guint64 * p_size);
95 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
96 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
97 GstObject * parent, GstPadMode mode, gboolean active);
98 static void gst_asf_demux_loop (GstASFDemux * demux);
100 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
101 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
102 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
103 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
105 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
106 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
107 AsfStream * stream, GstBuffer ** p_buffer);
108 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
110 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
112 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
115 #define gst_asf_demux_parent_class parent_class
116 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
119 gst_asf_demux_class_init (GstASFDemuxClass * klass)
121 GstElementClass *gstelement_class;
123 gstelement_class = (GstElementClass *) klass;
125 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
127 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
129 gst_element_class_add_pad_template (gstelement_class,
130 gst_static_pad_template_get (&audio_src_template));
131 gst_element_class_add_pad_template (gstelement_class,
132 gst_static_pad_template_get (&video_src_template));
133 gst_element_class_add_pad_template (gstelement_class,
134 gst_static_pad_template_get (&gst_asf_demux_sink_template));
136 gstelement_class->change_state =
137 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
138 gstelement_class->send_event =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
143 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
145 gst_caps_replace (&stream->caps, NULL);
146 if (stream->pending_tags) {
147 gst_tag_list_unref (stream->pending_tags);
148 stream->pending_tags = NULL;
152 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
154 gst_object_unref (stream->pad);
158 while (stream->payloads->len > 0) {
162 last = stream->payloads->len - 1;
163 payload = &g_array_index (stream->payloads, AsfPayload, last);
164 gst_buffer_replace (&payload->buf, NULL);
165 g_array_remove_index (stream->payloads, last);
167 if (stream->payloads) {
168 g_array_free (stream->payloads, TRUE);
169 stream->payloads = NULL;
171 if (stream->ext_props.valid) {
172 g_free (stream->ext_props.payload_extensions);
173 stream->ext_props.payload_extensions = NULL;
178 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
180 GST_LOG_OBJECT (demux, "resetting");
182 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
183 demux->segment_running = FALSE;
184 if (demux->adapter && !chain_reset) {
185 gst_adapter_clear (demux->adapter);
186 g_object_unref (demux->adapter);
187 demux->adapter = NULL;
189 if (demux->taglist) {
190 gst_tag_list_unref (demux->taglist);
191 demux->taglist = NULL;
193 if (demux->metadata) {
194 gst_caps_unref (demux->metadata);
195 demux->metadata = NULL;
197 if (demux->global_metadata) {
198 gst_structure_free (demux->global_metadata);
199 demux->global_metadata = NULL;
202 demux->state = GST_ASF_DEMUX_STATE_HEADER;
203 g_free (demux->objpath);
204 demux->objpath = NULL;
205 g_strfreev (demux->languages);
206 demux->languages = NULL;
207 demux->num_languages = 0;
208 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
210 g_slist_free (demux->ext_stream_props);
211 demux->ext_stream_props = NULL;
213 while (demux->old_num_streams > 0) {
214 gst_asf_demux_free_stream (demux,
215 &demux->old_stream[demux->old_num_streams - 1]);
216 --demux->old_num_streams;
218 memset (demux->old_stream, 0, sizeof (demux->old_stream));
219 demux->old_num_streams = 0;
221 /* when resetting for a new chained asf, we don't want to remove the pads
222 * before adding the new ones */
224 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
225 demux->old_num_streams = demux->num_streams;
226 demux->num_streams = 0;
229 while (demux->num_streams > 0) {
230 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
231 --demux->num_streams;
233 memset (demux->stream, 0, sizeof (demux->stream));
235 /* do not remove those for not adding pads with same name */
236 demux->num_audio_streams = 0;
237 demux->num_video_streams = 0;
238 demux->have_group_id = FALSE;
239 demux->group_id = G_MAXUINT;
241 demux->num_streams = 0;
242 demux->activated_streams = FALSE;
243 demux->first_ts = GST_CLOCK_TIME_NONE;
244 demux->segment_ts = GST_CLOCK_TIME_NONE;
247 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
248 demux->state = GST_ASF_DEMUX_STATE_HEADER;
249 demux->seekable = FALSE;
250 demux->broadcast = FALSE;
251 demux->sidx_interval = 0;
252 demux->sidx_num_entries = 0;
253 g_free (demux->sidx_entries);
254 demux->sidx_entries = NULL;
256 demux->speed_packets = 1;
259 GST_LOG_OBJECT (demux, "Restarting");
260 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
261 demux->need_newsegment = TRUE;
262 demux->segment_seqnum = 0;
263 demux->segment_running = FALSE;
264 demux->accurate = FALSE;
265 demux->metadata = gst_caps_new_empty ();
266 demux->global_metadata = gst_structure_new_empty ("metadata");
267 demux->data_size = 0;
268 demux->data_offset = 0;
269 demux->index_offset = 0;
271 demux->base_offset = 0;
274 g_slist_free (demux->other_streams);
275 demux->other_streams = NULL;
279 gst_asf_demux_init (GstASFDemux * demux)
282 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
283 gst_pad_set_chain_function (demux->sinkpad,
284 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
285 gst_pad_set_event_function (demux->sinkpad,
286 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
287 gst_pad_set_activate_function (demux->sinkpad,
288 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
289 gst_pad_set_activatemode_function (demux->sinkpad,
290 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
291 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
293 /* set initial state */
294 gst_asf_demux_reset (demux, FALSE);
298 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
303 query = gst_query_new_scheduling ();
305 if (!gst_pad_peer_query (sinkpad, query)) {
306 gst_query_unref (query);
310 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
311 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
312 gst_query_unref (query);
317 GST_DEBUG_OBJECT (sinkpad, "activating pull");
318 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
322 GST_DEBUG_OBJECT (sinkpad, "activating push");
323 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
328 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
329 GstPadMode mode, gboolean active)
334 demux = GST_ASF_DEMUX (parent);
337 case GST_PAD_MODE_PUSH:
338 demux->state = GST_ASF_DEMUX_STATE_HEADER;
339 demux->streaming = TRUE;
342 case GST_PAD_MODE_PULL:
344 demux->state = GST_ASF_DEMUX_STATE_HEADER;
345 demux->streaming = FALSE;
347 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
350 res = gst_pad_stop_task (sinkpad);
361 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
366 demux = GST_ASF_DEMUX (parent);
368 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
369 switch (GST_EVENT_TYPE (event)) {
370 case GST_EVENT_SEGMENT:{
371 const GstSegment *segment;
373 gst_event_parse_segment (event, &segment);
375 if (segment->format == GST_FORMAT_BYTES) {
376 if (demux->packet_size && segment->start > demux->data_offset)
377 demux->packet = (segment->start - demux->data_offset) /
381 } else if (segment->format == GST_FORMAT_TIME) {
382 /* do not know packet position, not really a problem */
385 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
386 gst_event_unref (event);
390 /* record upstream segment for interpolation */
391 if (segment->format != demux->in_segment.format)
392 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
393 gst_segment_copy_into (segment, &demux->in_segment);
395 /* in either case, clear some state and generate newsegment later on */
396 GST_OBJECT_LOCK (demux);
397 demux->segment_ts = GST_CLOCK_TIME_NONE;
398 demux->in_gap = GST_CLOCK_TIME_NONE;
399 demux->need_newsegment = TRUE;
400 demux->segment_seqnum = gst_event_get_seqnum (event);
401 gst_asf_demux_reset_stream_state_after_discont (demux);
402 GST_OBJECT_UNLOCK (demux);
404 gst_event_unref (event);
410 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
411 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
412 (_("This stream contains no data.")),
413 ("got eos and didn't receive a complete header object"));
416 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
417 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
418 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
419 (_("Internal data stream error.")),
420 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
424 GST_OBJECT_LOCK (demux);
425 gst_adapter_clear (demux->adapter);
426 GST_OBJECT_UNLOCK (demux);
427 gst_asf_demux_send_event_unlocked (demux, event);
431 case GST_EVENT_FLUSH_STOP:
432 GST_OBJECT_LOCK (demux);
433 gst_asf_demux_reset_stream_state_after_discont (demux);
434 GST_OBJECT_UNLOCK (demux);
435 gst_asf_demux_send_event_unlocked (demux, event);
436 /* upon activation, latency is no longer introduced, e.g. after seek */
437 if (demux->activated_streams)
442 ret = gst_pad_event_default (pad, parent, event);
450 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
451 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
452 gboolean next, gboolean * eos)
454 GstClockTime idx_time;
460 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
463 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
466 /* if we want the next keyframe, we have to go forward till we find
467 a different packet number */
469 if (idx >= demux->sidx_num_entries - 1) {
470 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
475 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
476 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
483 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
489 *packet = demux->sidx_entries[idx].packet;
491 *speed = demux->sidx_entries[idx].count;
493 /* so we get closer to the actual time of the packet ... actually, let's not
494 * do this, since we throw away superfluous payloads before the seek position
495 * anyway; this way, our key unit seek 'snap resolution' is a bit better
496 * (ie. same as index resolution) */
498 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
502 idx_time = demux->sidx_interval * idx;
503 if (G_LIKELY (idx_time >= demux->preroll))
504 idx_time -= demux->preroll;
506 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
507 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
508 GST_TIME_ARGS (idx_time));
510 if (G_LIKELY (p_idx_time))
511 *p_idx_time = idx_time;
517 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
521 gst_adapter_clear (demux->adapter);
523 GST_DEBUG_OBJECT (demux, "reset stream state");
525 for (n = 0; n < demux->num_streams; n++) {
526 demux->stream[n].discont = TRUE;
527 demux->stream[n].last_flow = GST_FLOW_OK;
529 while (demux->stream[n].payloads->len > 0) {
533 last = demux->stream[n].payloads->len - 1;
534 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
535 gst_buffer_replace (&payload->buf, NULL);
536 g_array_remove_index (demux->stream[n].payloads, last);
542 gst_asf_demux_mark_discont (GstASFDemux * demux)
546 GST_DEBUG_OBJECT (demux, "Mark stream discont");
548 for (n = 0; n < demux->num_streams; n++)
549 demux->stream[n].discont = TRUE;
552 /* do a seek in push based mode */
554 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
559 GstSeekType cur_type, stop_type;
563 GstEvent *byte_event;
565 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
568 stop_type = GST_SEEK_TYPE_NONE;
571 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
573 /* determine packet, by index or by estimation */
574 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
577 (guint) gst_util_uint64_scale (demux->num_packets, cur,
581 if (packet > demux->num_packets) {
582 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
587 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
589 cur = demux->data_offset + (packet * demux->packet_size);
591 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
592 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
593 /* BYTE seek event */
594 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
595 cur, stop_type, stop);
596 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
597 res = gst_pad_push_event (demux->sinkpad, byte_event);
603 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
605 GstClockTime idx_time;
608 GstSeekType cur_type, stop_type;
610 gboolean only_need_update;
611 gboolean keyunit_sync, after, before, next;
616 guint packet, speed_count = 1;
621 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
622 demux->num_packets == 0 || demux->play_time == 0)) {
623 GST_LOG_OBJECT (demux, "stream is not seekable");
627 if (G_UNLIKELY (!demux->activated_streams)) {
628 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
632 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
634 seqnum = gst_event_get_seqnum (event);
636 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
637 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
641 if (G_UNLIKELY (rate <= 0.0)) {
642 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
646 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
648 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
649 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
650 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
651 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
652 next = after && !before;
654 if (G_UNLIKELY (demux->streaming)) {
655 /* support it safely needs more segment handling, e.g. closing etc */
657 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
660 /* we can (re)construct the start later on, but not the end */
661 if (stop_type != GST_SEEK_TYPE_NONE &&
662 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
663 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
666 gst_event_ref (event);
667 /* upstream might handle TIME seek, e.g. mms or rtsp,
668 * or not, e.g. http, then we give it a hand */
669 if (!gst_pad_push_event (demux->sinkpad, event))
670 return gst_asf_demux_handle_seek_push (demux, event);
675 /* unlock the streaming thread */
676 if (G_LIKELY (flush)) {
677 fevent = gst_event_new_flush_start ();
679 gst_event_set_seqnum (fevent, seqnum);
680 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
681 gst_asf_demux_send_event_unlocked (demux, fevent);
683 gst_pad_pause_task (demux->sinkpad);
686 /* grab the stream lock so that streaming cannot continue, for
687 * non flushing seeks when the element is in PAUSED this could block
689 GST_PAD_STREAM_LOCK (demux->sinkpad);
691 /* we now can stop flushing, since we have the stream lock now */
692 fevent = gst_event_new_flush_stop (TRUE);
693 gst_event_set_seqnum (fevent, seqnum);
694 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
696 if (G_LIKELY (flush))
697 gst_asf_demux_send_event_unlocked (demux, fevent);
699 gst_event_unref (fevent);
701 /* operating on copy of segment until we know the seek worked */
702 segment = demux->segment;
704 if (G_UNLIKELY (demux->segment_running && !flush)) {
705 GstSegment newsegment;
708 /* create the segment event to close the current segment */
709 gst_segment_copy_into (&segment, &newsegment);
710 newseg = gst_event_new_segment (&newsegment);
711 gst_event_set_seqnum (newseg, seqnum);
713 gst_asf_demux_send_event_unlocked (demux, newseg);
716 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
717 cur, stop_type, stop, &only_need_update);
719 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
720 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
722 seek_time = segment.start;
724 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
725 * real start of data and segment_start to indexed time for key unit seek*/
726 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
727 &idx_time, &speed_count, next, &eos))) {
731 demux->packet = demux->num_packets;
735 /* First try to query our source to see if it can convert for us. This is
736 the case when our source is an mms stream, notice that in this case
737 gstmms will do a time based seek to get the byte offset, this is not a
738 problem as the seek to this offset needs to happen anway. */
739 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
740 GST_FORMAT_BYTES, &offset)) {
741 packet = (offset - demux->data_offset) / demux->packet_size;
742 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
743 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
744 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
745 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
746 demux->packet_size, packet);
748 /* FIXME: For streams containing video, seek to an earlier position in
749 * the hope of hitting a keyframe and let the sinks throw away the stuff
750 * before the segment start. For audio-only this is unnecessary as every
752 if (flush && (demux->accurate || (keyunit_sync && !next))
753 && demux->num_video_streams > 0) {
754 seek_time -= 5 * GST_SECOND;
759 packet = (guint) gst_util_uint64_scale (demux->num_packets,
760 seek_time, demux->play_time);
762 if (packet > demux->num_packets)
763 packet = demux->num_packets;
766 if (G_LIKELY (keyunit_sync)) {
767 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
768 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
769 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
770 segment.start = idx_time;
771 segment.position = idx_time;
772 segment.time = idx_time;
776 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
778 GST_OBJECT_LOCK (demux);
779 demux->segment = segment;
780 demux->packet = packet;
781 demux->need_newsegment = TRUE;
782 demux->segment_seqnum = seqnum;
783 demux->speed_packets = speed_count;
784 gst_asf_demux_reset_stream_state_after_discont (demux);
785 GST_OBJECT_UNLOCK (demux);
788 /* restart our task since it might have been stopped when we did the flush */
789 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
792 /* streaming can continue now */
793 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
799 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
805 demux = GST_ASF_DEMUX (parent);
807 switch (GST_EVENT_TYPE (event)) {
809 GST_LOG_OBJECT (pad, "seek event");
810 ret = gst_asf_demux_handle_seek_event (demux, event);
811 gst_event_unref (event);
814 case GST_EVENT_NAVIGATION:
815 /* just drop these two silently */
816 gst_event_unref (event);
820 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
821 ret = gst_pad_event_default (pad, parent, event);
828 static inline guint32
829 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
833 ret = gst_asf_identify_guid (guids, guid);
835 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
836 gst_asf_get_guid_nick (guids, ret),
837 guid->v1, guid->v2, guid->v3, guid->v4);
849 /* expect is true when the user is expeting an object,
850 * when false, it will give no warnings if the object
854 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
855 guint data_len, AsfObject * object, gboolean expect)
859 if (data_len < ASF_OBJECT_HEADER_SIZE)
862 guid.v1 = GST_READ_UINT32_LE (data + 0);
863 guid.v2 = GST_READ_UINT32_LE (data + 4);
864 guid.v3 = GST_READ_UINT32_LE (data + 8);
865 guid.v4 = GST_READ_UINT32_LE (data + 12);
867 object->size = GST_READ_UINT64_LE (data + 16);
869 /* FIXME: make asf_demux_identify_object_guid() */
870 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
871 if (object->id == ASF_OBJ_UNDEFINED && expect) {
872 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
873 guid.v1, guid.v2, guid.v3, guid.v4);
880 gst_asf_demux_release_old_pads (GstASFDemux * demux)
882 GST_DEBUG_OBJECT (demux, "Releasing old pads");
884 while (demux->old_num_streams > 0) {
885 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
886 gst_event_new_eos ());
887 gst_asf_demux_free_stream (demux,
888 &demux->old_stream[demux->old_num_streams - 1]);
889 --demux->old_num_streams;
891 memset (demux->old_stream, 0, sizeof (demux->old_stream));
892 demux->old_num_streams = 0;
896 gst_asf_demux_chain_headers (GstASFDemux * demux)
900 guint8 *header_data, *data = NULL;
901 const guint8 *cdata = NULL;
904 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
908 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
909 if (obj.id != ASF_OBJ_HEADER)
912 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
914 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
915 if (gst_adapter_available (demux->adapter) < obj.size + 50)
918 data = gst_adapter_take (demux->adapter, obj.size + 50);
921 header_size = obj.size;
922 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
923 if (flow != GST_FLOW_OK)
926 /* calculate where the packet data starts */
927 demux->data_offset = obj.size + 50;
929 /* now parse the beginning of the ASF_OBJ_DATA object */
930 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
933 if (demux->num_streams == 0)
942 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
949 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
950 ("This doesn't seem to be an ASF file"));
952 return GST_FLOW_ERROR;
957 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
958 ("header parsing failed, or no streams found, flow = %s",
959 gst_flow_get_name (flow)));
961 return GST_FLOW_ERROR;
966 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
971 GST_DEBUG_OBJECT (demux, "Aggregating");
973 /* Store the value */
974 stream->last_flow = flow;
976 /* any other error that is not not-linked can be returned right away */
977 if (flow != GST_FLOW_NOT_LINKED)
980 for (i = 0; i < demux->num_streams; i++) {
981 if (demux->stream[i].active) {
982 flow = demux->stream[i].last_flow;
983 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
984 gst_flow_get_name (flow));
985 if (flow != GST_FLOW_NOT_LINKED)
990 /* If we got here, then all our active streams are not linked */
996 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
997 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1002 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1005 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1007 if (G_LIKELY (p_flow))
1010 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1011 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1012 "+%u", gst_flow_get_name (flow), offset, size);
1017 g_assert (*p_buf != NULL);
1019 buffer_size = gst_buffer_get_size (*p_buf);
1020 if (G_UNLIKELY (buffer_size < size)) {
1021 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1022 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1023 gst_buffer_unref (*p_buf);
1024 if (G_LIKELY (p_flow))
1025 *p_flow = GST_FLOW_EOS;
1034 gst_asf_demux_pull_indices (GstASFDemux * demux)
1036 GstBuffer *buf = NULL;
1040 offset = demux->index_offset;
1042 if (G_UNLIKELY (offset == 0)) {
1043 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1047 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1053 gst_buffer_map (buf, &map, GST_MAP_READ);
1054 g_assert (map.size >= 16 + 8);
1055 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1056 gst_buffer_unmap (buf, &map);
1057 gst_buffer_replace (&buf, NULL);
1059 /* check for sanity */
1060 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1061 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1065 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1069 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1070 ", size %u", offset, (guint) obj.size);
1072 offset += obj.size; /* increase before _process_object changes it */
1074 gst_buffer_map (buf, &map, GST_MAP_READ);
1075 g_assert (map.size >= obj.size);
1076 bufdata = (guint8 *) map.data;
1077 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1078 gst_buffer_unmap (buf, &map);
1079 gst_buffer_replace (&buf, NULL);
1081 if (G_UNLIKELY (flow != GST_FLOW_OK))
1086 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1090 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1094 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1095 if (obj.id != ASF_OBJ_DATA) {
1096 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1100 demux->state = GST_ASF_DEMUX_STATE_DATA;
1102 if (!demux->broadcast && obj.size > 50) {
1103 demux->data_size = obj.size - 50;
1104 /* CHECKME: for at least one file this is off by +158 bytes?! */
1105 demux->index_offset = demux->data_offset + demux->data_size;
1107 demux->data_size = 0;
1108 demux->index_offset = 0;
1113 if (!demux->broadcast) {
1114 /* skip object header (24 bytes) and file GUID (16 bytes) */
1115 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1117 demux->num_packets = 0;
1120 if (demux->num_packets == 0)
1121 demux->seekable = FALSE;
1123 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1124 if (demux->data_size == 0 && demux->num_packets > 0) {
1125 demux->data_size = demux->num_packets * demux->packet_size;
1126 demux->index_offset = demux->data_offset + demux->data_size;
1129 /* process pending stream objects and create pads for those */
1130 gst_asf_demux_process_queued_extended_stream_objects (demux);
1132 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1133 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1134 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1135 demux->data_offset, demux->data_size, demux->index_offset);
1141 gst_asf_demux_pull_headers (GstASFDemux * demux)
1145 GstBuffer *buf = NULL;
1150 GST_LOG_OBJECT (demux, "reading headers");
1152 /* pull HEADER object header, so we know its size */
1153 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1156 gst_buffer_map (buf, &map, GST_MAP_READ);
1157 g_assert (map.size >= 16 + 8);
1158 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1159 gst_buffer_unmap (buf, &map);
1160 gst_buffer_replace (&buf, NULL);
1162 if (obj.id != ASF_OBJ_HEADER)
1165 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1167 /* pull HEADER object */
1168 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1172 size = obj.size; /* don't want obj.size changed */
1173 gst_buffer_map (buf, &map, GST_MAP_READ);
1174 g_assert (map.size >= size);
1175 bufdata = (guint8 *) map.data;
1176 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1177 gst_buffer_unmap (buf, &map);
1178 gst_buffer_replace (&buf, NULL);
1180 if (flow != GST_FLOW_OK) {
1181 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1185 /* calculate where the packet data starts */
1186 demux->data_offset = demux->base_offset + obj.size + 50;
1188 /* now pull beginning of DATA object before packet data */
1189 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1193 gst_buffer_map (buf, &map, GST_MAP_READ);
1194 g_assert (map.size >= size);
1195 bufdata = (guint8 *) map.data;
1196 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1199 if (demux->num_streams == 0)
1202 gst_buffer_unmap (buf, &map);
1203 gst_buffer_replace (&buf, NULL);
1211 gst_buffer_unmap (buf, &map);
1212 gst_buffer_replace (&buf, NULL);
1214 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1215 ("This doesn't seem to be an ASF file"));
1224 gst_buffer_unmap (buf, &map);
1225 gst_buffer_replace (&buf, NULL);
1226 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1232 all_streams_prerolled (GstASFDemux * demux)
1234 GstClockTime preroll_time;
1235 guint i, num_no_data = 0;
1237 /* Allow at least 500ms of preroll_time */
1238 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1240 /* returns TRUE as long as there isn't a stream which (a) has data queued
1241 * and (b) the timestamp of last piece of data queued is < demux->preroll
1242 * AND there is at least one other stream with data queued */
1243 for (i = 0; i < demux->num_streams; ++i) {
1244 AsfPayload *last_payload = NULL;
1248 stream = &demux->stream[i];
1249 if (G_UNLIKELY (stream->payloads->len == 0)) {
1251 GST_LOG_OBJECT (stream->pad, "no data queued");
1255 /* find last payload with timestamp */
1256 for (last_idx = stream->payloads->len - 1;
1257 last_idx >= 0 && (last_payload == NULL
1258 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1259 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1262 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1263 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1264 GST_TIME_ARGS (preroll_time));
1265 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1266 || last_payload->ts <= preroll_time)) {
1267 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1272 if (G_UNLIKELY (num_no_data > 0))
1280 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1285 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1288 /* check for each mutual exclusion group whether it affects this stream */
1289 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1290 if (*mes == stream->id) {
1291 /* we are in this group; let's check if we've already activated streams
1292 * that are in the same group (and hence mutually exclusive to this
1294 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1297 for (i = 0; i < demux->num_streams; ++i) {
1298 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1299 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1300 "to already active stream with ID %d", stream->id,
1301 demux->stream[i].id);
1306 /* we can only be in this group once, let's break out and move on to
1307 * the next mutual exclusion group */
1318 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1320 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1321 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1324 /* go trhough each stream, find smallest timestamp */
1325 for (i = 0; i < demux->num_streams; ++i) {
1328 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1329 stream = &demux->stream[i];
1331 for (j = 0; j < stream->payloads->len; ++j) {
1332 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1333 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1334 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1335 || stream_min_ts > payload->ts))
1336 stream_min_ts = payload->ts;
1339 /* if we don't have timestamp for this stream, wait for more data */
1340 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1343 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1344 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1345 first_ts = stream_min_ts;
1348 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1351 demux->first_ts = first_ts;
1353 /* update packets queued before we knew first timestamp */
1354 for (i = 0; i < demux->num_streams; ++i) {
1357 stream = &demux->stream[i];
1359 for (j = 0; j < stream->payloads->len; ++j) {
1360 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1361 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1362 if (payload->ts > first_ts)
1363 payload->ts -= first_ts;
1375 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1377 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1378 and often set wrong, inspecting the data is the only way that seem to be working */
1379 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1380 GstCaps *caps = NULL;
1381 GstAdapter *adapter = gst_adapter_new ();
1383 for (int i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1385 AsfPayload *payload;
1388 payload = &g_array_index (stream->payloads, AsfPayload, i);
1389 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1390 len = gst_adapter_available (adapter);
1391 data = gst_adapter_map (adapter, len);
1395 #define MIN_LENGTH 128
1397 /* look for the sync points */
1399 if (len < MIN_LENGTH || /* give typefind something to work on */
1400 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1401 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1407 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1410 if (prob < GST_TYPE_FIND_LIKELY) {
1413 if (len > MIN_LENGTH)
1414 /* this wasn't it, look for another sync point */
1418 gst_adapter_unmap (adapter);
1421 gst_object_unref (adapter);
1424 gst_caps_take (&stream->caps, caps);
1432 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1436 if (demux->activated_streams)
1439 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1442 if (!all_streams_prerolled (demux) && !force) {
1443 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1447 for (i = 0; i < demux->num_streams; ++i) {
1448 AsfStream *stream = &demux->stream[i];
1450 if (stream->payloads->len > 0) {
1452 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1453 !stream->active && /* do not inspect active streams (caps were already set) */
1454 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1455 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1456 /* try to gather some more data */
1459 /* we don't check mutual exclusion stuff here; either we have data for
1460 * a stream, then we active it, or we don't, then we'll ignore it */
1461 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1462 gst_asf_demux_activate_stream (demux, stream);
1464 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1468 gst_asf_demux_release_old_pads (demux);
1470 demux->activated_streams = TRUE;
1471 GST_LOG_OBJECT (demux, "signalling no more pads");
1472 gst_element_no_more_pads (GST_ELEMENT (demux));
1476 /* returns the stream that has a complete payload with the lowest timestamp
1477 * queued, or NULL (we push things by timestamp because during the internal
1478 * prerolling we might accumulate more data then the external queues can take,
1479 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1481 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1483 AsfPayload *best_payload = NULL;
1484 AsfStream *best_stream = NULL;
1487 for (i = 0; i < demux->num_streams; ++i) {
1491 stream = &demux->stream[i];
1493 /* Don't push any data until we have at least one payload that falls within
1494 * the current segment. This way we can remove out-of-segment payloads that
1495 * don't need to be decoded after a seek, sending only data from the
1496 * keyframe directly before our segment start */
1497 if (stream->payloads->len > 0) {
1498 AsfPayload *payload = NULL;
1501 /* find last payload with timestamp */
1502 for (last_idx = stream->payloads->len - 1;
1503 last_idx >= 0 && (payload == NULL
1504 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1505 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1507 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1508 (payload->ts < demux->segment.start))) {
1509 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1510 GST_DEBUG_OBJECT (stream->pad,
1511 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1512 GST_TIME_ARGS (payload->ts));
1513 demux->segment.start = payload->ts;
1514 demux->segment.time = payload->ts;
1516 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1517 GST_TIME_FORMAT " which is before our segment start %"
1518 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1519 GST_TIME_ARGS (demux->segment.start));
1524 /* Now see if there's a complete payload queued for this stream */
1527 /* find first complete payload with timestamp */
1529 j < stream->payloads->len && (payload == NULL
1530 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1531 payload = &g_array_index (stream->payloads, AsfPayload, j);
1534 if (!gst_asf_payload_is_complete (payload))
1537 /* ... and whether its timestamp is lower than the current best */
1538 if (best_stream == NULL || best_payload->ts > payload->ts) {
1539 best_stream = stream;
1540 best_payload = payload;
1548 static GstFlowReturn
1549 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1552 GstFlowReturn ret = GST_FLOW_OK;
1554 if (G_UNLIKELY (!demux->activated_streams)) {
1555 if (!gst_asf_demux_check_activate_streams (demux, force))
1557 /* streams are now activated */
1560 /* wait until we had a chance to "lock on" some payload's timestamp */
1561 if (G_UNLIKELY (demux->need_newsegment
1562 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1565 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1566 AsfPayload *payload;
1568 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1570 /* do we need to send a newsegment event */
1571 if ((G_UNLIKELY (demux->need_newsegment))) {
1572 GstEvent *segment_event;
1574 /* safe default if insufficient upstream info */
1575 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1578 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1579 demux->segment.duration > 0) {
1580 /* slight HACK; prevent clipping of last bit */
1581 demux->segment.stop = demux->segment.duration + demux->in_gap;
1584 /* FIXME : only if ACCURATE ! */
1585 if (G_LIKELY (!demux->accurate
1586 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1587 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1588 GST_TIME_ARGS (payload->ts));
1589 demux->segment.start = payload->ts;
1590 demux->segment.time = payload->ts;
1593 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1596 /* note: we fix up all timestamps to start from 0, so this should be ok */
1597 segment_event = gst_event_new_segment (&demux->segment);
1598 if (demux->segment_seqnum)
1599 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1600 gst_asf_demux_send_event_unlocked (demux, segment_event);
1602 /* now post any global tags we may have found */
1603 if (demux->taglist == NULL) {
1604 demux->taglist = gst_tag_list_new_empty ();
1605 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1608 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1609 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1611 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1612 gst_asf_demux_send_event_unlocked (demux,
1613 gst_event_new_tag (demux->taglist));
1614 demux->taglist = NULL;
1616 demux->need_newsegment = FALSE;
1617 demux->segment_seqnum = 0;
1618 demux->segment_running = TRUE;
1621 /* Do we have tags pending for this stream? */
1622 if (G_UNLIKELY (stream->pending_tags)) {
1623 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1624 gst_pad_push_event (stream->pad,
1625 gst_event_new_tag (stream->pending_tags));
1626 stream->pending_tags = NULL;
1629 /* We have the whole packet now so we should push the packet to
1630 * the src pad now. First though we should check if we need to do
1632 if (G_UNLIKELY (demux->span > 1)) {
1633 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1636 payload->buf = gst_buffer_make_writable (payload->buf);
1638 if (G_LIKELY (!payload->keyframe)) {
1639 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1642 if (G_UNLIKELY (stream->discont)) {
1643 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1644 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1645 stream->discont = FALSE;
1648 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1649 (payload->par_x != stream->par_x) &&
1650 (payload->par_y != stream->par_y))) {
1651 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1652 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1653 stream->par_x = payload->par_x;
1654 stream->par_y = payload->par_y;
1655 stream->caps = gst_caps_make_writable (stream->caps);
1656 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1657 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1658 gst_pad_set_caps (stream->pad, stream->caps);
1661 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1662 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1663 payload->interlaced);
1664 stream->interlaced = payload->interlaced;
1665 stream->caps = gst_caps_make_writable (stream->caps);
1666 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1667 (stream->interlaced ? "mixed" : "progressive"), NULL);
1668 gst_pad_set_caps (stream->pad, stream->caps);
1671 /* (sort of) interpolate timestamps using upstream "frame of reference",
1672 * typically useful for live src, but might (unavoidably) mess with
1673 * position reporting if a live src is playing not so live content
1674 * (e.g. rtspsrc taking some time to fall back to tcp) */
1675 GST_BUFFER_PTS (payload->buf) = payload->ts;
1676 if (GST_BUFFER_PTS_IS_VALID (payload->buf)) {
1677 GST_BUFFER_PTS (payload->buf) += demux->in_gap;
1679 if (payload->duration == GST_CLOCK_TIME_NONE
1680 && stream->ext_props.avg_time_per_frame != 0)
1681 GST_BUFFER_DURATION (payload->buf) =
1682 stream->ext_props.avg_time_per_frame * 100;
1684 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1686 /* FIXME: we should really set durations on buffers if we can */
1688 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1689 ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
1690 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1691 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1692 gst_buffer_get_size (payload->buf));
1694 if (stream->active) {
1695 ret = gst_pad_push (stream->pad, payload->buf);
1696 ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1698 gst_buffer_unref (payload->buf);
1701 payload->buf = NULL;
1702 g_array_remove_index (stream->payloads, 0);
1704 /* Break out as soon as we have an issue */
1705 if (G_UNLIKELY (ret != GST_FLOW_OK))
1713 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1717 g_assert (buf != NULL);
1719 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1721 gst_buffer_map (buf, &map, GST_MAP_READ);
1723 /* we return false on buffer too small */
1724 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1725 gst_buffer_unmap (buf, &map);
1729 /* check if it is a header */
1730 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1731 gst_buffer_unmap (buf, &map);
1732 if (obj.id == ASF_OBJ_HEADER) {
1739 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1741 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1742 GstFlowReturn ret = GST_FLOW_OK;
1743 GstBuffer *buf = NULL;
1744 gboolean header = FALSE;
1746 /* TODO maybe we should skip index objects after the data and look
1747 * further for a new header */
1748 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1749 g_assert (buf != NULL);
1750 /* check if it is a header */
1751 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1752 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1753 demux->base_offset = off;
1757 gst_buffer_unref (buf);
1764 gst_asf_demux_loop (GstASFDemux * demux)
1766 GstFlowReturn flow = GST_FLOW_OK;
1767 GstBuffer *buf = NULL;
1769 gboolean sent_eos = FALSE;
1771 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1772 if (!gst_asf_demux_pull_headers (demux)) {
1773 flow = GST_FLOW_ERROR;
1777 gst_asf_demux_pull_indices (demux);
1780 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1782 if (G_UNLIKELY (demux->num_packets != 0
1783 && demux->packet >= demux->num_packets))
1786 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1787 (guint) demux->num_packets);
1789 off = demux->data_offset + (demux->packet * demux->packet_size);
1791 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1792 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1793 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1794 if (flow == GST_FLOW_EOS)
1796 else if (flow == GST_FLOW_FLUSHING) {
1797 GST_DEBUG_OBJECT (demux, "Not fatal");
1803 if (G_LIKELY (demux->speed_packets == 1)) {
1804 GstAsfDemuxParsePacketError err;
1805 err = gst_asf_demux_parse_packet (demux, buf);
1806 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1807 /* when we don't know when the data object ends, we should check
1808 * for a chained asf */
1809 if (demux->num_packets == 0) {
1810 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1811 GST_INFO_OBJECT (demux, "Chained asf found");
1812 demux->base_offset = off;
1813 gst_asf_demux_reset (demux, TRUE);
1814 gst_buffer_unref (buf);
1818 /* FIXME: We should tally up fatal errors and error out only
1819 * after a few broken packets in a row? */
1821 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1822 gst_buffer_unref (buf);
1827 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1833 for (n = 0; n < demux->speed_packets; n++) {
1835 GstAsfDemuxParsePacketError err;
1838 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1839 n * demux->packet_size, demux->packet_size);
1840 err = gst_asf_demux_parse_packet (demux, sub);
1841 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1842 /* when we don't know when the data object ends, we should check
1843 * for a chained asf */
1844 if (demux->num_packets == 0) {
1845 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1846 GST_INFO_OBJECT (demux, "Chained asf found");
1847 demux->base_offset = off + n * demux->packet_size;
1848 gst_asf_demux_reset (demux, TRUE);
1849 gst_buffer_unref (sub);
1850 gst_buffer_unref (buf);
1854 /* FIXME: We should tally up fatal errors and error out only
1855 * after a few broken packets in a row? */
1857 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1861 gst_buffer_unref (sub);
1863 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1864 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1870 /* reset speed pull */
1871 demux->speed_packets = 1;
1874 gst_buffer_unref (buf);
1876 if (G_UNLIKELY (demux->num_packets > 0
1877 && demux->packet >= demux->num_packets)) {
1878 GST_LOG_OBJECT (demux, "reached EOS");
1882 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1883 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1887 /* check if we're at the end of the configured segment */
1888 /* FIXME: check if segment end reached etc. */
1894 /* if we haven't activated our streams yet, this might be because we have
1895 * less data queued than required for preroll; force stream activation and
1896 * send any pending payloads before sending EOS */
1897 if (!demux->activated_streams)
1898 gst_asf_demux_push_complete_payloads (demux, TRUE);
1900 /* we want to push an eos or post a segment-done in any case */
1901 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1904 /* for segment playback we need to post when (in stream time)
1905 * we stopped, this is either stop (when set) or the duration. */
1906 if ((stop = demux->segment.stop) == -1)
1907 stop = demux->segment.duration;
1909 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1910 gst_element_post_message (GST_ELEMENT_CAST (demux),
1911 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1913 gst_asf_demux_send_event_unlocked (demux,
1914 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1915 } else if (flow != GST_FLOW_EOS) {
1916 /* check if we have a chained asf, in case, we don't eos yet */
1917 if (gst_asf_demux_check_chained_asf (demux)) {
1918 GST_INFO_OBJECT (demux, "Chained ASF starting");
1919 gst_asf_demux_reset (demux, TRUE);
1923 /* normal playback, send EOS to all linked pads */
1924 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1925 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1927 /* ... and fall through to pause */
1931 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1932 gst_flow_get_name (flow));
1933 demux->segment_running = FALSE;
1934 gst_pad_pause_task (demux->sinkpad);
1936 /* For the error cases (not EOS) */
1938 if (flow == GST_FLOW_EOS)
1939 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1940 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1941 /* Post an error. Hopefully something else already has, but if not... */
1942 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1943 (_("Internal data stream error.")),
1944 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1953 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1954 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1955 flow = GST_FLOW_EOS;
1959 /* See FIXMEs above */
1962 gst_buffer_unref (buf);
1963 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1964 ("Error parsing ASF packet %u", (guint) demux->packet));
1965 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1966 flow = GST_FLOW_ERROR;
1972 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1973 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1974 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1977 gst_asf_demux_check_header (GstASFDemux * demux)
1980 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
1981 ASF_OBJECT_HEADER_SIZE);
1982 if (cdata == NULL) /* need more data */
1983 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1985 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1986 if (obj.id != ASF_OBJ_HEADER) {
1987 return GST_ASF_DEMUX_CHECK_HEADER_NO;
1989 return GST_ASF_DEMUX_CHECK_HEADER_YES;
1993 static GstFlowReturn
1994 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1996 GstFlowReturn ret = GST_FLOW_OK;
1999 demux = GST_ASF_DEMUX (parent);
2001 GST_LOG_OBJECT (demux,
2002 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2003 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2004 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2006 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2007 GST_DEBUG_OBJECT (demux, "received DISCONT");
2008 gst_asf_demux_mark_discont (demux);
2011 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2012 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2013 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2014 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2015 ", interpolation gap: %" GST_TIME_FORMAT,
2016 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2019 gst_adapter_push (demux->adapter, buf);
2021 switch (demux->state) {
2022 case GST_ASF_DEMUX_STATE_INDEX:{
2023 gint result = gst_asf_demux_check_header (demux);
2024 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2027 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2028 /* we don't care about this, probably an index */
2029 /* TODO maybe would be smarter to skip all the indices
2030 * until we got a new header or EOS to decide */
2031 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2034 GST_INFO_OBJECT (demux, "Chained asf starting");
2035 /* cleanup and get ready for a chained asf */
2036 gst_asf_demux_reset (demux, TRUE);
2040 case GST_ASF_DEMUX_STATE_HEADER:{
2041 ret = gst_asf_demux_chain_headers (demux);
2042 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2044 /* otherwise fall through */
2046 case GST_ASF_DEMUX_STATE_DATA:
2050 data_size = demux->packet_size;
2052 while (gst_adapter_available (demux->adapter) >= data_size) {
2054 GstAsfDemuxParsePacketError err;
2056 /* we don't know the length of the stream
2057 * check for a chained asf everytime */
2058 if (demux->num_packets == 0) {
2059 gint result = gst_asf_demux_check_header (demux);
2061 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2062 GST_INFO_OBJECT (demux, "Chained asf starting");
2063 /* cleanup and get ready for a chained asf */
2064 gst_asf_demux_reset (demux, TRUE);
2067 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2068 && demux->packet >= demux->num_packets)) {
2069 /* do not overshoot data section when streaming */
2073 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2075 /* FIXME: We should tally up fatal errors and error out only
2076 * after a few broken packets in a row? */
2077 err = gst_asf_demux_parse_packet (demux, buf);
2079 gst_buffer_unref (buf);
2081 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2082 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2084 GST_WARNING_OBJECT (demux, "Parse error");
2086 if (demux->packet >= 0)
2089 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2090 && demux->packet >= demux->num_packets)) {
2091 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2096 g_assert_not_reached ();
2100 if (ret != GST_FLOW_OK)
2101 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2107 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2113 static inline gboolean
2114 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2116 if (*p_size < num_bytes)
2119 *p_data += num_bytes;
2120 *p_size -= num_bytes;
2124 static inline guint8
2125 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2129 g_assert (*p_size >= 1);
2130 ret = GST_READ_UINT8 (*p_data);
2131 *p_data += sizeof (guint8);
2132 *p_size -= sizeof (guint8);
2136 static inline guint16
2137 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2141 g_assert (*p_size >= 2);
2142 ret = GST_READ_UINT16_LE (*p_data);
2143 *p_data += sizeof (guint16);
2144 *p_size -= sizeof (guint16);
2148 static inline guint32
2149 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2153 g_assert (*p_size >= 4);
2154 ret = GST_READ_UINT32_LE (*p_data);
2155 *p_data += sizeof (guint32);
2156 *p_size -= sizeof (guint32);
2160 static inline guint64
2161 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2165 g_assert (*p_size >= 8);
2166 ret = GST_READ_UINT64_LE (*p_data);
2167 *p_data += sizeof (guint64);
2168 *p_size -= sizeof (guint64);
2172 static inline guint32
2173 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
2180 g_assert (*p_size >= 1);
2181 return gst_asf_demux_get_uint8 (p_data, p_size);
2184 g_assert (*p_size >= 2);
2185 return gst_asf_demux_get_uint16 (p_data, p_size);
2188 g_assert (*p_size >= 4);
2189 return gst_asf_demux_get_uint32 (p_data, p_size);
2192 g_assert_not_reached ();
2199 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2200 guint8 ** p_data, guint64 * p_size)
2204 if (*p_size < num_bytes_to_read)
2207 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2208 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2210 *p_data += num_bytes_to_read;
2211 *p_size -= num_bytes_to_read;
2217 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2218 guint8 ** p_data, guint64 * p_size)
2222 if (*p_size < num_bytes_to_read)
2225 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2226 *p_data += num_bytes_to_read;
2227 *p_size -= num_bytes_to_read;
2232 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2233 guint8 ** p_data, guint64 * p_size)
2243 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2246 *p_strlen = s_length;
2248 if (s_length == 0) {
2249 GST_WARNING ("zero-length string");
2250 *p_str = g_strdup ("");
2254 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2257 g_assert (s != NULL);
2259 /* just because They don't exist doesn't
2260 * mean They are not out to get you ... */
2261 if (s[s_length - 1] != '\0') {
2262 s = g_realloc (s, s_length + 1);
2266 *p_str = (gchar *) s;
2272 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2274 g_assert (*p_size >= 4 * sizeof (guint32));
2276 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2277 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2278 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2279 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2283 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2286 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2289 /* WAVEFORMATEX Structure */
2290 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2291 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2292 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2293 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2294 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2295 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2296 /* Codec specific data size */
2297 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2302 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2305 if (*p_size < (4 + 4 + 1 + 2))
2308 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2309 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2310 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2311 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2316 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2317 guint8 ** p_data, guint64 * p_size)
2319 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2322 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2323 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2324 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2325 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2326 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2327 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2328 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2329 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2330 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2331 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2332 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2337 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2341 for (i = 0; i < demux->num_streams; i++) {
2342 if (demux->stream[i].id == id)
2343 return &demux->stream[i];
2346 if (gst_asf_demux_is_unknown_stream (demux, id))
2347 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2352 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2353 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2357 gst_pad_use_fixed_caps (src_pad);
2358 gst_pad_set_caps (src_pad, caps);
2360 gst_pad_set_event_function (src_pad,
2361 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2362 gst_pad_set_query_function (src_pad,
2363 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2365 stream = &demux->stream[demux->num_streams];
2366 stream->caps = caps;
2367 stream->pad = src_pad;
2369 stream->fps_known = !is_video; /* bit hacky for audio */
2370 stream->is_video = is_video;
2371 stream->pending_tags = tags;
2372 stream->discont = TRUE;
2376 st = gst_caps_get_structure (caps, 0);
2377 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2378 par_x > 0 && par_y > 0) {
2379 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2380 stream->par_x = par_x;
2381 stream->par_y = par_y;
2385 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2387 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2388 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2390 ++demux->num_streams;
2392 stream->active = FALSE;
2396 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2397 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2399 GstTagList *tags = NULL;
2400 GstBuffer *extradata = NULL;
2403 guint16 size_left = 0;
2404 gchar *codec_name = NULL;
2407 size_left = audio->size;
2409 /* Create the audio pad */
2410 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2412 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2415 /* Swallow up any left over data and set up the
2416 * standard properties from the header info */
2418 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2419 "codec specific data", size_left);
2421 g_assert (size_left <= *p_size);
2422 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2425 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2426 * additional two bytes indicating extradata. */
2427 /* FIXME: Handle the channel reorder map here */
2428 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2429 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2432 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2433 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2436 /* Informing about that audio format we just added */
2438 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2439 g_free (codec_name);
2443 gst_buffer_unref (extradata);
2445 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2446 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2447 audio->codec_tag, tags);
2449 ++demux->num_audio_streams;
2451 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2455 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2456 asf_stream_video_format * video, guint16 id,
2457 guint8 ** p_data, guint64 * p_size)
2459 GstTagList *tags = NULL;
2460 GstBuffer *extradata = NULL;
2465 gchar *codec_name = NULL;
2466 gint size_left = video->size - 40;
2468 /* Create the video pad */
2469 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2470 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2473 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2475 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2476 g_assert (size_left <= *p_size);
2477 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2480 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2482 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2483 caps = gst_riff_create_video_caps (video->tag, NULL,
2484 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2487 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2488 G_TYPE_UINT, video->tag, NULL);
2493 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2494 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2495 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2496 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2501 /* retry with the global metadata */
2502 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2503 demux->global_metadata);
2504 s = demux->global_metadata;
2505 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2506 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2507 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2508 if (ax > 0 && ay > 0)
2509 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2513 s = gst_caps_get_structure (caps, 0);
2514 gst_structure_remove_field (s, "framerate");
2517 /* add fourcc format to caps, some proprietary decoders seem to need it */
2518 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2519 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2523 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2524 g_free (codec_name);
2528 gst_buffer_unref (extradata);
2530 GST_INFO ("Adding video stream #%u, id %u, codec %"
2531 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2532 GST_FOURCC_ARGS (video->tag), video->tag);
2534 ++demux->num_video_streams;
2536 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2540 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2542 if (!stream->active) {
2546 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2547 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2548 gst_pad_set_active (stream->pad, TRUE);
2551 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2552 "%03u", stream->id);
2555 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2557 if (gst_event_parse_group_id (event, &demux->group_id))
2558 demux->have_group_id = TRUE;
2560 demux->have_group_id = FALSE;
2561 gst_event_unref (event);
2562 } else if (!demux->have_group_id) {
2563 demux->have_group_id = TRUE;
2564 demux->group_id = gst_util_group_id_next ();
2567 event = gst_event_new_stream_start (stream_id);
2568 if (demux->have_group_id)
2569 gst_event_set_group_id (event, demux->group_id);
2571 gst_pad_push_event (stream->pad, event);
2573 gst_pad_set_caps (stream->pad, stream->caps);
2575 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2576 stream->active = TRUE;
2581 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2584 AsfCorrectionType correction_type;
2585 AsfStreamType stream_type;
2586 GstClockTime time_offset;
2587 gboolean is_encrypted G_GNUC_UNUSED;
2591 guint stream_specific_size;
2592 guint type_specific_size G_GNUC_UNUSED;
2593 guint unknown G_GNUC_UNUSED;
2594 gboolean inspect_payload = FALSE;
2597 /* Get the rest of the header's header */
2598 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2599 goto not_enough_data;
2601 gst_asf_demux_get_guid (&guid, &data, &size);
2602 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2604 gst_asf_demux_get_guid (&guid, &data, &size);
2605 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2607 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2609 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2610 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2612 flags = gst_asf_demux_get_uint16 (&data, &size);
2613 stream_id = flags & 0x7f;
2614 is_encrypted = ! !((flags & 0x8000) << 15);
2615 unknown = gst_asf_demux_get_uint32 (&data, &size);
2617 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2618 stream_id, GST_TIME_ARGS (time_offset));
2620 /* dvr-ms has audio stream declared in stream specific data */
2621 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2622 AsfExtStreamType ext_stream_type;
2623 gst_asf_demux_get_guid (&guid, &data, &size);
2624 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2626 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2627 inspect_payload = TRUE;
2629 gst_asf_demux_get_guid (&guid, &data, &size);
2630 gst_asf_demux_get_uint32 (&data, &size);
2631 gst_asf_demux_get_uint32 (&data, &size);
2632 gst_asf_demux_get_uint32 (&data, &size);
2633 gst_asf_demux_get_guid (&guid, &data, &size);
2634 gst_asf_demux_get_uint32 (&data, &size);
2635 stream_type = ASF_STREAM_AUDIO;
2639 switch (stream_type) {
2640 case ASF_STREAM_AUDIO:{
2641 asf_stream_audio audio_object;
2643 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2644 goto not_enough_data;
2646 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2649 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2652 switch (correction_type) {
2653 case ASF_CORRECTION_ON:{
2654 guint span, packet_size, chunk_size, data_size, silence_data;
2656 GST_INFO ("Using error correction");
2658 if (size < (1 + 2 + 2 + 2 + 1))
2659 goto not_enough_data;
2661 span = gst_asf_demux_get_uint8 (&data, &size);
2662 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2663 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2664 data_size = gst_asf_demux_get_uint16 (&data, &size);
2665 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2667 /* FIXME: shouldn't this be per-stream? */
2670 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2671 packet_size, chunk_size, data_size, span, silence_data);
2673 if (demux->span > 1) {
2674 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2675 /* Disable descrambling */
2678 /* FIXME: this else branch was added for
2679 * weird_al_yankovic - the saga begins.asf */
2680 demux->ds_packet_size = packet_size;
2681 demux->ds_chunk_size = chunk_size;
2684 /* Descambling is enabled */
2685 demux->ds_packet_size = packet_size;
2686 demux->ds_chunk_size = chunk_size;
2689 /* Now skip the rest of the silence data */
2691 gst_bytestream_flush (demux->bs, data_size - 1);
2693 /* FIXME: CHECKME. And why -1? */
2694 if (data_size > 1) {
2695 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2696 goto not_enough_data;
2702 case ASF_CORRECTION_OFF:{
2703 GST_INFO ("Error correction off");
2704 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2705 goto not_enough_data;
2709 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2710 ("Audio stream using unknown error correction"));
2717 case ASF_STREAM_VIDEO:{
2718 asf_stream_video_format video_format_object;
2719 asf_stream_video video_object;
2722 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2723 goto not_enough_data;
2725 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2727 GST_INFO ("object is a video stream with %u bytes of "
2728 "additional data", vsize);
2730 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2732 goto not_enough_data;
2735 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2742 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2744 demux->other_streams =
2745 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
2749 stream = gst_asf_demux_get_stream (demux, stream_id);
2751 stream->inspect_payload = inspect_payload;
2756 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2757 /* we'll error out later if we found no streams */
2762 static const gchar *
2763 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2767 const gchar *asf_name;
2768 const gchar *gst_name;
2771 "WM/Genre", GST_TAG_GENRE}, {
2772 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2773 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2774 "WM/Picture", GST_TAG_IMAGE}, {
2775 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2776 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2777 "WM/Year", GST_TAG_DATE_TIME}
2778 /* { "WM/Composer", GST_TAG_COMPOSER } */
2783 if (name_utf8 == NULL) {
2784 GST_WARNING ("Failed to convert name to UTF8, skipping");
2788 out = strlen (name_utf8);
2790 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2791 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2792 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2793 return tags[i].gst_name;
2800 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2802 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2806 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2808 if (taglist == NULL)
2811 if (gst_tag_list_is_empty (taglist)) {
2812 gst_tag_list_unref (taglist);
2816 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2817 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
2819 gst_tag_list_unref (demux->taglist);
2820 gst_tag_list_unref (taglist);
2822 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2825 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2826 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2827 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2830 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2834 const guint8 *img_data = NULL;
2835 guint32 img_data_len = 0;
2836 guint8 pic_type = 0;
2838 gst_byte_reader_init (&r, tag_data, tag_data_len);
2840 /* skip mime type string (we don't trust it and do our own typefinding),
2841 * and also skip the description string, since we don't use it */
2842 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2843 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2844 !gst_byte_reader_skip_string_utf16 (&r) ||
2845 !gst_byte_reader_skip_string_utf16 (&r) ||
2846 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2847 goto not_enough_data;
2851 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2852 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2858 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2859 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2864 /* Extended Content Description Object */
2865 static GstFlowReturn
2866 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2869 /* Other known (and unused) 'text/unicode' metadata available :
2872 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2873 * WMFSDKVersion = 9.00.00.2980
2874 * WMFSDKNeeded = 0.0.0.0000
2875 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2876 * WM/Publisher = 4AD
2878 * WM/ProviderRating = 8
2879 * WM/ProviderStyle = Rock (similar to WM/Genre)
2880 * WM/GenreID (similar to WM/Genre)
2881 * WM/TrackNumber (same as WM/Track but as a string)
2883 * Other known (and unused) 'non-text' metadata available :
2889 * We might want to read WM/TrackNumber and use atoi() if we don't have
2893 GstTagList *taglist;
2894 guint16 blockcount, i;
2896 GST_INFO_OBJECT (demux, "object is an extended content description");
2898 taglist = gst_tag_list_new_empty ();
2900 /* Content Descriptor Count */
2902 goto not_enough_data;
2904 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2906 for (i = 1; i <= blockcount; ++i) {
2907 const gchar *gst_tag_name;
2911 GValue tag_value = { 0, };
2914 gchar *name_utf8 = NULL;
2918 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2919 goto not_enough_data;
2923 goto not_enough_data;
2925 /* Descriptor Value Data Type */
2926 datatype = gst_asf_demux_get_uint16 (&data, &size);
2928 /* Descriptor Value (not really a string, but same thing reading-wise) */
2929 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2931 goto not_enough_data;
2935 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2937 if (name_utf8 != NULL) {
2938 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2940 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2941 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2944 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2947 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2950 /* get rid of tags with empty value */
2951 if (value_utf8 != NULL && *value_utf8 != '\0') {
2952 GST_DEBUG ("string value %s", value_utf8);
2954 value_utf8[out] = '\0';
2956 if (gst_tag_name != NULL) {
2957 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
2958 guint year = atoi (value_utf8);
2961 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
2962 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
2964 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2965 guint id3v1_genre_id;
2966 const gchar *genre_str;
2968 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2969 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2970 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2971 g_free (value_utf8);
2972 value_utf8 = g_strdup (genre_str);
2977 /* convert tag from string to other type if required */
2978 tag_type = gst_tag_get_type (gst_tag_name);
2979 g_value_init (&tag_value, tag_type);
2980 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2981 GValue from_val = { 0, };
2983 g_value_init (&from_val, G_TYPE_STRING);
2984 g_value_set_string (&from_val, value_utf8);
2985 if (!g_value_transform (&from_val, &tag_value)) {
2986 GST_WARNING_OBJECT (demux,
2987 "Could not transform string tag to " "%s tag type %s",
2988 gst_tag_name, g_type_name (tag_type));
2989 g_value_unset (&tag_value);
2991 g_value_unset (&from_val);
2996 GST_DEBUG ("Setting metadata");
2997 g_value_init (&tag_value, G_TYPE_STRING);
2998 g_value_set_string (&tag_value, value_utf8);
3000 } else if (value_utf8 == NULL) {
3001 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3003 GST_DEBUG ("Skipping empty string value for %s",
3004 GST_STR_NULL (gst_tag_name));
3006 g_free (value_utf8);
3009 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3011 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3012 GST_FIXME ("Unhandled byte array tag %s",
3013 GST_STR_NULL (gst_tag_name));
3016 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3022 case ASF_DEMUX_DATA_TYPE_DWORD:{
3023 guint uint_val = GST_READ_UINT32_LE (value);
3025 /* this is the track number */
3026 g_value_init (&tag_value, G_TYPE_UINT);
3028 /* WM/Track counts from 0 */
3029 if (!strcmp (name_utf8, "WM/Track"))
3032 g_value_set_uint (&tag_value, uint_val);
3036 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3041 if (G_IS_VALUE (&tag_value)) {
3043 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3045 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3046 * is supposed to have a 0 base but is often wrongly written to start
3047 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3048 * replace the value added earlier from WM/Track or put it first in
3049 * the list, so that it will get picked up by _get_uint() */
3050 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3051 merge_mode = GST_TAG_MERGE_REPLACE;
3053 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3056 GST_DEBUG ("Setting global metadata %s", name_utf8);
3057 gst_structure_set_value (demux->global_metadata, name_utf8,
3061 g_value_unset (&tag_value);
3070 gst_asf_demux_add_global_tags (demux, taglist);
3077 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3078 gst_tag_list_unref (taglist);
3079 return GST_FLOW_OK; /* not really fatal */
3083 static GstStructure *
3084 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3089 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3091 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3094 s = gst_caps_get_structure (demux->metadata, i);
3095 if (gst_structure_has_name (s, sname))
3099 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3101 /* try lookup again; demux->metadata took ownership of the structure, so we
3102 * can't really make any assumptions about what happened to it, so we can't
3103 * just return it directly after appending it */
3104 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3107 static GstFlowReturn
3108 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3111 guint16 blockcount, i;
3113 GST_INFO_OBJECT (demux, "object is a metadata object");
3115 /* Content Descriptor Count */
3117 goto not_enough_data;
3119 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3121 for (i = 0; i < blockcount; ++i) {
3123 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3124 guint32 data_len, ival;
3127 if (size < (2 + 2 + 2 + 2 + 4))
3128 goto not_enough_data;
3130 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3131 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3132 name_len = gst_asf_demux_get_uint16 (&data, &size);
3133 data_type = gst_asf_demux_get_uint16 (&data, &size);
3134 data_len = gst_asf_demux_get_uint32 (&data, &size);
3136 if (size < name_len + data_len)
3137 goto not_enough_data;
3139 /* convert name to UTF-8 */
3140 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3142 gst_asf_demux_skip_bytes (name_len, &data, &size);
3144 if (name_utf8 == NULL) {
3145 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3146 gst_asf_demux_skip_bytes (data_len, &data, &size);
3150 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3151 gst_asf_demux_skip_bytes (data_len, &data, &size);
3159 goto not_enough_data;
3162 ival = gst_asf_demux_get_uint32 (&data, &size);
3164 /* skip anything else there may be, just in case */
3165 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3167 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3168 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3172 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3178 GST_WARNING ("Unexpected end of data parsing metadata object");
3179 return GST_FLOW_OK; /* not really fatal */
3183 static GstFlowReturn
3184 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3186 GstFlowReturn ret = GST_FLOW_OK;
3187 guint32 i, num_objects;
3188 guint8 unknown G_GNUC_UNUSED;
3190 /* Get the rest of the header's header */
3191 if (size < (4 + 1 + 1))
3192 goto not_enough_data;
3194 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3195 unknown = gst_asf_demux_get_uint8 (&data, &size);
3196 unknown = gst_asf_demux_get_uint8 (&data, &size);
3198 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3200 /* Loop through the header's objects, processing those */
3201 for (i = 0; i < num_objects; ++i) {
3202 GST_INFO_OBJECT (demux, "reading header part %u", i);
3203 ret = gst_asf_demux_process_object (demux, &data, &size);
3204 if (ret != GST_FLOW_OK) {
3205 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3214 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3215 ("short read parsing HEADER object"));
3216 return GST_FLOW_ERROR;
3220 static GstFlowReturn
3221 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3223 guint64 creation_time G_GNUC_UNUSED;
3224 guint64 file_size G_GNUC_UNUSED;
3225 guint64 send_time G_GNUC_UNUSED;
3226 guint64 packets_count, play_time, preroll;
3227 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3229 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3230 goto not_enough_data;
3232 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3233 file_size = gst_asf_demux_get_uint64 (&data, &size);
3234 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3235 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3236 play_time = gst_asf_demux_get_uint64 (&data, &size);
3237 send_time = gst_asf_demux_get_uint64 (&data, &size);
3238 preroll = gst_asf_demux_get_uint64 (&data, &size);
3239 flags = gst_asf_demux_get_uint32 (&data, &size);
3240 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3241 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3242 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3244 demux->broadcast = ! !(flags & 0x01);
3245 demux->seekable = ! !(flags & 0x02);
3247 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3248 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3249 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3251 if (demux->broadcast) {
3252 /* these fields are invalid if the broadcast flag is set */
3257 if (min_pktsize != max_pktsize)
3258 goto non_fixed_packet_size;
3260 demux->packet_size = max_pktsize;
3262 /* FIXME: do we need send_time as well? what is it? */
3263 if ((play_time * 100) >= (preroll * GST_MSECOND))
3264 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3266 demux->play_time = 0;
3268 demux->preroll = preroll * GST_MSECOND;
3270 /* initial latency */
3271 demux->latency = demux->preroll;
3273 if (demux->play_time == 0)
3274 demux->seekable = FALSE;
3276 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3277 GST_TIME_ARGS (demux->play_time));
3278 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3279 GST_TIME_ARGS (demux->preroll));
3281 if (demux->play_time > 0) {
3282 demux->segment.duration = demux->play_time;
3285 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3287 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3292 non_fixed_packet_size:
3294 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3295 ("packet size must be fixed"));
3296 return GST_FLOW_ERROR;
3300 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3301 ("short read parsing FILE object"));
3302 return GST_FLOW_ERROR;
3306 /* Content Description Object */
3307 static GstFlowReturn
3308 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3312 const gchar *gst_tag;
3317 GST_TAG_TITLE, 0, NULL}, {
3318 GST_TAG_ARTIST, 0, NULL}, {
3319 GST_TAG_COPYRIGHT, 0, NULL}, {
3320 GST_TAG_DESCRIPTION, 0, NULL}, {
3321 GST_TAG_COMMENT, 0, NULL}
3323 GstTagList *taglist;
3324 GValue value = { 0 };
3328 GST_INFO_OBJECT (demux, "object is a comment");
3330 if (size < (2 + 2 + 2 + 2 + 2))
3331 goto not_enough_data;
3333 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3334 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3335 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3336 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3337 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3339 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3340 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3341 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3343 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3344 if (size < tags[i].val_length)
3345 goto not_enough_data;
3347 /* might be just '/0', '/0'... */
3348 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3349 /* convert to UTF-8 */
3350 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3351 "UTF-8", "UTF-16LE", &in, &out, NULL);
3353 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3356 /* parse metadata into taglist */
3357 taglist = gst_tag_list_new_empty ();
3358 g_value_init (&value, G_TYPE_STRING);
3359 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3360 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3361 g_value_set_string (&value, tags[i].val_utf8);
3362 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3363 tags[i].gst_tag, &value, NULL);
3366 g_value_unset (&value);
3368 gst_asf_demux_add_global_tags (demux, taglist);
3370 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3371 g_free (tags[i].val_utf8);
3377 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3378 "comment tag section %d, skipping comment object", i);
3379 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3380 g_free (tags[i].val_utf8);
3381 return GST_FLOW_OK; /* not really fatal */
3385 static GstFlowReturn
3386 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3389 guint16 num_streams, i;
3393 goto not_enough_data;
3395 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3397 GST_INFO ("object is a bitrate properties object with %u streams",
3400 if (size < (num_streams * (2 + 4)))
3401 goto not_enough_data;
3403 for (i = 0; i < num_streams; ++i) {
3407 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3408 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3410 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3411 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3412 stream = gst_asf_demux_get_stream (demux, stream_id);
3414 if (stream->pending_tags == NULL) {
3415 stream->pending_tags =
3416 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3419 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3422 GST_WARNING ("stream id %u is too large", stream_id);
3430 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3431 return GST_FLOW_OK; /* not really fatal */
3435 static GstFlowReturn
3436 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3439 GstFlowReturn ret = GST_FLOW_OK;
3442 /* Get the rest of the header's header */
3443 if (size < (16 + 2 + 4))
3444 goto not_enough_data;
3446 /* skip GUID and two other bytes */
3447 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3448 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3450 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3452 /* FIXME: does data_size include the rest of the header that we have read? */
3453 if (hdr_size > size)
3454 goto not_enough_data;
3456 while (hdr_size > 0) {
3457 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3458 if (ret != GST_FLOW_OK)
3466 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3467 ("short read parsing extended header object"));
3468 return GST_FLOW_ERROR;
3472 static GstFlowReturn
3473 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3479 goto not_enough_data;
3481 if (demux->languages) {
3482 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3483 g_strfreev (demux->languages);
3484 demux->languages = NULL;
3485 demux->num_languages = 0;
3488 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3489 GST_LOG ("%u languages:", demux->num_languages);
3491 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3492 for (i = 0; i < demux->num_languages; ++i) {
3493 guint8 len, *lang_data = NULL;
3496 goto not_enough_data;
3497 len = gst_asf_demux_get_uint8 (&data, &size);
3498 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3501 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3504 /* truncate "en-us" etc. to just "en" */
3505 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3508 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3509 demux->languages[i] = utf8;
3512 goto not_enough_data;
3520 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3521 g_free (demux->languages);
3522 demux->languages = NULL;
3523 return GST_FLOW_OK; /* not fatal */
3527 static GstFlowReturn
3528 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3531 GstClockTime interval;
3534 if (size < (16 + 8 + 4 + 4))
3535 goto not_enough_data;
3538 gst_asf_demux_skip_bytes (16, &data, &size);
3539 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3540 gst_asf_demux_skip_bytes (4, &data, &size);
3541 count = gst_asf_demux_get_uint32 (&data, &size);
3543 demux->sidx_interval = interval;
3544 demux->sidx_num_entries = count;
3545 g_free (demux->sidx_entries);
3546 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3548 for (i = 0; i < count; ++i) {
3549 if (G_UNLIKELY (size <= 6))
3551 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3552 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3553 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3554 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3555 demux->sidx_entries[i].count);
3558 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3565 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3566 return GST_FLOW_OK; /* not fatal */
3570 static GstFlowReturn
3571 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3572 guint8 * data, guint64 size)
3578 if (size < 16 + 2 + (2 * 2))
3579 goto not_enough_data;
3581 gst_asf_demux_get_guid (&guid, &data, &size);
3582 num = gst_asf_demux_get_uint16 (&data, &size);
3585 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3589 if (size < (num * sizeof (guint16)))
3590 goto not_enough_data;
3592 /* read mutually exclusive stream numbers */
3593 mes = g_new (guint8, num + 1);
3594 for (i = 0; i < num; ++i) {
3595 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3596 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3599 /* add terminator so we can easily get the count or know when to stop */
3600 mes[i] = (guint8) - 1;
3602 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3609 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3610 return GST_FLOW_OK; /* not absolutely fatal */
3615 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3617 return g_slist_find (demux->other_streams,
3618 GINT_TO_POINTER (stream_num)) == NULL;
3621 static GstFlowReturn
3622 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3625 AsfStreamExtProps esp;
3626 AsfStream *stream = NULL;
3627 AsfObject stream_obj;
3628 guint16 stream_name_count;
3629 guint16 num_payload_ext;
3631 guint8 *stream_obj_data = NULL;
3634 guint i, stream_num;
3637 obj_size = (guint) size;
3640 goto not_enough_data;
3643 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3644 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3645 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3646 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3647 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3648 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3649 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3650 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3651 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3652 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3653 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3654 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3655 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3656 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3657 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3659 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3660 GST_TIME_ARGS (esp.start_time));
3661 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3662 GST_TIME_ARGS (esp.end_time));
3663 GST_INFO ("flags = %08x", esp.flags);
3664 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3665 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3666 GST_INFO ("stream number = %u", stream_num);
3667 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3668 (esp.lang_idx < demux->num_languages) ?
3669 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3670 GST_INFO ("stream name count = %u", stream_name_count);
3672 /* read stream names */
3673 for (i = 0; i < stream_name_count; ++i) {
3674 guint16 stream_lang_idx G_GNUC_UNUSED;
3675 gchar *stream_name = NULL;
3678 goto not_enough_data;
3679 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3680 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3681 goto not_enough_data;
3682 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3683 g_free (stream_name); /* TODO: store names in struct */
3686 /* read payload extension systems stuff */
3687 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3689 if (num_payload_ext > 0)
3690 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3692 esp.payload_extensions = NULL;
3694 for (i = 0; i < num_payload_ext; ++i) {
3695 AsfPayloadExtension ext;
3697 guint32 sys_info_len;
3699 if (size < 16 + 2 + 4)
3700 goto not_enough_data;
3702 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3703 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3704 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3706 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3707 GST_LOG ("payload systems info len = %u", sys_info_len);
3708 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3709 goto not_enough_data;
3711 esp.payload_extensions[i] = ext;
3714 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3716 /* there might be an optional STREAM_INFO object here now; if not, we
3717 * should have parsed the corresponding stream info object already (since
3718 * we are parsing the extended stream properties objects delayed) */
3720 stream = gst_asf_demux_get_stream (demux, stream_num);
3724 /* get size of the stream object */
3725 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3726 goto not_enough_data;
3728 if (stream_obj.id != ASF_OBJ_STREAM)
3729 goto expected_stream_object;
3731 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3732 stream_obj.size > (10 * 1024 * 1024))
3733 goto not_enough_data;
3735 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3737 /* process this stream object later after all the other 'normal' ones
3738 * have been processed (since the others are more important/non-hidden) */
3739 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3740 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3741 goto not_enough_data;
3743 /* parse stream object */
3744 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3745 g_free (stream_obj_data);
3750 stream->ext_props = esp;
3752 /* try to set the framerate */
3753 if (stream->is_video && stream->caps) {
3754 GValue framerate = { 0 };
3758 g_value_init (&framerate, GST_TYPE_FRACTION);
3760 num = GST_SECOND / 100;
3761 denom = esp.avg_time_per_frame;
3763 /* avoid division by 0, assume 25/1 framerate */
3764 denom = GST_SECOND / 2500;
3767 gst_value_set_fraction (&framerate, num, denom);
3769 stream->caps = gst_caps_make_writable (stream->caps);
3770 s = gst_caps_get_structure (stream->caps, 0);
3771 gst_structure_set_value (s, "framerate", &framerate);
3772 g_value_unset (&framerate);
3773 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3774 num, denom, ((gdouble) num) / denom);
3777 /* add language info now if we have it */
3778 if (stream->ext_props.lang_idx < demux->num_languages) {
3779 if (stream->pending_tags == NULL)
3780 stream->pending_tags = gst_tag_list_new_empty ();
3781 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3782 demux->languages[stream->ext_props.lang_idx]);
3783 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3784 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3787 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
3788 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3796 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3797 return GST_FLOW_OK; /* not absolutely fatal */
3799 expected_stream_object:
3801 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3802 "object: expected embedded stream object, but got %s object instead!",
3803 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3804 return GST_FLOW_OK; /* not absolutely fatal */
3808 static const gchar *
3809 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3813 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3814 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3815 nick += strlen ("ASF_OBJ_");
3817 if (demux->objpath == NULL) {
3818 demux->objpath = g_strdup (nick);
3822 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3823 g_free (demux->objpath);
3824 demux->objpath = newpath;
3827 return (const gchar *) demux->objpath;
3831 gst_asf_demux_pop_obj (GstASFDemux * demux)
3835 if ((s = g_strrstr (demux->objpath, "/"))) {
3838 g_free (demux->objpath);
3839 demux->objpath = NULL;
3844 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3849 /* Parse the queued extended stream property objects and add the info
3850 * to the existing streams or add the new embedded streams, but without
3851 * activating them yet */
3852 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3853 g_slist_length (demux->ext_stream_props));
3855 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3856 GstBuffer *buf = GST_BUFFER (l->data);
3859 gst_buffer_map (buf, &map, GST_MAP_READ);
3861 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3862 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
3863 gst_buffer_unmap (buf, &map);
3864 gst_buffer_unref (buf);
3866 g_slist_free (demux->ext_stream_props);
3867 demux->ext_stream_props = NULL;
3872 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3876 for (i = 0; i < demux->num_streams; ++i) {
3881 stream = &demux->stream[i];
3883 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3885 if (stream->active) {
3886 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3891 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3894 /* check for each mutual exclusion whether it affects this stream */
3895 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3896 if (*mes == stream->id) {
3897 /* if yes, check if we've already added streams that are mutually
3898 * exclusive with the stream we're about to add */
3899 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3900 for (j = 0; j < demux->num_streams; ++j) {
3901 /* if the broadcast flag is set, assume the hidden streams aren't
3902 * actually streamed and hide them (or playbin won't work right),
3903 * otherwise assume their data is available */
3904 if (demux->stream[j].id == *mes && demux->broadcast) {
3906 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3907 "mutually exclusive with already existing stream ID %d, "
3908 "hiding stream", stream->id, demux->stream[j].id);
3920 /* FIXME: we should do stream activation based on preroll data in
3921 * streaming mode too */
3922 if (demux->streaming && !is_hidden)
3923 gst_asf_demux_activate_stream (demux, stream);
3928 static GstFlowReturn
3929 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3932 GstFlowReturn ret = GST_FLOW_OK;
3934 guint64 obj_data_size;
3936 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3937 return ASF_FLOW_NEED_MORE_DATA;
3939 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3940 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3942 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3944 if (*p_size < obj_data_size)
3945 return ASF_FLOW_NEED_MORE_DATA;
3947 gst_asf_demux_push_obj (demux, obj.id);
3949 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3952 case ASF_OBJ_STREAM:
3953 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3957 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3959 case ASF_OBJ_HEADER:
3960 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3962 case ASF_OBJ_COMMENT:
3963 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3966 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3968 case ASF_OBJ_BITRATE_PROPS:
3970 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3973 case ASF_OBJ_EXT_CONTENT_DESC:
3975 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3978 case ASF_OBJ_METADATA_OBJECT:
3979 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3981 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3984 /* process these later, we might not have parsed the corresponding
3985 * stream object yet */
3986 GST_LOG ("%s: queued for later parsing", demux->objpath);
3987 buf = gst_buffer_new_and_alloc (obj_data_size);
3988 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
3989 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3993 case ASF_OBJ_LANGUAGE_LIST:
3994 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3996 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3997 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4000 case ASF_OBJ_SIMPLE_INDEX:
4001 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4003 case ASF_OBJ_CONTENT_ENCRYPTION:
4004 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4005 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4006 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4007 goto error_encrypted;
4008 case ASF_OBJ_CONCEAL_NONE:
4010 case ASF_OBJ_UNDEFINED:
4011 case ASF_OBJ_CODEC_COMMENT:
4013 case ASF_OBJ_PADDING:
4014 case ASF_OBJ_BITRATE_MUTEX:
4015 case ASF_OBJ_COMPATIBILITY:
4016 case ASF_OBJ_INDEX_PLACEHOLDER:
4017 case ASF_OBJ_INDEX_PARAMETERS:
4018 case ASF_OBJ_STREAM_PRIORITIZATION:
4019 case ASF_OBJ_SCRIPT_COMMAND:
4021 /* Unknown/unhandled object, skip it and hope for the best */
4022 GST_INFO ("%s: skipping object", demux->objpath);
4027 /* this can't fail, we checked the number of bytes available before */
4028 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4030 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4032 gst_asf_demux_pop_obj (demux);
4039 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4040 return GST_FLOW_ERROR;
4045 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4046 GstBuffer ** p_buffer)
4048 GstBuffer *descrambled_buffer;
4049 GstBuffer *scrambled_buffer;
4050 GstBuffer *sub_buffer;
4057 /* descrambled_buffer is initialised in the first iteration */
4058 descrambled_buffer = NULL;
4059 scrambled_buffer = *p_buffer;
4061 if (gst_buffer_get_size (scrambled_buffer) <
4062 demux->ds_packet_size * demux->span)
4065 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4066 offset += demux->ds_chunk_size) {
4067 off = offset / demux->ds_chunk_size;
4068 row = off / demux->span;
4069 col = off % demux->span;
4070 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
4071 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4072 col, off, demux->ds_chunk_size);
4073 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4074 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4075 demux->span, demux->ds_packet_size);
4076 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4077 gst_buffer_get_size (scrambled_buffer));
4079 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_NONE,
4080 idx * demux->ds_chunk_size, demux->ds_chunk_size);
4082 descrambled_buffer = sub_buffer;
4084 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4088 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4089 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4090 GST_BUFFER_DURATION (descrambled_buffer) =
4091 GST_BUFFER_DURATION (scrambled_buffer);
4092 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4093 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4094 GST_BUFFER_OFFSET_END (scrambled_buffer);
4096 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4098 gst_buffer_unref (scrambled_buffer);
4099 *p_buffer = descrambled_buffer;
4103 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4105 GstASFDemux *demux = GST_ASF_DEMUX (element);
4108 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4110 for (i = 0; i < demux->num_streams; ++i) {
4111 gst_event_ref (event);
4112 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4113 GST_OBJECT_CAST (element), event)) {
4114 gst_event_unref (event);
4119 gst_event_unref (event);
4123 /* takes ownership of the passed event */
4125 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4127 gboolean ret = TRUE;
4130 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4131 GST_EVENT_TYPE_NAME (event));
4133 for (i = 0; i < demux->num_streams; ++i) {
4134 gst_event_ref (event);
4135 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4137 gst_event_unref (event);
4142 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4146 gboolean res = FALSE;
4148 demux = GST_ASF_DEMUX (parent);
4150 GST_DEBUG ("handling %s query",
4151 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4153 switch (GST_QUERY_TYPE (query)) {
4154 case GST_QUERY_DURATION:
4158 gst_query_parse_duration (query, &format, NULL);
4160 if (format != GST_FORMAT_TIME) {
4161 GST_LOG ("only support duration queries in TIME format");
4165 GST_OBJECT_LOCK (demux);
4167 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4168 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4169 GST_TIME_ARGS (demux->segment.duration));
4171 gst_query_set_duration (query, GST_FORMAT_TIME,
4172 demux->segment.duration);
4176 GST_LOG ("duration not known yet");
4179 GST_OBJECT_UNLOCK (demux);
4183 case GST_QUERY_POSITION:{
4186 gst_query_parse_position (query, &format, NULL);
4188 if (format != GST_FORMAT_TIME) {
4189 GST_LOG ("only support position queries in TIME format");
4193 GST_OBJECT_LOCK (demux);
4195 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4196 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4197 GST_TIME_ARGS (demux->segment.position));
4199 gst_query_set_position (query, GST_FORMAT_TIME,
4200 demux->segment.position);
4204 GST_LOG ("position not known yet");
4207 GST_OBJECT_UNLOCK (demux);
4211 case GST_QUERY_SEEKING:{
4214 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4215 if (format == GST_FORMAT_TIME) {
4218 GST_OBJECT_LOCK (demux);
4219 duration = demux->segment.duration;
4220 GST_OBJECT_UNLOCK (demux);
4222 if (!demux->streaming || !demux->seekable) {
4223 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4230 /* try downstream first in TIME */
4231 res = gst_pad_query_default (pad, parent, query);
4233 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4234 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4235 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4236 /* if no luck, maybe in BYTES */
4237 if (!seekable || fmt != GST_FORMAT_TIME) {
4240 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4241 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4242 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4243 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4244 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4245 if (fmt != GST_FORMAT_BYTES)
4248 gst_query_unref (q);
4249 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4255 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4259 case GST_QUERY_LATENCY:
4262 GstClockTime min, max;
4264 /* preroll delay does not matter in non-live pipeline,
4265 * but we might end up in a live (rtsp) one ... */
4268 res = gst_pad_query_default (pad, parent, query);
4272 gst_query_parse_latency (query, &live, &min, &max);
4274 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4275 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4276 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4278 GST_OBJECT_LOCK (demux);
4280 min += demux->latency;
4282 max += demux->latency;
4283 GST_OBJECT_UNLOCK (demux);
4285 gst_query_set_latency (query, live, min, max);
4288 case GST_QUERY_SEGMENT:
4293 format = demux->segment.format;
4296 gst_segment_to_stream_time (&demux->segment, format,
4297 demux->segment.start);
4298 if ((stop = demux->segment.stop) == -1)
4299 stop = demux->segment.duration;
4301 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4303 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4308 res = gst_pad_query_default (pad, parent, query);
4315 static GstStateChangeReturn
4316 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4318 GstASFDemux *demux = GST_ASF_DEMUX (element);
4319 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4321 switch (transition) {
4322 case GST_STATE_CHANGE_NULL_TO_READY:{
4323 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4324 demux->need_newsegment = TRUE;
4325 demux->segment_running = FALSE;
4326 demux->accurate = FALSE;
4327 demux->adapter = gst_adapter_new ();
4328 demux->metadata = gst_caps_new_empty ();
4329 demux->global_metadata = gst_structure_new_empty ("metadata");
4330 demux->data_size = 0;
4331 demux->data_offset = 0;
4332 demux->index_offset = 0;
4333 demux->base_offset = 0;
4340 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4341 if (ret == GST_STATE_CHANGE_FAILURE)
4344 switch (transition) {
4345 case GST_STATE_CHANGE_PAUSED_TO_READY:
4346 case GST_STATE_CHANGE_READY_TO_NULL:
4347 gst_asf_demux_reset (demux, FALSE);