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;
151 if (stream->active) {
152 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
153 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
155 gst_object_unref (stream->pad);
159 if (stream->payloads) {
160 while (stream->payloads->len > 0) {
164 last = stream->payloads->len - 1;
165 payload = &g_array_index (stream->payloads, AsfPayload, last);
166 gst_buffer_replace (&payload->buf, NULL);
167 g_array_remove_index (stream->payloads, last);
169 g_array_free (stream->payloads, TRUE);
170 stream->payloads = NULL;
172 if (stream->ext_props.valid) {
173 g_free (stream->ext_props.payload_extensions);
174 stream->ext_props.payload_extensions = NULL;
179 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
181 GST_LOG_OBJECT (demux, "resetting");
183 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
184 demux->segment_running = FALSE;
185 if (demux->adapter && !chain_reset) {
186 gst_adapter_clear (demux->adapter);
187 g_object_unref (demux->adapter);
188 demux->adapter = NULL;
190 if (demux->taglist) {
191 gst_tag_list_unref (demux->taglist);
192 demux->taglist = NULL;
194 if (demux->metadata) {
195 gst_caps_unref (demux->metadata);
196 demux->metadata = NULL;
198 if (demux->global_metadata) {
199 gst_structure_free (demux->global_metadata);
200 demux->global_metadata = NULL;
203 demux->state = GST_ASF_DEMUX_STATE_HEADER;
204 g_free (demux->objpath);
205 demux->objpath = NULL;
206 g_strfreev (demux->languages);
207 demux->languages = NULL;
208 demux->num_languages = 0;
209 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
211 g_slist_free (demux->ext_stream_props);
212 demux->ext_stream_props = NULL;
214 while (demux->old_num_streams > 0) {
215 gst_asf_demux_free_stream (demux,
216 &demux->old_stream[demux->old_num_streams - 1]);
217 --demux->old_num_streams;
219 memset (demux->old_stream, 0, sizeof (demux->old_stream));
220 demux->old_num_streams = 0;
222 /* when resetting for a new chained asf, we don't want to remove the pads
223 * before adding the new ones */
225 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
226 demux->old_num_streams = demux->num_streams;
227 demux->num_streams = 0;
230 while (demux->num_streams > 0) {
231 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
232 --demux->num_streams;
234 memset (demux->stream, 0, sizeof (demux->stream));
236 /* do not remove those for not adding pads with same name */
237 demux->num_audio_streams = 0;
238 demux->num_video_streams = 0;
239 demux->have_group_id = FALSE;
240 demux->group_id = G_MAXUINT;
242 demux->num_streams = 0;
243 demux->activated_streams = FALSE;
244 demux->first_ts = GST_CLOCK_TIME_NONE;
245 demux->segment_ts = GST_CLOCK_TIME_NONE;
248 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
249 demux->state = GST_ASF_DEMUX_STATE_HEADER;
250 demux->seekable = FALSE;
251 demux->broadcast = FALSE;
252 demux->sidx_interval = 0;
253 demux->sidx_num_entries = 0;
254 g_free (demux->sidx_entries);
255 demux->sidx_entries = NULL;
257 demux->speed_packets = 1;
260 GST_LOG_OBJECT (demux, "Restarting");
261 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
262 demux->need_newsegment = TRUE;
263 demux->segment_seqnum = 0;
264 demux->segment_running = FALSE;
265 demux->accurate = FALSE;
266 demux->metadata = gst_caps_new_empty ();
267 demux->global_metadata = gst_structure_new_empty ("metadata");
268 demux->data_size = 0;
269 demux->data_offset = 0;
270 demux->index_offset = 0;
272 demux->base_offset = 0;
275 g_slist_free (demux->other_streams);
276 demux->other_streams = NULL;
280 gst_asf_demux_init (GstASFDemux * demux)
283 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
284 gst_pad_set_chain_function (demux->sinkpad,
285 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
286 gst_pad_set_event_function (demux->sinkpad,
287 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
288 gst_pad_set_activate_function (demux->sinkpad,
289 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
290 gst_pad_set_activatemode_function (demux->sinkpad,
291 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
292 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
294 /* set initial state */
295 gst_asf_demux_reset (demux, FALSE);
299 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
304 query = gst_query_new_scheduling ();
306 if (!gst_pad_peer_query (sinkpad, query)) {
307 gst_query_unref (query);
311 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
312 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
313 gst_query_unref (query);
318 GST_DEBUG_OBJECT (sinkpad, "activating pull");
319 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
323 GST_DEBUG_OBJECT (sinkpad, "activating push");
324 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
329 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
330 GstPadMode mode, gboolean active)
335 demux = GST_ASF_DEMUX (parent);
338 case GST_PAD_MODE_PUSH:
339 demux->state = GST_ASF_DEMUX_STATE_HEADER;
340 demux->streaming = TRUE;
343 case GST_PAD_MODE_PULL:
345 demux->state = GST_ASF_DEMUX_STATE_HEADER;
346 demux->streaming = FALSE;
348 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
351 res = gst_pad_stop_task (sinkpad);
362 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
367 demux = GST_ASF_DEMUX (parent);
369 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
370 switch (GST_EVENT_TYPE (event)) {
371 case GST_EVENT_SEGMENT:{
372 const GstSegment *segment;
374 gst_event_parse_segment (event, &segment);
376 if (segment->format == GST_FORMAT_BYTES) {
377 if (demux->packet_size && segment->start > demux->data_offset)
378 demux->packet = (segment->start - demux->data_offset) /
382 } else if (segment->format == GST_FORMAT_TIME) {
383 /* do not know packet position, not really a problem */
386 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
387 gst_event_unref (event);
391 /* record upstream segment for interpolation */
392 if (segment->format != demux->in_segment.format)
393 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
394 gst_segment_copy_into (segment, &demux->in_segment);
396 /* in either case, clear some state and generate newsegment later on */
397 GST_OBJECT_LOCK (demux);
398 demux->segment_ts = GST_CLOCK_TIME_NONE;
399 demux->in_gap = GST_CLOCK_TIME_NONE;
400 demux->need_newsegment = TRUE;
401 demux->segment_seqnum = gst_event_get_seqnum (event);
402 gst_asf_demux_reset_stream_state_after_discont (demux);
403 GST_OBJECT_UNLOCK (demux);
405 gst_event_unref (event);
411 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
412 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
413 (_("This stream contains no data.")),
414 ("got eos and didn't receive a complete header object"));
417 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
418 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
419 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
420 (_("Internal data stream error.")),
421 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
425 GST_OBJECT_LOCK (demux);
426 gst_adapter_clear (demux->adapter);
427 GST_OBJECT_UNLOCK (demux);
428 gst_asf_demux_send_event_unlocked (demux, event);
432 case GST_EVENT_FLUSH_STOP:
433 GST_OBJECT_LOCK (demux);
434 gst_asf_demux_reset_stream_state_after_discont (demux);
435 GST_OBJECT_UNLOCK (demux);
436 gst_asf_demux_send_event_unlocked (demux, event);
437 /* upon activation, latency is no longer introduced, e.g. after seek */
438 if (demux->activated_streams)
443 ret = gst_pad_event_default (pad, parent, event);
451 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
452 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
453 gboolean next, gboolean * eos)
455 GstClockTime idx_time;
461 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
464 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
467 /* if we want the next keyframe, we have to go forward till we find
468 a different packet number */
470 if (idx >= demux->sidx_num_entries - 1) {
471 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
476 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
477 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
484 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
490 *packet = demux->sidx_entries[idx].packet;
492 *speed = demux->sidx_entries[idx].count;
494 /* so we get closer to the actual time of the packet ... actually, let's not
495 * do this, since we throw away superfluous payloads before the seek position
496 * anyway; this way, our key unit seek 'snap resolution' is a bit better
497 * (ie. same as index resolution) */
499 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
503 idx_time = demux->sidx_interval * idx;
504 if (G_LIKELY (idx_time >= demux->preroll))
505 idx_time -= demux->preroll;
507 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
508 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
509 GST_TIME_ARGS (idx_time));
511 if (G_LIKELY (p_idx_time))
512 *p_idx_time = idx_time;
518 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
522 gst_adapter_clear (demux->adapter);
524 GST_DEBUG_OBJECT (demux, "reset stream state");
526 for (n = 0; n < demux->num_streams; n++) {
527 demux->stream[n].discont = TRUE;
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 if (cur_type != GST_SEEK_TYPE_SET)
723 seek_time = segment.start;
727 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
728 * real start of data and segment_start to indexed time for key unit seek*/
729 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
730 &idx_time, &speed_count, next, &eos))) {
734 demux->packet = demux->num_packets;
738 /* First try to query our source to see if it can convert for us. This is
739 the case when our source is an mms stream, notice that in this case
740 gstmms will do a time based seek to get the byte offset, this is not a
741 problem as the seek to this offset needs to happen anway. */
742 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
743 GST_FORMAT_BYTES, &offset)) {
744 packet = (offset - demux->data_offset) / demux->packet_size;
745 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
746 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
747 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
748 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
749 demux->packet_size, packet);
751 /* FIXME: For streams containing video, seek to an earlier position in
752 * the hope of hitting a keyframe and let the sinks throw away the stuff
753 * before the segment start. For audio-only this is unnecessary as every
755 if (flush && (demux->accurate || (keyunit_sync && !next))
756 && demux->num_video_streams > 0) {
757 seek_time -= 5 * GST_SECOND;
762 packet = (guint) gst_util_uint64_scale (demux->num_packets,
763 seek_time, demux->play_time);
765 if (packet > demux->num_packets)
766 packet = demux->num_packets;
769 if (G_LIKELY (keyunit_sync)) {
770 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
771 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
772 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
773 segment.start = idx_time;
774 segment.position = idx_time;
775 segment.time = idx_time;
779 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
781 GST_OBJECT_LOCK (demux);
782 demux->segment = segment;
783 demux->packet = packet;
784 demux->need_newsegment = TRUE;
785 demux->segment_seqnum = seqnum;
786 demux->speed_packets = speed_count;
787 gst_asf_demux_reset_stream_state_after_discont (demux);
788 GST_OBJECT_UNLOCK (demux);
791 /* restart our task since it might have been stopped when we did the flush */
792 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
795 /* streaming can continue now */
796 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
802 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
808 demux = GST_ASF_DEMUX (parent);
810 switch (GST_EVENT_TYPE (event)) {
812 GST_LOG_OBJECT (pad, "seek event");
813 ret = gst_asf_demux_handle_seek_event (demux, event);
814 gst_event_unref (event);
817 case GST_EVENT_NAVIGATION:
818 /* just drop these two silently */
819 gst_event_unref (event);
823 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
824 ret = gst_pad_event_default (pad, parent, event);
831 static inline guint32
832 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
836 ret = gst_asf_identify_guid (guids, guid);
838 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
839 gst_asf_get_guid_nick (guids, ret),
840 guid->v1, guid->v2, guid->v3, guid->v4);
852 /* expect is true when the user is expeting an object,
853 * when false, it will give no warnings if the object
857 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
858 guint data_len, AsfObject * object, gboolean expect)
862 if (data_len < ASF_OBJECT_HEADER_SIZE)
865 guid.v1 = GST_READ_UINT32_LE (data + 0);
866 guid.v2 = GST_READ_UINT32_LE (data + 4);
867 guid.v3 = GST_READ_UINT32_LE (data + 8);
868 guid.v4 = GST_READ_UINT32_LE (data + 12);
870 object->size = GST_READ_UINT64_LE (data + 16);
872 /* FIXME: make asf_demux_identify_object_guid() */
873 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
874 if (object->id == ASF_OBJ_UNDEFINED && expect) {
875 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
876 guid.v1, guid.v2, guid.v3, guid.v4);
883 gst_asf_demux_release_old_pads (GstASFDemux * demux)
885 GST_DEBUG_OBJECT (demux, "Releasing old pads");
887 while (demux->old_num_streams > 0) {
888 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
889 gst_event_new_eos ());
890 gst_asf_demux_free_stream (demux,
891 &demux->old_stream[demux->old_num_streams - 1]);
892 --demux->old_num_streams;
894 memset (demux->old_stream, 0, sizeof (demux->old_stream));
895 demux->old_num_streams = 0;
899 gst_asf_demux_chain_headers (GstASFDemux * demux)
903 guint8 *header_data, *data = NULL;
904 const guint8 *cdata = NULL;
907 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
911 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
912 if (obj.id != ASF_OBJ_HEADER)
915 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
917 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
918 if (gst_adapter_available (demux->adapter) < obj.size + 50)
921 data = gst_adapter_take (demux->adapter, obj.size + 50);
924 header_size = obj.size;
925 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
926 if (flow != GST_FLOW_OK)
929 /* calculate where the packet data starts */
930 demux->data_offset = obj.size + 50;
932 /* now parse the beginning of the ASF_OBJ_DATA object */
933 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
936 if (demux->num_streams == 0)
945 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
952 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
953 ("This doesn't seem to be an ASF file"));
955 return GST_FLOW_ERROR;
960 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
961 ("header parsing failed, or no streams found, flow = %s",
962 gst_flow_get_name (flow)));
964 return GST_FLOW_ERROR;
969 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
970 GstBuffer ** p_buf, GstFlowReturn * p_flow)
975 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
978 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
980 if (G_LIKELY (p_flow))
983 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
984 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
985 "+%u", gst_flow_get_name (flow), offset, size);
990 g_assert (*p_buf != NULL);
992 buffer_size = gst_buffer_get_size (*p_buf);
993 if (G_UNLIKELY (buffer_size < size)) {
994 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
995 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
996 gst_buffer_unref (*p_buf);
997 if (G_LIKELY (p_flow))
998 *p_flow = GST_FLOW_EOS;
1007 gst_asf_demux_pull_indices (GstASFDemux * demux)
1009 GstBuffer *buf = NULL;
1013 offset = demux->index_offset;
1015 if (G_UNLIKELY (offset == 0)) {
1016 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1020 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1026 gst_buffer_map (buf, &map, GST_MAP_READ);
1027 g_assert (map.size >= 16 + 8);
1028 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1029 gst_buffer_unmap (buf, &map);
1030 gst_buffer_replace (&buf, NULL);
1032 /* check for sanity */
1033 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1034 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1038 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1042 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1043 ", size %u", offset, (guint) obj.size);
1045 offset += obj.size; /* increase before _process_object changes it */
1047 gst_buffer_map (buf, &map, GST_MAP_READ);
1048 g_assert (map.size >= obj.size);
1049 bufdata = (guint8 *) map.data;
1050 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1051 gst_buffer_unmap (buf, &map);
1052 gst_buffer_replace (&buf, NULL);
1054 if (G_UNLIKELY (flow != GST_FLOW_OK))
1059 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1063 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1067 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1068 if (obj.id != ASF_OBJ_DATA) {
1069 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1073 demux->state = GST_ASF_DEMUX_STATE_DATA;
1075 if (!demux->broadcast && obj.size > 50) {
1076 demux->data_size = obj.size - 50;
1077 /* CHECKME: for at least one file this is off by +158 bytes?! */
1078 demux->index_offset = demux->data_offset + demux->data_size;
1080 demux->data_size = 0;
1081 demux->index_offset = 0;
1086 if (!demux->broadcast) {
1087 /* skip object header (24 bytes) and file GUID (16 bytes) */
1088 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1090 demux->num_packets = 0;
1093 if (demux->num_packets == 0)
1094 demux->seekable = FALSE;
1096 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1097 if (demux->data_size == 0 && demux->num_packets > 0) {
1098 demux->data_size = demux->num_packets * demux->packet_size;
1099 demux->index_offset = demux->data_offset + demux->data_size;
1102 /* process pending stream objects and create pads for those */
1103 gst_asf_demux_process_queued_extended_stream_objects (demux);
1105 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1106 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1107 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1108 demux->data_offset, demux->data_size, demux->index_offset);
1114 gst_asf_demux_pull_headers (GstASFDemux * demux)
1118 GstBuffer *buf = NULL;
1123 GST_LOG_OBJECT (demux, "reading headers");
1125 /* pull HEADER object header, so we know its size */
1126 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1129 gst_buffer_map (buf, &map, GST_MAP_READ);
1130 g_assert (map.size >= 16 + 8);
1131 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1132 gst_buffer_unmap (buf, &map);
1133 gst_buffer_replace (&buf, NULL);
1135 if (obj.id != ASF_OBJ_HEADER)
1138 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1140 /* pull HEADER object */
1141 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1145 size = obj.size; /* don't want obj.size changed */
1146 gst_buffer_map (buf, &map, GST_MAP_READ);
1147 g_assert (map.size >= size);
1148 bufdata = (guint8 *) map.data;
1149 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1150 gst_buffer_unmap (buf, &map);
1151 gst_buffer_replace (&buf, NULL);
1153 if (flow != GST_FLOW_OK) {
1154 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1158 /* calculate where the packet data starts */
1159 demux->data_offset = demux->base_offset + obj.size + 50;
1161 /* now pull beginning of DATA object before packet data */
1162 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1166 gst_buffer_map (buf, &map, GST_MAP_READ);
1167 g_assert (map.size >= size);
1168 bufdata = (guint8 *) map.data;
1169 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1172 if (demux->num_streams == 0)
1175 gst_buffer_unmap (buf, &map);
1176 gst_buffer_replace (&buf, NULL);
1184 gst_buffer_unmap (buf, &map);
1185 gst_buffer_replace (&buf, NULL);
1187 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1188 ("This doesn't seem to be an ASF file"));
1197 gst_buffer_unmap (buf, &map);
1198 gst_buffer_replace (&buf, NULL);
1199 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1205 all_streams_prerolled (GstASFDemux * demux)
1207 GstClockTime preroll_time;
1208 guint i, num_no_data = 0;
1210 /* Allow at least 500ms of preroll_time */
1211 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1213 /* returns TRUE as long as there isn't a stream which (a) has data queued
1214 * and (b) the timestamp of last piece of data queued is < demux->preroll
1215 * AND there is at least one other stream with data queued */
1216 for (i = 0; i < demux->num_streams; ++i) {
1217 AsfPayload *last_payload = NULL;
1221 stream = &demux->stream[i];
1222 if (G_UNLIKELY (stream->payloads->len == 0)) {
1224 GST_LOG_OBJECT (stream->pad, "no data queued");
1228 /* find last payload with timestamp */
1229 for (last_idx = stream->payloads->len - 1;
1230 last_idx >= 0 && (last_payload == NULL
1231 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1232 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1235 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1236 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1237 GST_TIME_ARGS (preroll_time));
1238 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1239 || last_payload->ts <= preroll_time)) {
1240 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1245 if (G_UNLIKELY (num_no_data > 0))
1253 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1258 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1261 /* check for each mutual exclusion group whether it affects this stream */
1262 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1263 if (*mes == stream->id) {
1264 /* we are in this group; let's check if we've already activated streams
1265 * that are in the same group (and hence mutually exclusive to this
1267 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1270 for (i = 0; i < demux->num_streams; ++i) {
1271 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1272 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1273 "to already active stream with ID %d", stream->id,
1274 demux->stream[i].id);
1279 /* we can only be in this group once, let's break out and move on to
1280 * the next mutual exclusion group */
1291 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1293 /* remember the first queued timestamp for the segment */
1294 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1295 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1296 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1297 GST_TIME_ARGS (demux->first_ts));
1298 demux->segment_ts = payload_ts;
1299 /* always note, but only determines segment when streaming */
1300 if (demux->streaming)
1301 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1302 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1303 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1308 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1310 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1311 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1314 /* go trhough each stream, find smallest timestamp */
1315 for (i = 0; i < demux->num_streams; ++i) {
1318 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1319 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1320 stream = &demux->stream[i];
1322 for (j = 0; j < stream->payloads->len; ++j) {
1323 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1324 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1325 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1326 || stream_min_ts > payload->ts)) {
1327 stream_min_ts = payload->ts;
1329 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1330 payload->ts > stream_min_ts &&
1331 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1332 || stream_min_ts2 > payload->ts)) {
1333 stream_min_ts2 = payload->ts;
1337 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1338 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1339 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1340 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1341 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1343 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1346 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1347 stream_min_ts = stream_min_ts2;
1349 /* if we don't have timestamp for this stream, wait for more data */
1350 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1353 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1354 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1355 first_ts = stream_min_ts;
1358 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1361 demux->first_ts = first_ts;
1363 /* update packets queued before we knew first timestamp */
1364 for (i = 0; i < demux->num_streams; ++i) {
1367 stream = &demux->stream[i];
1369 for (j = 0; j < stream->payloads->len; ++j) {
1370 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1371 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1372 if (payload->ts > first_ts)
1373 payload->ts -= first_ts;
1381 gst_asf_demux_check_segment_ts (demux, 0);
1387 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1389 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1390 and often set wrong, inspecting the data is the only way that seem to be working */
1391 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1392 GstCaps *caps = NULL;
1394 GstAdapter *adapter = gst_adapter_new ();
1396 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1398 AsfPayload *payload;
1401 payload = &g_array_index (stream->payloads, AsfPayload, i);
1402 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1403 len = gst_adapter_available (adapter);
1404 data = gst_adapter_map (adapter, len);
1408 #define MIN_LENGTH 128
1410 /* look for the sync points */
1412 if (len < MIN_LENGTH || /* give typefind something to work on */
1413 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1414 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1420 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1423 if (prob < GST_TYPE_FIND_LIKELY) {
1426 if (len > MIN_LENGTH)
1427 /* this wasn't it, look for another sync point */
1431 gst_adapter_unmap (adapter);
1434 gst_object_unref (adapter);
1437 gst_caps_take (&stream->caps, caps);
1445 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1449 if (demux->activated_streams)
1452 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1455 if (!all_streams_prerolled (demux) && !force) {
1456 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1460 for (i = 0; i < demux->num_streams; ++i) {
1461 AsfStream *stream = &demux->stream[i];
1463 if (stream->payloads->len > 0) {
1465 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1466 !stream->active && /* do not inspect active streams (caps were already set) */
1467 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1468 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1469 /* try to gather some more data */
1472 /* we don't check mutual exclusion stuff here; either we have data for
1473 * a stream, then we active it, or we don't, then we'll ignore it */
1474 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1475 gst_asf_demux_activate_stream (demux, stream);
1477 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1481 gst_asf_demux_release_old_pads (demux);
1483 demux->activated_streams = TRUE;
1484 GST_LOG_OBJECT (demux, "signalling no more pads");
1485 gst_element_no_more_pads (GST_ELEMENT (demux));
1489 /* returns the stream that has a complete payload with the lowest timestamp
1490 * queued, or NULL (we push things by timestamp because during the internal
1491 * prerolling we might accumulate more data then the external queues can take,
1492 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1494 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1496 AsfPayload *best_payload = NULL;
1497 AsfStream *best_stream = NULL;
1500 for (i = 0; i < demux->num_streams; ++i) {
1504 stream = &demux->stream[i];
1506 /* Don't push any data until we have at least one payload that falls within
1507 * the current segment. This way we can remove out-of-segment payloads that
1508 * don't need to be decoded after a seek, sending only data from the
1509 * keyframe directly before our segment start */
1510 if (stream->payloads->len > 0) {
1511 AsfPayload *payload = NULL;
1514 /* find last payload with timestamp */
1515 for (last_idx = stream->payloads->len - 1;
1516 last_idx >= 0 && (payload == NULL
1517 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1518 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1521 /* if this is first payload after seek we might need to update the segment */
1522 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1523 gst_asf_demux_check_segment_ts (demux, payload->ts);
1525 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1526 (payload->ts < demux->segment.start))) {
1527 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1528 GST_DEBUG_OBJECT (stream->pad,
1529 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1530 GST_TIME_ARGS (payload->ts));
1531 demux->segment.start = payload->ts;
1532 demux->segment.time = payload->ts;
1534 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1535 GST_TIME_FORMAT " which is before our segment start %"
1536 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1537 GST_TIME_ARGS (demux->segment.start));
1542 /* Now see if there's a complete payload queued for this stream */
1545 /* find first complete payload with timestamp */
1547 j < stream->payloads->len && (payload == NULL
1548 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1549 payload = &g_array_index (stream->payloads, AsfPayload, j);
1552 if (!gst_asf_payload_is_complete (payload))
1555 /* ... and whether its timestamp is lower than the current best */
1556 if (best_stream == NULL || best_payload->ts > payload->ts) {
1557 best_stream = stream;
1558 best_payload = payload;
1566 static GstFlowReturn
1567 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1570 GstFlowReturn ret = GST_FLOW_OK;
1572 if (G_UNLIKELY (!demux->activated_streams)) {
1573 if (!gst_asf_demux_check_activate_streams (demux, force))
1575 /* streams are now activated */
1578 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1579 AsfPayload *payload;
1581 /* wait until we had a chance to "lock on" some payload's timestamp */
1582 if (G_UNLIKELY (demux->need_newsegment
1583 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1586 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1588 /* do we need to send a newsegment event */
1589 if ((G_UNLIKELY (demux->need_newsegment))) {
1590 GstEvent *segment_event;
1592 /* safe default if insufficient upstream info */
1593 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1596 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1597 demux->segment.duration > 0) {
1598 /* slight HACK; prevent clipping of last bit */
1599 demux->segment.stop = demux->segment.duration + demux->in_gap;
1602 /* FIXME : only if ACCURATE ! */
1603 if (G_LIKELY (!demux->accurate
1604 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1605 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1606 GST_TIME_ARGS (payload->ts));
1607 demux->segment.start = payload->ts;
1608 demux->segment.time = payload->ts;
1611 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1614 /* note: we fix up all timestamps to start from 0, so this should be ok */
1615 segment_event = gst_event_new_segment (&demux->segment);
1616 if (demux->segment_seqnum)
1617 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1618 gst_asf_demux_send_event_unlocked (demux, segment_event);
1620 /* now post any global tags we may have found */
1621 if (demux->taglist == NULL) {
1622 demux->taglist = gst_tag_list_new_empty ();
1623 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1626 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1627 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1629 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1630 gst_asf_demux_send_event_unlocked (demux,
1631 gst_event_new_tag (demux->taglist));
1632 demux->taglist = NULL;
1634 demux->need_newsegment = FALSE;
1635 demux->segment_seqnum = 0;
1636 demux->segment_running = TRUE;
1639 /* Do we have tags pending for this stream? */
1640 if (G_UNLIKELY (stream->pending_tags)) {
1641 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1642 gst_pad_push_event (stream->pad,
1643 gst_event_new_tag (stream->pending_tags));
1644 stream->pending_tags = NULL;
1647 /* We have the whole packet now so we should push the packet to
1648 * the src pad now. First though we should check if we need to do
1650 if (G_UNLIKELY (stream->span > 1)) {
1651 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1654 payload->buf = gst_buffer_make_writable (payload->buf);
1656 if (G_LIKELY (!payload->keyframe)) {
1657 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1660 if (G_UNLIKELY (stream->discont)) {
1661 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1662 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1663 stream->discont = FALSE;
1666 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1667 (payload->par_x != stream->par_x) &&
1668 (payload->par_y != stream->par_y))) {
1669 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1670 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1671 stream->par_x = payload->par_x;
1672 stream->par_y = payload->par_y;
1673 stream->caps = gst_caps_make_writable (stream->caps);
1674 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1675 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1676 gst_pad_set_caps (stream->pad, stream->caps);
1679 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1680 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1681 payload->interlaced);
1682 stream->interlaced = payload->interlaced;
1683 stream->caps = gst_caps_make_writable (stream->caps);
1684 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1685 (stream->interlaced ? "mixed" : "progressive"), NULL);
1686 gst_pad_set_caps (stream->pad, stream->caps);
1689 /* (sort of) interpolate timestamps using upstream "frame of reference",
1690 * typically useful for live src, but might (unavoidably) mess with
1691 * position reporting if a live src is playing not so live content
1692 * (e.g. rtspsrc taking some time to fall back to tcp) */
1693 GST_BUFFER_PTS (payload->buf) = payload->ts;
1694 if (GST_BUFFER_PTS_IS_VALID (payload->buf)) {
1695 GST_BUFFER_PTS (payload->buf) += demux->in_gap;
1697 if (payload->duration == GST_CLOCK_TIME_NONE
1698 && stream->ext_props.avg_time_per_frame != 0)
1699 GST_BUFFER_DURATION (payload->buf) =
1700 stream->ext_props.avg_time_per_frame * 100;
1702 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1704 /* FIXME: we should really set durations on buffers if we can */
1706 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1709 if (stream->active) {
1710 ret = gst_pad_push (stream->pad, payload->buf);
1711 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
1713 gst_buffer_unref (payload->buf);
1716 payload->buf = NULL;
1717 g_array_remove_index (stream->payloads, 0);
1719 /* Break out as soon as we have an issue */
1720 if (G_UNLIKELY (ret != GST_FLOW_OK))
1728 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1732 g_assert (buf != NULL);
1734 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1736 gst_buffer_map (buf, &map, GST_MAP_READ);
1738 /* we return false on buffer too small */
1739 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1740 gst_buffer_unmap (buf, &map);
1744 /* check if it is a header */
1745 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1746 gst_buffer_unmap (buf, &map);
1747 if (obj.id == ASF_OBJ_HEADER) {
1754 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1756 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1757 GstFlowReturn ret = GST_FLOW_OK;
1758 GstBuffer *buf = NULL;
1759 gboolean header = FALSE;
1761 /* TODO maybe we should skip index objects after the data and look
1762 * further for a new header */
1763 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1764 g_assert (buf != NULL);
1765 /* check if it is a header */
1766 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1767 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1768 demux->base_offset = off;
1772 gst_buffer_unref (buf);
1779 gst_asf_demux_loop (GstASFDemux * demux)
1781 GstFlowReturn flow = GST_FLOW_OK;
1782 GstBuffer *buf = NULL;
1784 gboolean sent_eos = FALSE;
1786 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1787 if (!gst_asf_demux_pull_headers (demux)) {
1788 flow = GST_FLOW_ERROR;
1792 gst_asf_demux_pull_indices (demux);
1795 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1797 if (G_UNLIKELY (demux->num_packets != 0
1798 && demux->packet >= demux->num_packets))
1801 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1802 (guint) demux->num_packets);
1804 off = demux->data_offset + (demux->packet * demux->packet_size);
1806 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1807 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1808 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1809 if (flow == GST_FLOW_EOS)
1811 else if (flow == GST_FLOW_FLUSHING) {
1812 GST_DEBUG_OBJECT (demux, "Not fatal");
1818 if (G_LIKELY (demux->speed_packets == 1)) {
1819 GstAsfDemuxParsePacketError err;
1820 err = gst_asf_demux_parse_packet (demux, buf);
1821 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1822 /* when we don't know when the data object ends, we should check
1823 * for a chained asf */
1824 if (demux->num_packets == 0) {
1825 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1826 GST_INFO_OBJECT (demux, "Chained asf found");
1827 demux->base_offset = off;
1828 gst_asf_demux_reset (demux, TRUE);
1829 gst_buffer_unref (buf);
1833 /* FIXME: We should tally up fatal errors and error out only
1834 * after a few broken packets in a row? */
1836 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1837 gst_buffer_unref (buf);
1842 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1848 for (n = 0; n < demux->speed_packets; n++) {
1850 GstAsfDemuxParsePacketError err;
1853 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1854 n * demux->packet_size, demux->packet_size);
1855 err = gst_asf_demux_parse_packet (demux, sub);
1856 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1857 /* when we don't know when the data object ends, we should check
1858 * for a chained asf */
1859 if (demux->num_packets == 0) {
1860 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1861 GST_INFO_OBJECT (demux, "Chained asf found");
1862 demux->base_offset = off + n * demux->packet_size;
1863 gst_asf_demux_reset (demux, TRUE);
1864 gst_buffer_unref (sub);
1865 gst_buffer_unref (buf);
1869 /* FIXME: We should tally up fatal errors and error out only
1870 * after a few broken packets in a row? */
1872 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1876 gst_buffer_unref (sub);
1878 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1879 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1885 /* reset speed pull */
1886 demux->speed_packets = 1;
1889 gst_buffer_unref (buf);
1891 if (G_UNLIKELY (demux->num_packets > 0
1892 && demux->packet >= demux->num_packets)) {
1893 GST_LOG_OBJECT (demux, "reached EOS");
1897 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1898 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1902 /* check if we're at the end of the configured segment */
1903 /* FIXME: check if segment end reached etc. */
1909 /* if we haven't activated our streams yet, this might be because we have
1910 * less data queued than required for preroll; force stream activation and
1911 * send any pending payloads before sending EOS */
1912 if (!demux->activated_streams)
1913 gst_asf_demux_push_complete_payloads (demux, TRUE);
1915 /* we want to push an eos or post a segment-done in any case */
1916 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1919 /* for segment playback we need to post when (in stream time)
1920 * we stopped, this is either stop (when set) or the duration. */
1921 if ((stop = demux->segment.stop) == -1)
1922 stop = demux->segment.duration;
1924 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1925 gst_element_post_message (GST_ELEMENT_CAST (demux),
1926 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1928 gst_asf_demux_send_event_unlocked (demux,
1929 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1930 } else if (flow != GST_FLOW_EOS) {
1931 /* check if we have a chained asf, in case, we don't eos yet */
1932 if (gst_asf_demux_check_chained_asf (demux)) {
1933 GST_INFO_OBJECT (demux, "Chained ASF starting");
1934 gst_asf_demux_reset (demux, TRUE);
1938 /* normal playback, send EOS to all linked pads */
1939 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1940 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1942 /* ... and fall through to pause */
1946 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1947 gst_flow_get_name (flow));
1948 demux->segment_running = FALSE;
1949 gst_pad_pause_task (demux->sinkpad);
1951 /* For the error cases (not EOS) */
1953 if (flow == GST_FLOW_EOS)
1954 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1955 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1956 /* Post an error. Hopefully something else already has, but if not... */
1957 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1958 (_("Internal data stream error.")),
1959 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1968 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1969 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1970 flow = GST_FLOW_EOS;
1974 /* See FIXMEs above */
1977 gst_buffer_unref (buf);
1978 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1979 ("Error parsing ASF packet %u", (guint) demux->packet));
1980 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1981 flow = GST_FLOW_ERROR;
1987 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1988 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1989 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1992 gst_asf_demux_check_header (GstASFDemux * demux)
1995 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
1996 ASF_OBJECT_HEADER_SIZE);
1997 if (cdata == NULL) /* need more data */
1998 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2000 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2001 if (obj.id != ASF_OBJ_HEADER) {
2002 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2004 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2008 static GstFlowReturn
2009 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2011 GstFlowReturn ret = GST_FLOW_OK;
2014 demux = GST_ASF_DEMUX (parent);
2016 GST_LOG_OBJECT (demux,
2017 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2018 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2019 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2021 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2022 GST_DEBUG_OBJECT (demux, "received DISCONT");
2023 gst_asf_demux_mark_discont (demux);
2026 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2027 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2028 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2029 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2030 ", interpolation gap: %" GST_TIME_FORMAT,
2031 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2034 gst_adapter_push (demux->adapter, buf);
2036 switch (demux->state) {
2037 case GST_ASF_DEMUX_STATE_INDEX:{
2038 gint result = gst_asf_demux_check_header (demux);
2039 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2042 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2043 /* we don't care about this, probably an index */
2044 /* TODO maybe would be smarter to skip all the indices
2045 * until we got a new header or EOS to decide */
2046 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2049 GST_INFO_OBJECT (demux, "Chained asf starting");
2050 /* cleanup and get ready for a chained asf */
2051 gst_asf_demux_reset (demux, TRUE);
2055 case GST_ASF_DEMUX_STATE_HEADER:{
2056 ret = gst_asf_demux_chain_headers (demux);
2057 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2059 /* otherwise fall through */
2061 case GST_ASF_DEMUX_STATE_DATA:
2065 data_size = demux->packet_size;
2067 while (gst_adapter_available (demux->adapter) >= data_size) {
2069 GstAsfDemuxParsePacketError err;
2071 /* we don't know the length of the stream
2072 * check for a chained asf everytime */
2073 if (demux->num_packets == 0) {
2074 gint result = gst_asf_demux_check_header (demux);
2076 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2077 GST_INFO_OBJECT (demux, "Chained asf starting");
2078 /* cleanup and get ready for a chained asf */
2079 gst_asf_demux_reset (demux, TRUE);
2082 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2083 && demux->packet >= demux->num_packets)) {
2084 /* do not overshoot data section when streaming */
2088 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2090 /* FIXME: We should tally up fatal errors and error out only
2091 * after a few broken packets in a row? */
2092 err = gst_asf_demux_parse_packet (demux, buf);
2094 gst_buffer_unref (buf);
2096 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2097 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2099 GST_WARNING_OBJECT (demux, "Parse error");
2101 if (demux->packet >= 0)
2104 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2105 && demux->packet >= demux->num_packets)) {
2106 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2111 g_assert_not_reached ();
2115 if (ret != GST_FLOW_OK)
2116 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2122 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2128 static inline gboolean
2129 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2131 if (*p_size < num_bytes)
2134 *p_data += num_bytes;
2135 *p_size -= num_bytes;
2139 static inline guint8
2140 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2144 g_assert (*p_size >= 1);
2145 ret = GST_READ_UINT8 (*p_data);
2146 *p_data += sizeof (guint8);
2147 *p_size -= sizeof (guint8);
2151 static inline guint16
2152 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2156 g_assert (*p_size >= 2);
2157 ret = GST_READ_UINT16_LE (*p_data);
2158 *p_data += sizeof (guint16);
2159 *p_size -= sizeof (guint16);
2163 static inline guint32
2164 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2168 g_assert (*p_size >= 4);
2169 ret = GST_READ_UINT32_LE (*p_data);
2170 *p_data += sizeof (guint32);
2171 *p_size -= sizeof (guint32);
2175 static inline guint64
2176 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2180 g_assert (*p_size >= 8);
2181 ret = GST_READ_UINT64_LE (*p_data);
2182 *p_data += sizeof (guint64);
2183 *p_size -= sizeof (guint64);
2188 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2189 guint8 ** p_data, guint64 * p_size)
2193 if (*p_size < num_bytes_to_read)
2196 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2197 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2199 *p_data += num_bytes_to_read;
2200 *p_size -= num_bytes_to_read;
2206 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2207 guint8 ** p_data, guint64 * p_size)
2211 if (*p_size < num_bytes_to_read)
2214 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2215 *p_data += num_bytes_to_read;
2216 *p_size -= num_bytes_to_read;
2221 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2222 guint8 ** p_data, guint64 * p_size)
2232 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2235 *p_strlen = s_length;
2237 if (s_length == 0) {
2238 GST_WARNING ("zero-length string");
2239 *p_str = g_strdup ("");
2243 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2246 g_assert (s != NULL);
2248 /* just because They don't exist doesn't
2249 * mean They are not out to get you ... */
2250 if (s[s_length - 1] != '\0') {
2251 s = g_realloc (s, s_length + 1);
2255 *p_str = (gchar *) s;
2261 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2263 g_assert (*p_size >= 4 * sizeof (guint32));
2265 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2266 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2267 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2268 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2272 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2275 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2278 /* WAVEFORMATEX Structure */
2279 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2280 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2281 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2282 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2283 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2284 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2285 /* Codec specific data size */
2286 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2291 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2294 if (*p_size < (4 + 4 + 1 + 2))
2297 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2298 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2299 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2300 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2305 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2306 guint8 ** p_data, guint64 * p_size)
2308 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2311 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2312 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2313 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2314 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2315 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2316 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2317 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2318 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2319 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2320 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2321 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2326 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2330 for (i = 0; i < demux->num_streams; i++) {
2331 if (demux->stream[i].id == id)
2332 return &demux->stream[i];
2335 if (gst_asf_demux_is_unknown_stream (demux, id))
2336 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2341 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2342 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2346 gst_pad_use_fixed_caps (src_pad);
2347 gst_pad_set_caps (src_pad, caps);
2349 gst_pad_set_event_function (src_pad,
2350 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2351 gst_pad_set_query_function (src_pad,
2352 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2354 stream = &demux->stream[demux->num_streams];
2355 stream->caps = caps;
2356 stream->pad = src_pad;
2358 stream->fps_known = !is_video; /* bit hacky for audio */
2359 stream->is_video = is_video;
2360 stream->pending_tags = tags;
2361 stream->discont = TRUE;
2365 st = gst_caps_get_structure (caps, 0);
2366 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2367 par_x > 0 && par_y > 0) {
2368 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2369 stream->par_x = par_x;
2370 stream->par_y = par_y;
2374 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2376 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2377 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2379 ++demux->num_streams;
2381 stream->active = FALSE;
2387 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2388 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2390 GstTagList *tags = NULL;
2391 GstBuffer *extradata = NULL;
2394 guint16 size_left = 0;
2395 gchar *codec_name = NULL;
2398 size_left = audio->size;
2400 /* Create the audio pad */
2401 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2403 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2406 /* Swallow up any left over data and set up the
2407 * standard properties from the header info */
2409 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2410 "codec specific data", size_left);
2412 g_assert (size_left <= *p_size);
2413 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2416 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2417 * additional two bytes indicating extradata. */
2418 /* FIXME: Handle the channel reorder map here */
2419 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2420 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2423 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2424 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2427 /* Informing about that audio format we just added */
2429 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2430 g_free (codec_name);
2434 gst_buffer_unref (extradata);
2436 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2437 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2438 audio->codec_tag, tags);
2440 ++demux->num_audio_streams;
2442 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2446 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2447 asf_stream_video_format * video, guint16 id,
2448 guint8 ** p_data, guint64 * p_size)
2450 GstTagList *tags = NULL;
2451 GstStructure *caps_s;
2452 GstBuffer *extradata = NULL;
2457 gchar *codec_name = NULL;
2458 gint size_left = video->size - 40;
2460 /* Create the video pad */
2461 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2462 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2465 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2467 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2468 g_assert (size_left <= *p_size);
2469 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2472 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2474 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2475 caps = gst_riff_create_video_caps (video->tag, NULL,
2476 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2479 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2480 G_TYPE_UINT, video->tag, NULL);
2485 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2486 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2487 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2488 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2493 /* retry with the global metadata */
2494 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2495 demux->global_metadata);
2496 s = demux->global_metadata;
2497 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2498 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2499 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2500 if (ax > 0 && ay > 0)
2501 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2505 s = gst_caps_get_structure (caps, 0);
2506 gst_structure_remove_field (s, "framerate");
2509 caps_s = gst_caps_get_structure (caps, 0);
2511 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2512 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2513 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2514 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2519 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2520 g_free (codec_name);
2524 gst_buffer_unref (extradata);
2526 GST_INFO ("Adding video stream #%u, id %u, codec %"
2527 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2528 GST_FOURCC_ARGS (video->tag), video->tag);
2530 ++demux->num_video_streams;
2532 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2536 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2538 if (!stream->active) {
2542 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2543 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2544 gst_pad_set_active (stream->pad, TRUE);
2547 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2548 "%03u", stream->id);
2551 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2553 if (gst_event_parse_group_id (event, &demux->group_id))
2554 demux->have_group_id = TRUE;
2556 demux->have_group_id = FALSE;
2557 gst_event_unref (event);
2558 } else if (!demux->have_group_id) {
2559 demux->have_group_id = TRUE;
2560 demux->group_id = gst_util_group_id_next ();
2563 event = gst_event_new_stream_start (stream_id);
2564 if (demux->have_group_id)
2565 gst_event_set_group_id (event, demux->group_id);
2567 gst_pad_push_event (stream->pad, event);
2569 gst_pad_set_caps (stream->pad, stream->caps);
2571 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2572 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2573 stream->active = TRUE;
2578 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2581 AsfCorrectionType correction_type;
2582 AsfStreamType stream_type;
2583 GstClockTime time_offset;
2584 gboolean is_encrypted G_GNUC_UNUSED;
2588 guint stream_specific_size;
2589 guint type_specific_size G_GNUC_UNUSED;
2590 guint unknown G_GNUC_UNUSED;
2591 gboolean inspect_payload = FALSE;
2592 AsfStream *stream = NULL;
2594 /* Get the rest of the header's header */
2595 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2596 goto not_enough_data;
2598 gst_asf_demux_get_guid (&guid, &data, &size);
2599 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2601 gst_asf_demux_get_guid (&guid, &data, &size);
2602 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2604 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2606 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2607 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2609 flags = gst_asf_demux_get_uint16 (&data, &size);
2610 stream_id = flags & 0x7f;
2611 is_encrypted = ! !((flags & 0x8000) << 15);
2612 unknown = gst_asf_demux_get_uint32 (&data, &size);
2614 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2615 stream_id, GST_TIME_ARGS (time_offset));
2617 /* dvr-ms has audio stream declared in stream specific data */
2618 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2619 AsfExtStreamType ext_stream_type;
2620 gst_asf_demux_get_guid (&guid, &data, &size);
2621 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2623 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2624 inspect_payload = TRUE;
2626 gst_asf_demux_get_guid (&guid, &data, &size);
2627 gst_asf_demux_get_uint32 (&data, &size);
2628 gst_asf_demux_get_uint32 (&data, &size);
2629 gst_asf_demux_get_uint32 (&data, &size);
2630 gst_asf_demux_get_guid (&guid, &data, &size);
2631 gst_asf_demux_get_uint32 (&data, &size);
2632 stream_type = ASF_STREAM_AUDIO;
2636 switch (stream_type) {
2637 case ASF_STREAM_AUDIO:{
2638 asf_stream_audio audio_object;
2640 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2641 goto not_enough_data;
2643 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2646 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2649 switch (correction_type) {
2650 case ASF_CORRECTION_ON:{
2651 guint span, packet_size, chunk_size, data_size, silence_data;
2653 GST_INFO ("Using error correction");
2655 if (size < (1 + 2 + 2 + 2 + 1))
2656 goto not_enough_data;
2658 span = gst_asf_demux_get_uint8 (&data, &size);
2659 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2660 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2661 data_size = gst_asf_demux_get_uint16 (&data, &size);
2662 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2664 stream->span = span;
2666 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2667 packet_size, chunk_size, data_size, span, silence_data);
2669 if (stream->span > 1) {
2670 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2671 /* Disable descrambling */
2674 /* FIXME: this else branch was added for
2675 * weird_al_yankovic - the saga begins.asf */
2676 stream->ds_packet_size = packet_size;
2677 stream->ds_chunk_size = chunk_size;
2680 /* Descambling is enabled */
2681 stream->ds_packet_size = packet_size;
2682 stream->ds_chunk_size = chunk_size;
2685 /* Now skip the rest of the silence data */
2687 gst_bytestream_flush (demux->bs, data_size - 1);
2689 /* FIXME: CHECKME. And why -1? */
2690 if (data_size > 1) {
2691 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2692 goto not_enough_data;
2698 case ASF_CORRECTION_OFF:{
2699 GST_INFO ("Error correction off");
2700 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2701 goto not_enough_data;
2705 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2706 ("Audio stream using unknown error correction"));
2713 case ASF_STREAM_VIDEO:{
2714 asf_stream_video_format video_format_object;
2715 asf_stream_video video_object;
2718 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2719 goto not_enough_data;
2721 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2723 GST_INFO ("object is a video stream with %u bytes of "
2724 "additional data", vsize);
2726 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2728 goto not_enough_data;
2731 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
2732 stream_id, &data, &size);
2738 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2740 demux->other_streams =
2741 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
2746 stream->inspect_payload = inspect_payload;
2751 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2752 /* we'll error out later if we found no streams */
2757 static const gchar *
2758 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2762 const gchar *asf_name;
2763 const gchar *gst_name;
2766 "WM/Genre", GST_TAG_GENRE}, {
2767 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2768 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2769 "WM/Picture", GST_TAG_IMAGE}, {
2770 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2771 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2772 "WM/Year", GST_TAG_DATE_TIME}
2773 /* { "WM/Composer", GST_TAG_COMPOSER } */
2778 if (name_utf8 == NULL) {
2779 GST_WARNING ("Failed to convert name to UTF8, skipping");
2783 out = strlen (name_utf8);
2785 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2786 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2787 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2788 return tags[i].gst_name;
2795 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2797 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2801 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2803 if (taglist == NULL)
2806 if (gst_tag_list_is_empty (taglist)) {
2807 gst_tag_list_unref (taglist);
2811 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2812 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
2814 gst_tag_list_unref (demux->taglist);
2815 gst_tag_list_unref (taglist);
2817 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2820 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2821 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2822 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2825 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2829 const guint8 *img_data = NULL;
2830 guint32 img_data_len = 0;
2831 guint8 pic_type = 0;
2833 gst_byte_reader_init (&r, tag_data, tag_data_len);
2835 /* skip mime type string (we don't trust it and do our own typefinding),
2836 * and also skip the description string, since we don't use it */
2837 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2838 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2839 !gst_byte_reader_skip_string_utf16 (&r) ||
2840 !gst_byte_reader_skip_string_utf16 (&r) ||
2841 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2842 goto not_enough_data;
2846 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2847 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2853 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2854 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2859 /* Extended Content Description Object */
2860 static GstFlowReturn
2861 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2864 /* Other known (and unused) 'text/unicode' metadata available :
2867 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2868 * WMFSDKVersion = 9.00.00.2980
2869 * WMFSDKNeeded = 0.0.0.0000
2870 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2871 * WM/Publisher = 4AD
2873 * WM/ProviderRating = 8
2874 * WM/ProviderStyle = Rock (similar to WM/Genre)
2875 * WM/GenreID (similar to WM/Genre)
2876 * WM/TrackNumber (same as WM/Track but as a string)
2878 * Other known (and unused) 'non-text' metadata available :
2884 * We might want to read WM/TrackNumber and use atoi() if we don't have
2888 GstTagList *taglist;
2889 guint16 blockcount, i;
2891 GST_INFO_OBJECT (demux, "object is an extended content description");
2893 taglist = gst_tag_list_new_empty ();
2895 /* Content Descriptor Count */
2897 goto not_enough_data;
2899 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2901 for (i = 1; i <= blockcount; ++i) {
2902 const gchar *gst_tag_name;
2906 GValue tag_value = { 0, };
2909 gchar *name_utf8 = NULL;
2913 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2914 goto not_enough_data;
2918 goto not_enough_data;
2920 /* Descriptor Value Data Type */
2921 datatype = gst_asf_demux_get_uint16 (&data, &size);
2923 /* Descriptor Value (not really a string, but same thing reading-wise) */
2924 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2926 goto not_enough_data;
2930 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2932 if (name_utf8 != NULL) {
2933 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2935 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2936 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2939 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2942 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2945 /* get rid of tags with empty value */
2946 if (value_utf8 != NULL && *value_utf8 != '\0') {
2947 GST_DEBUG ("string value %s", value_utf8);
2949 value_utf8[out] = '\0';
2951 if (gst_tag_name != NULL) {
2952 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
2953 guint year = atoi (value_utf8);
2956 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
2957 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
2959 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2960 guint id3v1_genre_id;
2961 const gchar *genre_str;
2963 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2964 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2965 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2966 g_free (value_utf8);
2967 value_utf8 = g_strdup (genre_str);
2972 /* convert tag from string to other type if required */
2973 tag_type = gst_tag_get_type (gst_tag_name);
2974 g_value_init (&tag_value, tag_type);
2975 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2976 GValue from_val = { 0, };
2978 g_value_init (&from_val, G_TYPE_STRING);
2979 g_value_set_string (&from_val, value_utf8);
2980 if (!g_value_transform (&from_val, &tag_value)) {
2981 GST_WARNING_OBJECT (demux,
2982 "Could not transform string tag to " "%s tag type %s",
2983 gst_tag_name, g_type_name (tag_type));
2984 g_value_unset (&tag_value);
2986 g_value_unset (&from_val);
2991 GST_DEBUG ("Setting metadata");
2992 g_value_init (&tag_value, G_TYPE_STRING);
2993 g_value_set_string (&tag_value, value_utf8);
2995 } else if (value_utf8 == NULL) {
2996 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2998 GST_DEBUG ("Skipping empty string value for %s",
2999 GST_STR_NULL (gst_tag_name));
3001 g_free (value_utf8);
3004 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3006 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3007 GST_FIXME ("Unhandled byte array tag %s",
3008 GST_STR_NULL (gst_tag_name));
3011 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3017 case ASF_DEMUX_DATA_TYPE_DWORD:{
3018 guint uint_val = GST_READ_UINT32_LE (value);
3020 /* this is the track number */
3021 g_value_init (&tag_value, G_TYPE_UINT);
3023 /* WM/Track counts from 0 */
3024 if (!strcmp (name_utf8, "WM/Track"))
3027 g_value_set_uint (&tag_value, uint_val);
3031 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3036 if (G_IS_VALUE (&tag_value)) {
3038 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3040 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3041 * is supposed to have a 0 base but is often wrongly written to start
3042 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3043 * replace the value added earlier from WM/Track or put it first in
3044 * the list, so that it will get picked up by _get_uint() */
3045 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3046 merge_mode = GST_TAG_MERGE_REPLACE;
3048 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3051 GST_DEBUG ("Setting global metadata %s", name_utf8);
3052 gst_structure_set_value (demux->global_metadata, name_utf8,
3056 g_value_unset (&tag_value);
3065 gst_asf_demux_add_global_tags (demux, taglist);
3072 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3073 gst_tag_list_unref (taglist);
3074 return GST_FLOW_OK; /* not really fatal */
3078 static GstStructure *
3079 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3084 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3086 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3089 s = gst_caps_get_structure (demux->metadata, i);
3090 if (gst_structure_has_name (s, sname))
3094 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3096 /* try lookup again; demux->metadata took ownership of the structure, so we
3097 * can't really make any assumptions about what happened to it, so we can't
3098 * just return it directly after appending it */
3099 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3102 static GstFlowReturn
3103 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3106 guint16 blockcount, i;
3108 GST_INFO_OBJECT (demux, "object is a metadata object");
3110 /* Content Descriptor Count */
3112 goto not_enough_data;
3114 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3116 for (i = 0; i < blockcount; ++i) {
3118 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3119 guint32 data_len, ival;
3122 if (size < (2 + 2 + 2 + 2 + 4))
3123 goto not_enough_data;
3125 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3126 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3127 name_len = gst_asf_demux_get_uint16 (&data, &size);
3128 data_type = gst_asf_demux_get_uint16 (&data, &size);
3129 data_len = gst_asf_demux_get_uint32 (&data, &size);
3131 if (size < name_len + data_len)
3132 goto not_enough_data;
3134 /* convert name to UTF-8 */
3135 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3137 gst_asf_demux_skip_bytes (name_len, &data, &size);
3139 if (name_utf8 == NULL) {
3140 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3141 gst_asf_demux_skip_bytes (data_len, &data, &size);
3145 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3146 gst_asf_demux_skip_bytes (data_len, &data, &size);
3154 goto not_enough_data;
3157 ival = gst_asf_demux_get_uint32 (&data, &size);
3159 /* skip anything else there may be, just in case */
3160 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3162 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3163 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3167 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3173 GST_WARNING ("Unexpected end of data parsing metadata object");
3174 return GST_FLOW_OK; /* not really fatal */
3178 static GstFlowReturn
3179 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3181 GstFlowReturn ret = GST_FLOW_OK;
3182 guint32 i, num_objects;
3183 guint8 unknown G_GNUC_UNUSED;
3185 /* Get the rest of the header's header */
3186 if (size < (4 + 1 + 1))
3187 goto not_enough_data;
3189 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3190 unknown = gst_asf_demux_get_uint8 (&data, &size);
3191 unknown = gst_asf_demux_get_uint8 (&data, &size);
3193 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3195 /* Loop through the header's objects, processing those */
3196 for (i = 0; i < num_objects; ++i) {
3197 GST_INFO_OBJECT (demux, "reading header part %u", i);
3198 ret = gst_asf_demux_process_object (demux, &data, &size);
3199 if (ret != GST_FLOW_OK) {
3200 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3209 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3210 ("short read parsing HEADER object"));
3211 return GST_FLOW_ERROR;
3215 static GstFlowReturn
3216 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3218 guint64 creation_time G_GNUC_UNUSED;
3219 guint64 file_size G_GNUC_UNUSED;
3220 guint64 send_time G_GNUC_UNUSED;
3221 guint64 packets_count, play_time, preroll;
3222 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3224 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3225 goto not_enough_data;
3227 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3228 file_size = gst_asf_demux_get_uint64 (&data, &size);
3229 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3230 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3231 play_time = gst_asf_demux_get_uint64 (&data, &size);
3232 send_time = gst_asf_demux_get_uint64 (&data, &size);
3233 preroll = gst_asf_demux_get_uint64 (&data, &size);
3234 flags = gst_asf_demux_get_uint32 (&data, &size);
3235 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3236 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3237 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3239 demux->broadcast = ! !(flags & 0x01);
3240 demux->seekable = ! !(flags & 0x02);
3242 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3243 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3244 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3246 if (demux->broadcast) {
3247 /* these fields are invalid if the broadcast flag is set */
3252 if (min_pktsize != max_pktsize)
3253 goto non_fixed_packet_size;
3255 demux->packet_size = max_pktsize;
3257 /* FIXME: do we need send_time as well? what is it? */
3258 if ((play_time * 100) >= (preroll * GST_MSECOND))
3259 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3261 demux->play_time = 0;
3263 demux->preroll = preroll * GST_MSECOND;
3265 /* initial latency */
3266 demux->latency = demux->preroll;
3268 if (demux->play_time == 0)
3269 demux->seekable = FALSE;
3271 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3272 GST_TIME_ARGS (demux->play_time));
3273 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3274 GST_TIME_ARGS (demux->preroll));
3276 if (demux->play_time > 0) {
3277 demux->segment.duration = demux->play_time;
3280 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3282 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3287 non_fixed_packet_size:
3289 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3290 ("packet size must be fixed"));
3291 return GST_FLOW_ERROR;
3295 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3296 ("short read parsing FILE object"));
3297 return GST_FLOW_ERROR;
3301 /* Content Description Object */
3302 static GstFlowReturn
3303 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3307 const gchar *gst_tag;
3312 GST_TAG_TITLE, 0, NULL}, {
3313 GST_TAG_ARTIST, 0, NULL}, {
3314 GST_TAG_COPYRIGHT, 0, NULL}, {
3315 GST_TAG_DESCRIPTION, 0, NULL}, {
3316 GST_TAG_COMMENT, 0, NULL}
3318 GstTagList *taglist;
3319 GValue value = { 0 };
3323 GST_INFO_OBJECT (demux, "object is a comment");
3325 if (size < (2 + 2 + 2 + 2 + 2))
3326 goto not_enough_data;
3328 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3329 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3330 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3331 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3332 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3334 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3335 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3336 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3338 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3339 if (size < tags[i].val_length)
3340 goto not_enough_data;
3342 /* might be just '/0', '/0'... */
3343 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3344 /* convert to UTF-8 */
3345 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3346 "UTF-8", "UTF-16LE", &in, &out, NULL);
3348 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3351 /* parse metadata into taglist */
3352 taglist = gst_tag_list_new_empty ();
3353 g_value_init (&value, G_TYPE_STRING);
3354 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3355 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3356 g_value_set_string (&value, tags[i].val_utf8);
3357 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3358 tags[i].gst_tag, &value, NULL);
3361 g_value_unset (&value);
3363 gst_asf_demux_add_global_tags (demux, taglist);
3365 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3366 g_free (tags[i].val_utf8);
3372 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3373 "comment tag section %d, skipping comment object", i);
3374 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3375 g_free (tags[i].val_utf8);
3376 return GST_FLOW_OK; /* not really fatal */
3380 static GstFlowReturn
3381 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3384 guint16 num_streams, i;
3388 goto not_enough_data;
3390 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3392 GST_INFO ("object is a bitrate properties object with %u streams",
3395 if (size < (num_streams * (2 + 4)))
3396 goto not_enough_data;
3398 for (i = 0; i < num_streams; ++i) {
3402 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3403 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3405 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3406 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3407 stream = gst_asf_demux_get_stream (demux, stream_id);
3409 if (stream->pending_tags == NULL) {
3410 stream->pending_tags =
3411 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3414 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3417 GST_WARNING ("stream id %u is too large", stream_id);
3425 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3426 return GST_FLOW_OK; /* not really fatal */
3430 static GstFlowReturn
3431 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3434 GstFlowReturn ret = GST_FLOW_OK;
3437 /* Get the rest of the header's header */
3438 if (size < (16 + 2 + 4))
3439 goto not_enough_data;
3441 /* skip GUID and two other bytes */
3442 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3443 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3445 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3447 /* FIXME: does data_size include the rest of the header that we have read? */
3448 if (hdr_size > size)
3449 goto not_enough_data;
3451 while (hdr_size > 0) {
3452 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3453 if (ret != GST_FLOW_OK)
3461 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3462 ("short read parsing extended header object"));
3463 return GST_FLOW_ERROR;
3467 static GstFlowReturn
3468 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3474 goto not_enough_data;
3476 if (demux->languages) {
3477 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3478 g_strfreev (demux->languages);
3479 demux->languages = NULL;
3480 demux->num_languages = 0;
3483 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3484 GST_LOG ("%u languages:", demux->num_languages);
3486 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3487 for (i = 0; i < demux->num_languages; ++i) {
3488 guint8 len, *lang_data = NULL;
3491 goto not_enough_data;
3492 len = gst_asf_demux_get_uint8 (&data, &size);
3493 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3496 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3499 /* truncate "en-us" etc. to just "en" */
3500 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3503 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3504 demux->languages[i] = utf8;
3507 goto not_enough_data;
3515 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3516 g_free (demux->languages);
3517 demux->languages = NULL;
3518 return GST_FLOW_OK; /* not fatal */
3522 static GstFlowReturn
3523 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3526 GstClockTime interval;
3529 if (size < (16 + 8 + 4 + 4))
3530 goto not_enough_data;
3533 gst_asf_demux_skip_bytes (16, &data, &size);
3534 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3535 gst_asf_demux_skip_bytes (4, &data, &size);
3536 count = gst_asf_demux_get_uint32 (&data, &size);
3538 demux->sidx_interval = interval;
3539 demux->sidx_num_entries = count;
3540 g_free (demux->sidx_entries);
3541 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3543 for (i = 0; i < count; ++i) {
3544 if (G_UNLIKELY (size < 6)) {
3545 /* adjust for broken files, to avoid having entries at the end
3546 * of the parsed index that point to time=0. Resulting in seeking to
3547 * the end of the file leading back to the beginning */
3548 demux->sidx_num_entries -= (count - i);
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 stream->ds_packet_size * stream->span)
4065 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4066 offset += stream->ds_chunk_size) {
4067 off = offset / stream->ds_chunk_size;
4068 row = off / stream->span;
4069 col = off % stream->span;
4070 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4071 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4072 col, off, stream->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 stream->span, stream->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_MEMORY,
4080 idx * stream->ds_chunk_size, stream->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;
4334 demux->flowcombiner = gst_flow_combiner_new ();
4341 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4342 if (ret == GST_STATE_CHANGE_FAILURE)
4345 switch (transition) {
4346 case GST_STATE_CHANGE_PAUSED_TO_READY:
4347 gst_asf_demux_reset (demux, FALSE);
4350 case GST_STATE_CHANGE_READY_TO_NULL:
4351 gst_asf_demux_reset (demux, FALSE);
4352 gst_flow_combiner_free (demux->flowcombiner);
4353 demux->flowcombiner = NULL;