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, ts=%" GST_TIME_FORMAT
1707 ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
1708 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1709 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1710 gst_buffer_get_size (payload->buf));
1712 if (stream->active) {
1713 ret = gst_pad_push (stream->pad, payload->buf);
1714 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
1716 gst_buffer_unref (payload->buf);
1719 payload->buf = NULL;
1720 g_array_remove_index (stream->payloads, 0);
1722 /* Break out as soon as we have an issue */
1723 if (G_UNLIKELY (ret != GST_FLOW_OK))
1731 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1735 g_assert (buf != NULL);
1737 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1739 gst_buffer_map (buf, &map, GST_MAP_READ);
1741 /* we return false on buffer too small */
1742 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1743 gst_buffer_unmap (buf, &map);
1747 /* check if it is a header */
1748 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1749 gst_buffer_unmap (buf, &map);
1750 if (obj.id == ASF_OBJ_HEADER) {
1757 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1759 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1760 GstFlowReturn ret = GST_FLOW_OK;
1761 GstBuffer *buf = NULL;
1762 gboolean header = FALSE;
1764 /* TODO maybe we should skip index objects after the data and look
1765 * further for a new header */
1766 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1767 g_assert (buf != NULL);
1768 /* check if it is a header */
1769 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1770 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1771 demux->base_offset = off;
1775 gst_buffer_unref (buf);
1782 gst_asf_demux_loop (GstASFDemux * demux)
1784 GstFlowReturn flow = GST_FLOW_OK;
1785 GstBuffer *buf = NULL;
1787 gboolean sent_eos = FALSE;
1789 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1790 if (!gst_asf_demux_pull_headers (demux)) {
1791 flow = GST_FLOW_ERROR;
1795 gst_asf_demux_pull_indices (demux);
1798 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1800 if (G_UNLIKELY (demux->num_packets != 0
1801 && demux->packet >= demux->num_packets))
1804 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1805 (guint) demux->num_packets);
1807 off = demux->data_offset + (demux->packet * demux->packet_size);
1809 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1810 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1811 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1812 if (flow == GST_FLOW_EOS)
1814 else if (flow == GST_FLOW_FLUSHING) {
1815 GST_DEBUG_OBJECT (demux, "Not fatal");
1821 if (G_LIKELY (demux->speed_packets == 1)) {
1822 GstAsfDemuxParsePacketError err;
1823 err = gst_asf_demux_parse_packet (demux, buf);
1824 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1825 /* when we don't know when the data object ends, we should check
1826 * for a chained asf */
1827 if (demux->num_packets == 0) {
1828 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1829 GST_INFO_OBJECT (demux, "Chained asf found");
1830 demux->base_offset = off;
1831 gst_asf_demux_reset (demux, TRUE);
1832 gst_buffer_unref (buf);
1836 /* FIXME: We should tally up fatal errors and error out only
1837 * after a few broken packets in a row? */
1839 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1840 gst_buffer_unref (buf);
1845 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1851 for (n = 0; n < demux->speed_packets; n++) {
1853 GstAsfDemuxParsePacketError err;
1856 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1857 n * demux->packet_size, demux->packet_size);
1858 err = gst_asf_demux_parse_packet (demux, sub);
1859 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1860 /* when we don't know when the data object ends, we should check
1861 * for a chained asf */
1862 if (demux->num_packets == 0) {
1863 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1864 GST_INFO_OBJECT (demux, "Chained asf found");
1865 demux->base_offset = off + n * demux->packet_size;
1866 gst_asf_demux_reset (demux, TRUE);
1867 gst_buffer_unref (sub);
1868 gst_buffer_unref (buf);
1872 /* FIXME: We should tally up fatal errors and error out only
1873 * after a few broken packets in a row? */
1875 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1879 gst_buffer_unref (sub);
1881 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1882 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1888 /* reset speed pull */
1889 demux->speed_packets = 1;
1892 gst_buffer_unref (buf);
1894 if (G_UNLIKELY (demux->num_packets > 0
1895 && demux->packet >= demux->num_packets)) {
1896 GST_LOG_OBJECT (demux, "reached EOS");
1900 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1901 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1905 /* check if we're at the end of the configured segment */
1906 /* FIXME: check if segment end reached etc. */
1912 /* if we haven't activated our streams yet, this might be because we have
1913 * less data queued than required for preroll; force stream activation and
1914 * send any pending payloads before sending EOS */
1915 if (!demux->activated_streams)
1916 gst_asf_demux_push_complete_payloads (demux, TRUE);
1918 /* we want to push an eos or post a segment-done in any case */
1919 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1922 /* for segment playback we need to post when (in stream time)
1923 * we stopped, this is either stop (when set) or the duration. */
1924 if ((stop = demux->segment.stop) == -1)
1925 stop = demux->segment.duration;
1927 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1928 gst_element_post_message (GST_ELEMENT_CAST (demux),
1929 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1931 gst_asf_demux_send_event_unlocked (demux,
1932 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1933 } else if (flow != GST_FLOW_EOS) {
1934 /* check if we have a chained asf, in case, we don't eos yet */
1935 if (gst_asf_demux_check_chained_asf (demux)) {
1936 GST_INFO_OBJECT (demux, "Chained ASF starting");
1937 gst_asf_demux_reset (demux, TRUE);
1941 /* normal playback, send EOS to all linked pads */
1942 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1943 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1945 /* ... and fall through to pause */
1949 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1950 gst_flow_get_name (flow));
1951 demux->segment_running = FALSE;
1952 gst_pad_pause_task (demux->sinkpad);
1954 /* For the error cases (not EOS) */
1956 if (flow == GST_FLOW_EOS)
1957 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1958 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1959 /* Post an error. Hopefully something else already has, but if not... */
1960 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1961 (_("Internal data stream error.")),
1962 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1971 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1972 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1973 flow = GST_FLOW_EOS;
1977 /* See FIXMEs above */
1980 gst_buffer_unref (buf);
1981 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1982 ("Error parsing ASF packet %u", (guint) demux->packet));
1983 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1984 flow = GST_FLOW_ERROR;
1990 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1991 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1992 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1995 gst_asf_demux_check_header (GstASFDemux * demux)
1998 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
1999 ASF_OBJECT_HEADER_SIZE);
2000 if (cdata == NULL) /* need more data */
2001 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2003 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2004 if (obj.id != ASF_OBJ_HEADER) {
2005 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2007 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2011 static GstFlowReturn
2012 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2014 GstFlowReturn ret = GST_FLOW_OK;
2017 demux = GST_ASF_DEMUX (parent);
2019 GST_LOG_OBJECT (demux,
2020 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2021 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2022 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2024 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2025 GST_DEBUG_OBJECT (demux, "received DISCONT");
2026 gst_asf_demux_mark_discont (demux);
2029 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2030 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2031 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2032 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2033 ", interpolation gap: %" GST_TIME_FORMAT,
2034 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2037 gst_adapter_push (demux->adapter, buf);
2039 switch (demux->state) {
2040 case GST_ASF_DEMUX_STATE_INDEX:{
2041 gint result = gst_asf_demux_check_header (demux);
2042 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2045 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2046 /* we don't care about this, probably an index */
2047 /* TODO maybe would be smarter to skip all the indices
2048 * until we got a new header or EOS to decide */
2049 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2052 GST_INFO_OBJECT (demux, "Chained asf starting");
2053 /* cleanup and get ready for a chained asf */
2054 gst_asf_demux_reset (demux, TRUE);
2058 case GST_ASF_DEMUX_STATE_HEADER:{
2059 ret = gst_asf_demux_chain_headers (demux);
2060 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2062 /* otherwise fall through */
2064 case GST_ASF_DEMUX_STATE_DATA:
2068 data_size = demux->packet_size;
2070 while (gst_adapter_available (demux->adapter) >= data_size) {
2072 GstAsfDemuxParsePacketError err;
2074 /* we don't know the length of the stream
2075 * check for a chained asf everytime */
2076 if (demux->num_packets == 0) {
2077 gint result = gst_asf_demux_check_header (demux);
2079 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2080 GST_INFO_OBJECT (demux, "Chained asf starting");
2081 /* cleanup and get ready for a chained asf */
2082 gst_asf_demux_reset (demux, TRUE);
2085 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2086 && demux->packet >= demux->num_packets)) {
2087 /* do not overshoot data section when streaming */
2091 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2093 /* FIXME: We should tally up fatal errors and error out only
2094 * after a few broken packets in a row? */
2095 err = gst_asf_demux_parse_packet (demux, buf);
2097 gst_buffer_unref (buf);
2099 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2100 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2102 GST_WARNING_OBJECT (demux, "Parse error");
2104 if (demux->packet >= 0)
2107 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2108 && demux->packet >= demux->num_packets)) {
2109 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2114 g_assert_not_reached ();
2118 if (ret != GST_FLOW_OK)
2119 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2125 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2131 static inline gboolean
2132 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2134 if (*p_size < num_bytes)
2137 *p_data += num_bytes;
2138 *p_size -= num_bytes;
2142 static inline guint8
2143 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2147 g_assert (*p_size >= 1);
2148 ret = GST_READ_UINT8 (*p_data);
2149 *p_data += sizeof (guint8);
2150 *p_size -= sizeof (guint8);
2154 static inline guint16
2155 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2159 g_assert (*p_size >= 2);
2160 ret = GST_READ_UINT16_LE (*p_data);
2161 *p_data += sizeof (guint16);
2162 *p_size -= sizeof (guint16);
2166 static inline guint32
2167 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2171 g_assert (*p_size >= 4);
2172 ret = GST_READ_UINT32_LE (*p_data);
2173 *p_data += sizeof (guint32);
2174 *p_size -= sizeof (guint32);
2178 static inline guint64
2179 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2183 g_assert (*p_size >= 8);
2184 ret = GST_READ_UINT64_LE (*p_data);
2185 *p_data += sizeof (guint64);
2186 *p_size -= sizeof (guint64);
2191 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2192 guint8 ** p_data, guint64 * p_size)
2196 if (*p_size < num_bytes_to_read)
2199 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2200 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2202 *p_data += num_bytes_to_read;
2203 *p_size -= num_bytes_to_read;
2209 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2210 guint8 ** p_data, guint64 * p_size)
2214 if (*p_size < num_bytes_to_read)
2217 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2218 *p_data += num_bytes_to_read;
2219 *p_size -= num_bytes_to_read;
2224 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2225 guint8 ** p_data, guint64 * p_size)
2235 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2238 *p_strlen = s_length;
2240 if (s_length == 0) {
2241 GST_WARNING ("zero-length string");
2242 *p_str = g_strdup ("");
2246 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2249 g_assert (s != NULL);
2251 /* just because They don't exist doesn't
2252 * mean They are not out to get you ... */
2253 if (s[s_length - 1] != '\0') {
2254 s = g_realloc (s, s_length + 1);
2258 *p_str = (gchar *) s;
2264 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2266 g_assert (*p_size >= 4 * sizeof (guint32));
2268 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2269 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2270 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2271 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2275 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2278 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2281 /* WAVEFORMATEX Structure */
2282 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2283 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2284 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2285 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2286 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2287 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2288 /* Codec specific data size */
2289 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2294 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2297 if (*p_size < (4 + 4 + 1 + 2))
2300 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2301 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2302 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2303 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2308 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2309 guint8 ** p_data, guint64 * p_size)
2311 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2314 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2315 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2316 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2317 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2318 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2319 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2320 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2321 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2322 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2323 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2324 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2329 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2333 for (i = 0; i < demux->num_streams; i++) {
2334 if (demux->stream[i].id == id)
2335 return &demux->stream[i];
2338 if (gst_asf_demux_is_unknown_stream (demux, id))
2339 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2344 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2345 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2349 gst_pad_use_fixed_caps (src_pad);
2350 gst_pad_set_caps (src_pad, caps);
2352 gst_pad_set_event_function (src_pad,
2353 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2354 gst_pad_set_query_function (src_pad,
2355 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2357 stream = &demux->stream[demux->num_streams];
2358 stream->caps = caps;
2359 stream->pad = src_pad;
2361 stream->fps_known = !is_video; /* bit hacky for audio */
2362 stream->is_video = is_video;
2363 stream->pending_tags = tags;
2364 stream->discont = TRUE;
2368 st = gst_caps_get_structure (caps, 0);
2369 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2370 par_x > 0 && par_y > 0) {
2371 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2372 stream->par_x = par_x;
2373 stream->par_y = par_y;
2377 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2379 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2380 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2382 ++demux->num_streams;
2384 stream->active = FALSE;
2390 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2391 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2393 GstTagList *tags = NULL;
2394 GstBuffer *extradata = NULL;
2397 guint16 size_left = 0;
2398 gchar *codec_name = NULL;
2401 size_left = audio->size;
2403 /* Create the audio pad */
2404 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2406 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2409 /* Swallow up any left over data and set up the
2410 * standard properties from the header info */
2412 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2413 "codec specific data", size_left);
2415 g_assert (size_left <= *p_size);
2416 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2419 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2420 * additional two bytes indicating extradata. */
2421 /* FIXME: Handle the channel reorder map here */
2422 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2423 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2426 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2427 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2430 /* Informing about that audio format we just added */
2432 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2433 g_free (codec_name);
2437 gst_buffer_unref (extradata);
2439 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2440 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2441 audio->codec_tag, tags);
2443 ++demux->num_audio_streams;
2445 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2449 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2450 asf_stream_video_format * video, guint16 id,
2451 guint8 ** p_data, guint64 * p_size)
2453 GstTagList *tags = NULL;
2454 GstStructure *caps_s;
2455 GstBuffer *extradata = NULL;
2460 gchar *codec_name = NULL;
2461 gint size_left = video->size - 40;
2463 /* Create the video pad */
2464 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2465 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2468 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2470 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2471 g_assert (size_left <= *p_size);
2472 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2475 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2477 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2478 caps = gst_riff_create_video_caps (video->tag, NULL,
2479 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2482 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2483 G_TYPE_UINT, video->tag, NULL);
2488 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2489 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2490 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2491 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2496 /* retry with the global metadata */
2497 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2498 demux->global_metadata);
2499 s = demux->global_metadata;
2500 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2501 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2502 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2503 if (ax > 0 && ay > 0)
2504 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2508 s = gst_caps_get_structure (caps, 0);
2509 gst_structure_remove_field (s, "framerate");
2512 caps_s = gst_caps_get_structure (caps, 0);
2514 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2515 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2516 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2517 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2522 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2523 g_free (codec_name);
2527 gst_buffer_unref (extradata);
2529 GST_INFO ("Adding video stream #%u, id %u, codec %"
2530 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2531 GST_FOURCC_ARGS (video->tag), video->tag);
2533 ++demux->num_video_streams;
2535 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2539 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2541 if (!stream->active) {
2545 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2546 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2547 gst_pad_set_active (stream->pad, TRUE);
2550 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2551 "%03u", stream->id);
2554 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2556 if (gst_event_parse_group_id (event, &demux->group_id))
2557 demux->have_group_id = TRUE;
2559 demux->have_group_id = FALSE;
2560 gst_event_unref (event);
2561 } else if (!demux->have_group_id) {
2562 demux->have_group_id = TRUE;
2563 demux->group_id = gst_util_group_id_next ();
2566 event = gst_event_new_stream_start (stream_id);
2567 if (demux->have_group_id)
2568 gst_event_set_group_id (event, demux->group_id);
2570 gst_pad_push_event (stream->pad, event);
2572 gst_pad_set_caps (stream->pad, stream->caps);
2574 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2575 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2576 stream->active = TRUE;
2581 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2584 AsfCorrectionType correction_type;
2585 AsfStreamType stream_type;
2586 GstClockTime time_offset;
2587 gboolean is_encrypted G_GNUC_UNUSED;
2591 guint stream_specific_size;
2592 guint type_specific_size G_GNUC_UNUSED;
2593 guint unknown G_GNUC_UNUSED;
2594 gboolean inspect_payload = FALSE;
2595 AsfStream *stream = NULL;
2597 /* Get the rest of the header's header */
2598 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2599 goto not_enough_data;
2601 gst_asf_demux_get_guid (&guid, &data, &size);
2602 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2604 gst_asf_demux_get_guid (&guid, &data, &size);
2605 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2607 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2609 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2610 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2612 flags = gst_asf_demux_get_uint16 (&data, &size);
2613 stream_id = flags & 0x7f;
2614 is_encrypted = ! !((flags & 0x8000) << 15);
2615 unknown = gst_asf_demux_get_uint32 (&data, &size);
2617 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2618 stream_id, GST_TIME_ARGS (time_offset));
2620 /* dvr-ms has audio stream declared in stream specific data */
2621 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2622 AsfExtStreamType ext_stream_type;
2623 gst_asf_demux_get_guid (&guid, &data, &size);
2624 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2626 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2627 inspect_payload = TRUE;
2629 gst_asf_demux_get_guid (&guid, &data, &size);
2630 gst_asf_demux_get_uint32 (&data, &size);
2631 gst_asf_demux_get_uint32 (&data, &size);
2632 gst_asf_demux_get_uint32 (&data, &size);
2633 gst_asf_demux_get_guid (&guid, &data, &size);
2634 gst_asf_demux_get_uint32 (&data, &size);
2635 stream_type = ASF_STREAM_AUDIO;
2639 switch (stream_type) {
2640 case ASF_STREAM_AUDIO:{
2641 asf_stream_audio audio_object;
2643 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2644 goto not_enough_data;
2646 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2649 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2652 switch (correction_type) {
2653 case ASF_CORRECTION_ON:{
2654 guint span, packet_size, chunk_size, data_size, silence_data;
2656 GST_INFO ("Using error correction");
2658 if (size < (1 + 2 + 2 + 2 + 1))
2659 goto not_enough_data;
2661 span = gst_asf_demux_get_uint8 (&data, &size);
2662 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2663 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2664 data_size = gst_asf_demux_get_uint16 (&data, &size);
2665 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2667 stream->span = span;
2669 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2670 packet_size, chunk_size, data_size, span, silence_data);
2672 if (stream->span > 1) {
2673 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2674 /* Disable descrambling */
2677 /* FIXME: this else branch was added for
2678 * weird_al_yankovic - the saga begins.asf */
2679 stream->ds_packet_size = packet_size;
2680 stream->ds_chunk_size = chunk_size;
2683 /* Descambling is enabled */
2684 stream->ds_packet_size = packet_size;
2685 stream->ds_chunk_size = chunk_size;
2688 /* Now skip the rest of the silence data */
2690 gst_bytestream_flush (demux->bs, data_size - 1);
2692 /* FIXME: CHECKME. And why -1? */
2693 if (data_size > 1) {
2694 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2695 goto not_enough_data;
2701 case ASF_CORRECTION_OFF:{
2702 GST_INFO ("Error correction off");
2703 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2704 goto not_enough_data;
2708 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2709 ("Audio stream using unknown error correction"));
2716 case ASF_STREAM_VIDEO:{
2717 asf_stream_video_format video_format_object;
2718 asf_stream_video video_object;
2721 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2722 goto not_enough_data;
2724 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2726 GST_INFO ("object is a video stream with %u bytes of "
2727 "additional data", vsize);
2729 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2731 goto not_enough_data;
2734 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
2735 stream_id, &data, &size);
2741 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2743 demux->other_streams =
2744 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
2749 stream->inspect_payload = inspect_payload;
2754 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2755 /* we'll error out later if we found no streams */
2760 static const gchar *
2761 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2765 const gchar *asf_name;
2766 const gchar *gst_name;
2769 "WM/Genre", GST_TAG_GENRE}, {
2770 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2771 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2772 "WM/Picture", GST_TAG_IMAGE}, {
2773 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2774 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2775 "WM/Year", GST_TAG_DATE_TIME}
2776 /* { "WM/Composer", GST_TAG_COMPOSER } */
2781 if (name_utf8 == NULL) {
2782 GST_WARNING ("Failed to convert name to UTF8, skipping");
2786 out = strlen (name_utf8);
2788 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2789 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2790 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2791 return tags[i].gst_name;
2798 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2800 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2804 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2806 if (taglist == NULL)
2809 if (gst_tag_list_is_empty (taglist)) {
2810 gst_tag_list_unref (taglist);
2814 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2815 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
2817 gst_tag_list_unref (demux->taglist);
2818 gst_tag_list_unref (taglist);
2820 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2823 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2824 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2825 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2828 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2832 const guint8 *img_data = NULL;
2833 guint32 img_data_len = 0;
2834 guint8 pic_type = 0;
2836 gst_byte_reader_init (&r, tag_data, tag_data_len);
2838 /* skip mime type string (we don't trust it and do our own typefinding),
2839 * and also skip the description string, since we don't use it */
2840 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2841 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2842 !gst_byte_reader_skip_string_utf16 (&r) ||
2843 !gst_byte_reader_skip_string_utf16 (&r) ||
2844 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2845 goto not_enough_data;
2849 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2850 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2856 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2857 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2862 /* Extended Content Description Object */
2863 static GstFlowReturn
2864 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2867 /* Other known (and unused) 'text/unicode' metadata available :
2870 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2871 * WMFSDKVersion = 9.00.00.2980
2872 * WMFSDKNeeded = 0.0.0.0000
2873 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2874 * WM/Publisher = 4AD
2876 * WM/ProviderRating = 8
2877 * WM/ProviderStyle = Rock (similar to WM/Genre)
2878 * WM/GenreID (similar to WM/Genre)
2879 * WM/TrackNumber (same as WM/Track but as a string)
2881 * Other known (and unused) 'non-text' metadata available :
2887 * We might want to read WM/TrackNumber and use atoi() if we don't have
2891 GstTagList *taglist;
2892 guint16 blockcount, i;
2894 GST_INFO_OBJECT (demux, "object is an extended content description");
2896 taglist = gst_tag_list_new_empty ();
2898 /* Content Descriptor Count */
2900 goto not_enough_data;
2902 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2904 for (i = 1; i <= blockcount; ++i) {
2905 const gchar *gst_tag_name;
2909 GValue tag_value = { 0, };
2912 gchar *name_utf8 = NULL;
2916 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2917 goto not_enough_data;
2921 goto not_enough_data;
2923 /* Descriptor Value Data Type */
2924 datatype = gst_asf_demux_get_uint16 (&data, &size);
2926 /* Descriptor Value (not really a string, but same thing reading-wise) */
2927 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2929 goto not_enough_data;
2933 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2935 if (name_utf8 != NULL) {
2936 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2938 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2939 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2942 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2945 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2948 /* get rid of tags with empty value */
2949 if (value_utf8 != NULL && *value_utf8 != '\0') {
2950 GST_DEBUG ("string value %s", value_utf8);
2952 value_utf8[out] = '\0';
2954 if (gst_tag_name != NULL) {
2955 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
2956 guint year = atoi (value_utf8);
2959 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
2960 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
2962 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2963 guint id3v1_genre_id;
2964 const gchar *genre_str;
2966 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2967 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2968 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2969 g_free (value_utf8);
2970 value_utf8 = g_strdup (genre_str);
2975 /* convert tag from string to other type if required */
2976 tag_type = gst_tag_get_type (gst_tag_name);
2977 g_value_init (&tag_value, tag_type);
2978 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2979 GValue from_val = { 0, };
2981 g_value_init (&from_val, G_TYPE_STRING);
2982 g_value_set_string (&from_val, value_utf8);
2983 if (!g_value_transform (&from_val, &tag_value)) {
2984 GST_WARNING_OBJECT (demux,
2985 "Could not transform string tag to " "%s tag type %s",
2986 gst_tag_name, g_type_name (tag_type));
2987 g_value_unset (&tag_value);
2989 g_value_unset (&from_val);
2994 GST_DEBUG ("Setting metadata");
2995 g_value_init (&tag_value, G_TYPE_STRING);
2996 g_value_set_string (&tag_value, value_utf8);
2998 } else if (value_utf8 == NULL) {
2999 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3001 GST_DEBUG ("Skipping empty string value for %s",
3002 GST_STR_NULL (gst_tag_name));
3004 g_free (value_utf8);
3007 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3009 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3010 GST_FIXME ("Unhandled byte array tag %s",
3011 GST_STR_NULL (gst_tag_name));
3014 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3020 case ASF_DEMUX_DATA_TYPE_DWORD:{
3021 guint uint_val = GST_READ_UINT32_LE (value);
3023 /* this is the track number */
3024 g_value_init (&tag_value, G_TYPE_UINT);
3026 /* WM/Track counts from 0 */
3027 if (!strcmp (name_utf8, "WM/Track"))
3030 g_value_set_uint (&tag_value, uint_val);
3034 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3039 if (G_IS_VALUE (&tag_value)) {
3041 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3043 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3044 * is supposed to have a 0 base but is often wrongly written to start
3045 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3046 * replace the value added earlier from WM/Track or put it first in
3047 * the list, so that it will get picked up by _get_uint() */
3048 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3049 merge_mode = GST_TAG_MERGE_REPLACE;
3051 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3054 GST_DEBUG ("Setting global metadata %s", name_utf8);
3055 gst_structure_set_value (demux->global_metadata, name_utf8,
3059 g_value_unset (&tag_value);
3068 gst_asf_demux_add_global_tags (demux, taglist);
3075 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3076 gst_tag_list_unref (taglist);
3077 return GST_FLOW_OK; /* not really fatal */
3081 static GstStructure *
3082 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3087 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3089 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3092 s = gst_caps_get_structure (demux->metadata, i);
3093 if (gst_structure_has_name (s, sname))
3097 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3099 /* try lookup again; demux->metadata took ownership of the structure, so we
3100 * can't really make any assumptions about what happened to it, so we can't
3101 * just return it directly after appending it */
3102 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3105 static GstFlowReturn
3106 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3109 guint16 blockcount, i;
3111 GST_INFO_OBJECT (demux, "object is a metadata object");
3113 /* Content Descriptor Count */
3115 goto not_enough_data;
3117 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3119 for (i = 0; i < blockcount; ++i) {
3121 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3122 guint32 data_len, ival;
3125 if (size < (2 + 2 + 2 + 2 + 4))
3126 goto not_enough_data;
3128 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3129 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3130 name_len = gst_asf_demux_get_uint16 (&data, &size);
3131 data_type = gst_asf_demux_get_uint16 (&data, &size);
3132 data_len = gst_asf_demux_get_uint32 (&data, &size);
3134 if (size < name_len + data_len)
3135 goto not_enough_data;
3137 /* convert name to UTF-8 */
3138 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3140 gst_asf_demux_skip_bytes (name_len, &data, &size);
3142 if (name_utf8 == NULL) {
3143 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3144 gst_asf_demux_skip_bytes (data_len, &data, &size);
3148 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3149 gst_asf_demux_skip_bytes (data_len, &data, &size);
3157 goto not_enough_data;
3160 ival = gst_asf_demux_get_uint32 (&data, &size);
3162 /* skip anything else there may be, just in case */
3163 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3165 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3166 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3170 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3176 GST_WARNING ("Unexpected end of data parsing metadata object");
3177 return GST_FLOW_OK; /* not really fatal */
3181 static GstFlowReturn
3182 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3184 GstFlowReturn ret = GST_FLOW_OK;
3185 guint32 i, num_objects;
3186 guint8 unknown G_GNUC_UNUSED;
3188 /* Get the rest of the header's header */
3189 if (size < (4 + 1 + 1))
3190 goto not_enough_data;
3192 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3193 unknown = gst_asf_demux_get_uint8 (&data, &size);
3194 unknown = gst_asf_demux_get_uint8 (&data, &size);
3196 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3198 /* Loop through the header's objects, processing those */
3199 for (i = 0; i < num_objects; ++i) {
3200 GST_INFO_OBJECT (demux, "reading header part %u", i);
3201 ret = gst_asf_demux_process_object (demux, &data, &size);
3202 if (ret != GST_FLOW_OK) {
3203 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3212 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3213 ("short read parsing HEADER object"));
3214 return GST_FLOW_ERROR;
3218 static GstFlowReturn
3219 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3221 guint64 creation_time G_GNUC_UNUSED;
3222 guint64 file_size G_GNUC_UNUSED;
3223 guint64 send_time G_GNUC_UNUSED;
3224 guint64 packets_count, play_time, preroll;
3225 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3227 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3228 goto not_enough_data;
3230 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3231 file_size = gst_asf_demux_get_uint64 (&data, &size);
3232 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3233 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3234 play_time = gst_asf_demux_get_uint64 (&data, &size);
3235 send_time = gst_asf_demux_get_uint64 (&data, &size);
3236 preroll = gst_asf_demux_get_uint64 (&data, &size);
3237 flags = gst_asf_demux_get_uint32 (&data, &size);
3238 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3239 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3240 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3242 demux->broadcast = ! !(flags & 0x01);
3243 demux->seekable = ! !(flags & 0x02);
3245 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3246 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3247 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3249 if (demux->broadcast) {
3250 /* these fields are invalid if the broadcast flag is set */
3255 if (min_pktsize != max_pktsize)
3256 goto non_fixed_packet_size;
3258 demux->packet_size = max_pktsize;
3260 /* FIXME: do we need send_time as well? what is it? */
3261 if ((play_time * 100) >= (preroll * GST_MSECOND))
3262 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3264 demux->play_time = 0;
3266 demux->preroll = preroll * GST_MSECOND;
3268 /* initial latency */
3269 demux->latency = demux->preroll;
3271 if (demux->play_time == 0)
3272 demux->seekable = FALSE;
3274 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3275 GST_TIME_ARGS (demux->play_time));
3276 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3277 GST_TIME_ARGS (demux->preroll));
3279 if (demux->play_time > 0) {
3280 demux->segment.duration = demux->play_time;
3283 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3285 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3290 non_fixed_packet_size:
3292 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3293 ("packet size must be fixed"));
3294 return GST_FLOW_ERROR;
3298 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3299 ("short read parsing FILE object"));
3300 return GST_FLOW_ERROR;
3304 /* Content Description Object */
3305 static GstFlowReturn
3306 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3310 const gchar *gst_tag;
3315 GST_TAG_TITLE, 0, NULL}, {
3316 GST_TAG_ARTIST, 0, NULL}, {
3317 GST_TAG_COPYRIGHT, 0, NULL}, {
3318 GST_TAG_DESCRIPTION, 0, NULL}, {
3319 GST_TAG_COMMENT, 0, NULL}
3321 GstTagList *taglist;
3322 GValue value = { 0 };
3326 GST_INFO_OBJECT (demux, "object is a comment");
3328 if (size < (2 + 2 + 2 + 2 + 2))
3329 goto not_enough_data;
3331 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3332 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3333 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3334 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3335 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3337 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3338 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3339 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3341 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3342 if (size < tags[i].val_length)
3343 goto not_enough_data;
3345 /* might be just '/0', '/0'... */
3346 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3347 /* convert to UTF-8 */
3348 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3349 "UTF-8", "UTF-16LE", &in, &out, NULL);
3351 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3354 /* parse metadata into taglist */
3355 taglist = gst_tag_list_new_empty ();
3356 g_value_init (&value, G_TYPE_STRING);
3357 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3358 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3359 g_value_set_string (&value, tags[i].val_utf8);
3360 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3361 tags[i].gst_tag, &value, NULL);
3364 g_value_unset (&value);
3366 gst_asf_demux_add_global_tags (demux, taglist);
3368 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3369 g_free (tags[i].val_utf8);
3375 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3376 "comment tag section %d, skipping comment object", i);
3377 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3378 g_free (tags[i].val_utf8);
3379 return GST_FLOW_OK; /* not really fatal */
3383 static GstFlowReturn
3384 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3387 guint16 num_streams, i;
3391 goto not_enough_data;
3393 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3395 GST_INFO ("object is a bitrate properties object with %u streams",
3398 if (size < (num_streams * (2 + 4)))
3399 goto not_enough_data;
3401 for (i = 0; i < num_streams; ++i) {
3405 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3406 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3408 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3409 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3410 stream = gst_asf_demux_get_stream (demux, stream_id);
3412 if (stream->pending_tags == NULL) {
3413 stream->pending_tags =
3414 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3417 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3420 GST_WARNING ("stream id %u is too large", stream_id);
3428 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3429 return GST_FLOW_OK; /* not really fatal */
3433 static GstFlowReturn
3434 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3437 GstFlowReturn ret = GST_FLOW_OK;
3440 /* Get the rest of the header's header */
3441 if (size < (16 + 2 + 4))
3442 goto not_enough_data;
3444 /* skip GUID and two other bytes */
3445 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3446 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3448 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3450 /* FIXME: does data_size include the rest of the header that we have read? */
3451 if (hdr_size > size)
3452 goto not_enough_data;
3454 while (hdr_size > 0) {
3455 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3456 if (ret != GST_FLOW_OK)
3464 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3465 ("short read parsing extended header object"));
3466 return GST_FLOW_ERROR;
3470 static GstFlowReturn
3471 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3477 goto not_enough_data;
3479 if (demux->languages) {
3480 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3481 g_strfreev (demux->languages);
3482 demux->languages = NULL;
3483 demux->num_languages = 0;
3486 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3487 GST_LOG ("%u languages:", demux->num_languages);
3489 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3490 for (i = 0; i < demux->num_languages; ++i) {
3491 guint8 len, *lang_data = NULL;
3494 goto not_enough_data;
3495 len = gst_asf_demux_get_uint8 (&data, &size);
3496 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3499 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3502 /* truncate "en-us" etc. to just "en" */
3503 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3506 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3507 demux->languages[i] = utf8;
3510 goto not_enough_data;
3518 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3519 g_free (demux->languages);
3520 demux->languages = NULL;
3521 return GST_FLOW_OK; /* not fatal */
3525 static GstFlowReturn
3526 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3529 GstClockTime interval;
3532 if (size < (16 + 8 + 4 + 4))
3533 goto not_enough_data;
3536 gst_asf_demux_skip_bytes (16, &data, &size);
3537 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3538 gst_asf_demux_skip_bytes (4, &data, &size);
3539 count = gst_asf_demux_get_uint32 (&data, &size);
3541 demux->sidx_interval = interval;
3542 demux->sidx_num_entries = count;
3543 g_free (demux->sidx_entries);
3544 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3546 for (i = 0; i < count; ++i) {
3547 if (G_UNLIKELY (size < 6)) {
3548 /* adjust for broken files, to avoid having entries at the end
3549 * of the parsed index that point to time=0. Resulting in seeking to
3550 * the end of the file leading back to the beginning */
3551 demux->sidx_num_entries -= (count - i);
3554 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3555 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3556 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3557 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3558 demux->sidx_entries[i].count);
3561 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3568 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3569 return GST_FLOW_OK; /* not fatal */
3573 static GstFlowReturn
3574 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3575 guint8 * data, guint64 size)
3581 if (size < 16 + 2 + (2 * 2))
3582 goto not_enough_data;
3584 gst_asf_demux_get_guid (&guid, &data, &size);
3585 num = gst_asf_demux_get_uint16 (&data, &size);
3588 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3592 if (size < (num * sizeof (guint16)))
3593 goto not_enough_data;
3595 /* read mutually exclusive stream numbers */
3596 mes = g_new (guint8, num + 1);
3597 for (i = 0; i < num; ++i) {
3598 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3599 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3602 /* add terminator so we can easily get the count or know when to stop */
3603 mes[i] = (guint8) - 1;
3605 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3612 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3613 return GST_FLOW_OK; /* not absolutely fatal */
3618 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3620 return g_slist_find (demux->other_streams,
3621 GINT_TO_POINTER (stream_num)) == NULL;
3624 static GstFlowReturn
3625 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3628 AsfStreamExtProps esp;
3629 AsfStream *stream = NULL;
3630 AsfObject stream_obj;
3631 guint16 stream_name_count;
3632 guint16 num_payload_ext;
3634 guint8 *stream_obj_data = NULL;
3637 guint i, stream_num;
3640 obj_size = (guint) size;
3643 goto not_enough_data;
3646 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3647 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3648 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3649 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3650 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3651 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3652 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3653 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3654 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3655 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3656 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3657 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3658 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3659 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3660 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3662 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3663 GST_TIME_ARGS (esp.start_time));
3664 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3665 GST_TIME_ARGS (esp.end_time));
3666 GST_INFO ("flags = %08x", esp.flags);
3667 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3668 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3669 GST_INFO ("stream number = %u", stream_num);
3670 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3671 (esp.lang_idx < demux->num_languages) ?
3672 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3673 GST_INFO ("stream name count = %u", stream_name_count);
3675 /* read stream names */
3676 for (i = 0; i < stream_name_count; ++i) {
3677 guint16 stream_lang_idx G_GNUC_UNUSED;
3678 gchar *stream_name = NULL;
3681 goto not_enough_data;
3682 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3683 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3684 goto not_enough_data;
3685 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3686 g_free (stream_name); /* TODO: store names in struct */
3689 /* read payload extension systems stuff */
3690 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3692 if (num_payload_ext > 0)
3693 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3695 esp.payload_extensions = NULL;
3697 for (i = 0; i < num_payload_ext; ++i) {
3698 AsfPayloadExtension ext;
3700 guint32 sys_info_len;
3702 if (size < 16 + 2 + 4)
3703 goto not_enough_data;
3705 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3706 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3707 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3709 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3710 GST_LOG ("payload systems info len = %u", sys_info_len);
3711 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3712 goto not_enough_data;
3714 esp.payload_extensions[i] = ext;
3717 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3719 /* there might be an optional STREAM_INFO object here now; if not, we
3720 * should have parsed the corresponding stream info object already (since
3721 * we are parsing the extended stream properties objects delayed) */
3723 stream = gst_asf_demux_get_stream (demux, stream_num);
3727 /* get size of the stream object */
3728 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3729 goto not_enough_data;
3731 if (stream_obj.id != ASF_OBJ_STREAM)
3732 goto expected_stream_object;
3734 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3735 stream_obj.size > (10 * 1024 * 1024))
3736 goto not_enough_data;
3738 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3740 /* process this stream object later after all the other 'normal' ones
3741 * have been processed (since the others are more important/non-hidden) */
3742 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3743 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3744 goto not_enough_data;
3746 /* parse stream object */
3747 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3748 g_free (stream_obj_data);
3753 stream->ext_props = esp;
3755 /* try to set the framerate */
3756 if (stream->is_video && stream->caps) {
3757 GValue framerate = { 0 };
3761 g_value_init (&framerate, GST_TYPE_FRACTION);
3763 num = GST_SECOND / 100;
3764 denom = esp.avg_time_per_frame;
3766 /* avoid division by 0, assume 25/1 framerate */
3767 denom = GST_SECOND / 2500;
3770 gst_value_set_fraction (&framerate, num, denom);
3772 stream->caps = gst_caps_make_writable (stream->caps);
3773 s = gst_caps_get_structure (stream->caps, 0);
3774 gst_structure_set_value (s, "framerate", &framerate);
3775 g_value_unset (&framerate);
3776 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3777 num, denom, ((gdouble) num) / denom);
3780 /* add language info now if we have it */
3781 if (stream->ext_props.lang_idx < demux->num_languages) {
3782 if (stream->pending_tags == NULL)
3783 stream->pending_tags = gst_tag_list_new_empty ();
3784 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3785 demux->languages[stream->ext_props.lang_idx]);
3786 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3787 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3790 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
3791 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3799 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3800 return GST_FLOW_OK; /* not absolutely fatal */
3802 expected_stream_object:
3804 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3805 "object: expected embedded stream object, but got %s object instead!",
3806 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3807 return GST_FLOW_OK; /* not absolutely fatal */
3811 static const gchar *
3812 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3816 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3817 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3818 nick += strlen ("ASF_OBJ_");
3820 if (demux->objpath == NULL) {
3821 demux->objpath = g_strdup (nick);
3825 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3826 g_free (demux->objpath);
3827 demux->objpath = newpath;
3830 return (const gchar *) demux->objpath;
3834 gst_asf_demux_pop_obj (GstASFDemux * demux)
3838 if ((s = g_strrstr (demux->objpath, "/"))) {
3841 g_free (demux->objpath);
3842 demux->objpath = NULL;
3847 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3852 /* Parse the queued extended stream property objects and add the info
3853 * to the existing streams or add the new embedded streams, but without
3854 * activating them yet */
3855 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3856 g_slist_length (demux->ext_stream_props));
3858 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3859 GstBuffer *buf = GST_BUFFER (l->data);
3862 gst_buffer_map (buf, &map, GST_MAP_READ);
3864 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3865 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
3866 gst_buffer_unmap (buf, &map);
3867 gst_buffer_unref (buf);
3869 g_slist_free (demux->ext_stream_props);
3870 demux->ext_stream_props = NULL;
3875 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3879 for (i = 0; i < demux->num_streams; ++i) {
3884 stream = &demux->stream[i];
3886 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3888 if (stream->active) {
3889 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3894 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3897 /* check for each mutual exclusion whether it affects this stream */
3898 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3899 if (*mes == stream->id) {
3900 /* if yes, check if we've already added streams that are mutually
3901 * exclusive with the stream we're about to add */
3902 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3903 for (j = 0; j < demux->num_streams; ++j) {
3904 /* if the broadcast flag is set, assume the hidden streams aren't
3905 * actually streamed and hide them (or playbin won't work right),
3906 * otherwise assume their data is available */
3907 if (demux->stream[j].id == *mes && demux->broadcast) {
3909 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3910 "mutually exclusive with already existing stream ID %d, "
3911 "hiding stream", stream->id, demux->stream[j].id);
3923 /* FIXME: we should do stream activation based on preroll data in
3924 * streaming mode too */
3925 if (demux->streaming && !is_hidden)
3926 gst_asf_demux_activate_stream (demux, stream);
3931 static GstFlowReturn
3932 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3935 GstFlowReturn ret = GST_FLOW_OK;
3937 guint64 obj_data_size;
3939 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3940 return ASF_FLOW_NEED_MORE_DATA;
3942 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3943 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3945 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3947 if (*p_size < obj_data_size)
3948 return ASF_FLOW_NEED_MORE_DATA;
3950 gst_asf_demux_push_obj (demux, obj.id);
3952 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3955 case ASF_OBJ_STREAM:
3956 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3960 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3962 case ASF_OBJ_HEADER:
3963 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3965 case ASF_OBJ_COMMENT:
3966 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3969 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3971 case ASF_OBJ_BITRATE_PROPS:
3973 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3976 case ASF_OBJ_EXT_CONTENT_DESC:
3978 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3981 case ASF_OBJ_METADATA_OBJECT:
3982 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3984 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3987 /* process these later, we might not have parsed the corresponding
3988 * stream object yet */
3989 GST_LOG ("%s: queued for later parsing", demux->objpath);
3990 buf = gst_buffer_new_and_alloc (obj_data_size);
3991 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
3992 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3996 case ASF_OBJ_LANGUAGE_LIST:
3997 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3999 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4000 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4003 case ASF_OBJ_SIMPLE_INDEX:
4004 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4006 case ASF_OBJ_CONTENT_ENCRYPTION:
4007 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4008 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4009 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4010 goto error_encrypted;
4011 case ASF_OBJ_CONCEAL_NONE:
4013 case ASF_OBJ_UNDEFINED:
4014 case ASF_OBJ_CODEC_COMMENT:
4016 case ASF_OBJ_PADDING:
4017 case ASF_OBJ_BITRATE_MUTEX:
4018 case ASF_OBJ_COMPATIBILITY:
4019 case ASF_OBJ_INDEX_PLACEHOLDER:
4020 case ASF_OBJ_INDEX_PARAMETERS:
4021 case ASF_OBJ_STREAM_PRIORITIZATION:
4022 case ASF_OBJ_SCRIPT_COMMAND:
4024 /* Unknown/unhandled object, skip it and hope for the best */
4025 GST_INFO ("%s: skipping object", demux->objpath);
4030 /* this can't fail, we checked the number of bytes available before */
4031 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4033 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4035 gst_asf_demux_pop_obj (demux);
4042 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4043 return GST_FLOW_ERROR;
4048 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4049 GstBuffer ** p_buffer)
4051 GstBuffer *descrambled_buffer;
4052 GstBuffer *scrambled_buffer;
4053 GstBuffer *sub_buffer;
4060 /* descrambled_buffer is initialised in the first iteration */
4061 descrambled_buffer = NULL;
4062 scrambled_buffer = *p_buffer;
4064 if (gst_buffer_get_size (scrambled_buffer) <
4065 stream->ds_packet_size * stream->span)
4068 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4069 offset += stream->ds_chunk_size) {
4070 off = offset / stream->ds_chunk_size;
4071 row = off / stream->span;
4072 col = off % stream->span;
4073 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4074 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4075 col, off, stream->ds_chunk_size);
4076 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4077 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4078 stream->span, stream->ds_packet_size);
4079 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4080 gst_buffer_get_size (scrambled_buffer));
4082 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4083 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4085 descrambled_buffer = sub_buffer;
4087 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4091 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4092 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4093 GST_BUFFER_DURATION (descrambled_buffer) =
4094 GST_BUFFER_DURATION (scrambled_buffer);
4095 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4096 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4097 GST_BUFFER_OFFSET_END (scrambled_buffer);
4099 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4101 gst_buffer_unref (scrambled_buffer);
4102 *p_buffer = descrambled_buffer;
4106 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4108 GstASFDemux *demux = GST_ASF_DEMUX (element);
4111 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4113 for (i = 0; i < demux->num_streams; ++i) {
4114 gst_event_ref (event);
4115 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4116 GST_OBJECT_CAST (element), event)) {
4117 gst_event_unref (event);
4122 gst_event_unref (event);
4126 /* takes ownership of the passed event */
4128 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4130 gboolean ret = TRUE;
4133 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4134 GST_EVENT_TYPE_NAME (event));
4136 for (i = 0; i < demux->num_streams; ++i) {
4137 gst_event_ref (event);
4138 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4140 gst_event_unref (event);
4145 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4149 gboolean res = FALSE;
4151 demux = GST_ASF_DEMUX (parent);
4153 GST_DEBUG ("handling %s query",
4154 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4156 switch (GST_QUERY_TYPE (query)) {
4157 case GST_QUERY_DURATION:
4161 gst_query_parse_duration (query, &format, NULL);
4163 if (format != GST_FORMAT_TIME) {
4164 GST_LOG ("only support duration queries in TIME format");
4168 GST_OBJECT_LOCK (demux);
4170 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4171 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4172 GST_TIME_ARGS (demux->segment.duration));
4174 gst_query_set_duration (query, GST_FORMAT_TIME,
4175 demux->segment.duration);
4179 GST_LOG ("duration not known yet");
4182 GST_OBJECT_UNLOCK (demux);
4186 case GST_QUERY_POSITION:{
4189 gst_query_parse_position (query, &format, NULL);
4191 if (format != GST_FORMAT_TIME) {
4192 GST_LOG ("only support position queries in TIME format");
4196 GST_OBJECT_LOCK (demux);
4198 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4199 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4200 GST_TIME_ARGS (demux->segment.position));
4202 gst_query_set_position (query, GST_FORMAT_TIME,
4203 demux->segment.position);
4207 GST_LOG ("position not known yet");
4210 GST_OBJECT_UNLOCK (demux);
4214 case GST_QUERY_SEEKING:{
4217 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4218 if (format == GST_FORMAT_TIME) {
4221 GST_OBJECT_LOCK (demux);
4222 duration = demux->segment.duration;
4223 GST_OBJECT_UNLOCK (demux);
4225 if (!demux->streaming || !demux->seekable) {
4226 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4233 /* try downstream first in TIME */
4234 res = gst_pad_query_default (pad, parent, query);
4236 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4237 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4238 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4239 /* if no luck, maybe in BYTES */
4240 if (!seekable || fmt != GST_FORMAT_TIME) {
4243 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4244 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4245 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4246 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4247 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4248 if (fmt != GST_FORMAT_BYTES)
4251 gst_query_unref (q);
4252 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4258 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4262 case GST_QUERY_LATENCY:
4265 GstClockTime min, max;
4267 /* preroll delay does not matter in non-live pipeline,
4268 * but we might end up in a live (rtsp) one ... */
4271 res = gst_pad_query_default (pad, parent, query);
4275 gst_query_parse_latency (query, &live, &min, &max);
4277 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4278 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4279 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4281 GST_OBJECT_LOCK (demux);
4283 min += demux->latency;
4285 max += demux->latency;
4286 GST_OBJECT_UNLOCK (demux);
4288 gst_query_set_latency (query, live, min, max);
4291 case GST_QUERY_SEGMENT:
4296 format = demux->segment.format;
4299 gst_segment_to_stream_time (&demux->segment, format,
4300 demux->segment.start);
4301 if ((stop = demux->segment.stop) == -1)
4302 stop = demux->segment.duration;
4304 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4306 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4311 res = gst_pad_query_default (pad, parent, query);
4318 static GstStateChangeReturn
4319 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4321 GstASFDemux *demux = GST_ASF_DEMUX (element);
4322 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4324 switch (transition) {
4325 case GST_STATE_CHANGE_NULL_TO_READY:{
4326 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4327 demux->need_newsegment = TRUE;
4328 demux->segment_running = FALSE;
4329 demux->accurate = FALSE;
4330 demux->adapter = gst_adapter_new ();
4331 demux->metadata = gst_caps_new_empty ();
4332 demux->global_metadata = gst_structure_new_empty ("metadata");
4333 demux->data_size = 0;
4334 demux->data_offset = 0;
4335 demux->index_offset = 0;
4336 demux->base_offset = 0;
4337 demux->flowcombiner = gst_flow_combiner_new ();
4344 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4345 if (ret == GST_STATE_CHANGE_FAILURE)
4348 switch (transition) {
4349 case GST_STATE_CHANGE_PAUSED_TO_READY:
4350 gst_asf_demux_reset (demux, FALSE);
4353 case GST_STATE_CHANGE_READY_TO_NULL:
4354 gst_asf_demux_reset (demux, FALSE);
4355 gst_flow_combiner_free (demux->flowcombiner);
4356 demux->flowcombiner = NULL;