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., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, 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/riff/riff-media.h>
38 #include <gst/tag/tag.h>
39 #include <gst/gst-i18n-plugin.h>
44 #include "gstasfdemux.h"
45 #include "asfheaders.h"
46 #include "asfpacket.h"
48 static GstStaticPadTemplate gst_asf_demux_sink_template =
49 GST_STATIC_PAD_TEMPLATE ("sink",
52 GST_STATIC_CAPS ("video/x-ms-asf")
55 static GstStaticPadTemplate audio_src_template =
56 GST_STATIC_PAD_TEMPLATE ("audio_%u",
61 static GstStaticPadTemplate video_src_template =
62 GST_STATIC_PAD_TEMPLATE ("video_%u",
67 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
68 #define ASF_OBJECT_HEADER_SIZE (16+8)
70 /* FIXME: get rid of this */
71 /* abuse this GstFlowReturn enum for internal usage */
72 #define ASF_FLOW_NEED_MORE_DATA 99
74 #define gst_asf_get_flow_name(flow) \
75 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
76 "need-more-data" : gst_flow_get_name (flow)
78 GST_DEBUG_CATEGORY (asfdemux_dbg);
80 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
81 GstStateChange transition);
82 static gboolean gst_asf_demux_element_send_event (GstElement * element,
84 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
86 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
87 GstObject * parent, GstQuery * query);
88 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
90 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
92 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
93 guint8 ** p_data, guint64 * p_size);
94 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
95 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
96 GstObject * parent, GstPadMode mode, gboolean active);
97 static void gst_asf_demux_loop (GstASFDemux * demux);
99 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
100 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
101 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
102 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
104 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
105 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
106 AsfStream * stream, GstBuffer ** p_buffer);
107 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
109 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
111 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
114 #define gst_asf_demux_parent_class parent_class
115 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
118 gst_asf_demux_class_init (GstASFDemuxClass * klass)
120 GstElementClass *gstelement_class;
122 gstelement_class = (GstElementClass *) klass;
124 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
126 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
128 gst_element_class_add_pad_template (gstelement_class,
129 gst_static_pad_template_get (&audio_src_template));
130 gst_element_class_add_pad_template (gstelement_class,
131 gst_static_pad_template_get (&video_src_template));
132 gst_element_class_add_pad_template (gstelement_class,
133 gst_static_pad_template_get (&gst_asf_demux_sink_template));
135 gstelement_class->change_state =
136 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
137 gstelement_class->send_event =
138 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
142 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
144 gst_caps_replace (&stream->caps, NULL);
145 if (stream->pending_tags) {
146 gst_tag_list_free (stream->pending_tags);
147 stream->pending_tags = NULL;
151 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
153 gst_object_unref (stream->pad);
157 while (stream->payloads->len > 0) {
161 last = stream->payloads->len - 1;
162 payload = &g_array_index (stream->payloads, AsfPayload, last);
163 gst_buffer_replace (&payload->buf, NULL);
164 g_array_remove_index (stream->payloads, last);
166 if (stream->payloads) {
167 g_array_free (stream->payloads, TRUE);
168 stream->payloads = NULL;
170 if (stream->ext_props.valid) {
171 g_free (stream->ext_props.payload_extensions);
172 stream->ext_props.payload_extensions = NULL;
177 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
179 GST_LOG_OBJECT (demux, "resetting");
181 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
182 demux->segment_running = FALSE;
183 if (demux->adapter && !chain_reset) {
184 gst_adapter_clear (demux->adapter);
185 g_object_unref (demux->adapter);
186 demux->adapter = NULL;
188 if (demux->taglist) {
189 gst_tag_list_free (demux->taglist);
190 demux->taglist = NULL;
192 if (demux->metadata) {
193 gst_caps_unref (demux->metadata);
194 demux->metadata = NULL;
196 if (demux->global_metadata) {
197 gst_structure_free (demux->global_metadata);
198 demux->global_metadata = NULL;
201 demux->state = GST_ASF_DEMUX_STATE_HEADER;
202 g_free (demux->objpath);
203 demux->objpath = NULL;
204 g_strfreev (demux->languages);
205 demux->languages = NULL;
206 demux->num_languages = 0;
207 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
209 g_slist_free (demux->ext_stream_props);
210 demux->ext_stream_props = NULL;
212 while (demux->old_num_streams > 0) {
213 gst_asf_demux_free_stream (demux,
214 &demux->old_stream[demux->old_num_streams - 1]);
215 --demux->old_num_streams;
217 memset (demux->old_stream, 0, sizeof (demux->old_stream));
218 demux->old_num_streams = 0;
220 /* when resetting for a new chained asf, we don't want to remove the pads
221 * before adding the new ones */
223 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
224 demux->old_num_streams = demux->num_streams;
225 demux->num_streams = 0;
228 while (demux->num_streams > 0) {
229 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
230 --demux->num_streams;
232 memset (demux->stream, 0, sizeof (demux->stream));
234 /* do not remove those for not adding pads with same name */
235 demux->num_audio_streams = 0;
236 demux->num_video_streams = 0;
238 demux->num_streams = 0;
239 demux->activated_streams = FALSE;
240 demux->first_ts = GST_CLOCK_TIME_NONE;
241 demux->segment_ts = GST_CLOCK_TIME_NONE;
244 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
245 demux->state = GST_ASF_DEMUX_STATE_HEADER;
246 demux->seekable = FALSE;
247 demux->broadcast = FALSE;
248 demux->sidx_interval = 0;
249 demux->sidx_num_entries = 0;
250 g_free (demux->sidx_entries);
251 demux->sidx_entries = NULL;
253 demux->speed_packets = 1;
256 GST_LOG_OBJECT (demux, "Restarting");
257 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
258 demux->need_newsegment = TRUE;
259 demux->segment_running = FALSE;
260 demux->accurate = FALSE;
261 demux->metadata = gst_caps_new_empty ();
262 demux->global_metadata = gst_structure_new_empty ("metadata");
263 demux->data_size = 0;
264 demux->data_offset = 0;
265 demux->index_offset = 0;
267 demux->base_offset = 0;
272 gst_asf_demux_init (GstASFDemux * demux)
275 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
276 gst_pad_set_chain_function (demux->sinkpad,
277 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
278 gst_pad_set_event_function (demux->sinkpad,
279 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
280 gst_pad_set_activate_function (demux->sinkpad,
281 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
282 gst_pad_set_activatemode_function (demux->sinkpad,
283 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
284 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
286 /* set initial state */
287 gst_asf_demux_reset (demux, FALSE);
291 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
296 query = gst_query_new_scheduling ();
298 if (!gst_pad_peer_query (sinkpad, query)) {
299 gst_query_unref (query);
303 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
304 gst_query_unref (query);
309 GST_DEBUG_OBJECT (sinkpad, "activating pull");
310 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
314 GST_DEBUG_OBJECT (sinkpad, "activating push");
315 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
320 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
321 GstPadMode mode, gboolean active)
326 demux = GST_ASF_DEMUX (parent);
329 case GST_PAD_MODE_PUSH:
330 demux->state = GST_ASF_DEMUX_STATE_HEADER;
331 demux->streaming = TRUE;
334 case GST_PAD_MODE_PULL:
336 demux->state = GST_ASF_DEMUX_STATE_HEADER;
337 demux->streaming = FALSE;
339 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
342 res = gst_pad_stop_task (sinkpad);
353 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
358 demux = GST_ASF_DEMUX (parent);
360 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
361 switch (GST_EVENT_TYPE (event)) {
362 case GST_EVENT_SEGMENT:{
363 const GstSegment *segment;
365 gst_event_parse_segment (event, &segment);
367 if (segment->format == GST_FORMAT_BYTES) {
368 if (demux->packet_size && segment->start > demux->data_offset)
369 demux->packet = (segment->start - demux->data_offset) /
373 } else if (segment->format == GST_FORMAT_TIME) {
374 /* do not know packet position, not really a problem */
377 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
378 gst_event_unref (event);
382 /* record upstream segment for interpolation */
383 if (segment->format != demux->in_segment.format)
384 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
385 gst_segment_copy_into (segment, &demux->in_segment);
387 /* in either case, clear some state and generate newsegment later on */
388 GST_OBJECT_LOCK (demux);
389 demux->segment_ts = GST_CLOCK_TIME_NONE;
390 demux->in_gap = GST_CLOCK_TIME_NONE;
391 demux->need_newsegment = TRUE;
392 gst_asf_demux_reset_stream_state_after_discont (demux);
393 GST_OBJECT_UNLOCK (demux);
395 gst_event_unref (event);
401 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
402 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
403 (_("This stream contains no data.")),
404 ("got eos and didn't receive a complete header object"));
407 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
408 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
409 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
410 (_("Internal data stream error.")),
411 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
415 GST_OBJECT_LOCK (demux);
416 gst_adapter_clear (demux->adapter);
417 GST_OBJECT_UNLOCK (demux);
418 gst_asf_demux_send_event_unlocked (demux, event);
422 case GST_EVENT_FLUSH_STOP:
423 GST_OBJECT_LOCK (demux);
424 gst_asf_demux_reset_stream_state_after_discont (demux);
425 GST_OBJECT_UNLOCK (demux);
426 gst_asf_demux_send_event_unlocked (demux, event);
427 /* upon activation, latency is no longer introduced, e.g. after seek */
428 if (demux->activated_streams)
433 ret = gst_pad_event_default (pad, parent, event);
441 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
442 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
444 GstClockTime idx_time;
447 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
450 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
452 /* FIXME: seek beyond end of file should result in immediate EOS from
453 * streaming thread instead of a failed seek */
454 if (G_UNLIKELY (idx >= demux->sidx_num_entries))
457 *packet = demux->sidx_entries[idx].packet;
459 *speed = demux->sidx_entries[idx].count;
461 /* so we get closer to the actual time of the packet ... actually, let's not
462 * do this, since we throw away superfluous payloads before the seek position
463 * anyway; this way, our key unit seek 'snap resolution' is a bit better
464 * (ie. same as index resolution) */
466 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
470 idx_time = demux->sidx_interval * idx;
471 if (G_LIKELY (idx_time >= demux->preroll))
472 idx_time -= demux->preroll;
474 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
475 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
476 GST_TIME_ARGS (idx_time));
478 if (G_LIKELY (p_idx_time))
479 *p_idx_time = idx_time;
485 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
489 gst_adapter_clear (demux->adapter);
491 GST_DEBUG_OBJECT (demux, "reset stream state");
493 for (n = 0; n < demux->num_streams; n++) {
494 demux->stream[n].discont = TRUE;
495 demux->stream[n].last_flow = GST_FLOW_OK;
497 while (demux->stream[n].payloads->len > 0) {
501 last = demux->stream[n].payloads->len - 1;
502 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
503 gst_buffer_replace (&payload->buf, NULL);
504 g_array_remove_index (demux->stream[n].payloads, last);
510 gst_asf_demux_mark_discont (GstASFDemux * demux)
514 GST_DEBUG_OBJECT (demux, "Mark stream discont");
516 for (n = 0; n < demux->num_streams; n++)
517 demux->stream[n].discont = TRUE;
520 /* do a seek in push based mode */
522 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
527 GstSeekType cur_type, stop_type;
532 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
535 stop_type = GST_SEEK_TYPE_NONE;
538 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
540 /* determine packet, by index or by estimation */
541 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
542 packet = (guint) gst_util_uint64_scale (demux->num_packets,
543 cur, demux->play_time);
546 if (packet > demux->num_packets) {
547 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
552 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
554 cur = demux->data_offset + (packet * demux->packet_size);
556 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
557 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
558 /* BYTE seek event */
559 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
561 res = gst_pad_push_event (demux->sinkpad, event);
567 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
569 GstClockTime idx_time;
572 GstSeekType cur_type, stop_type;
574 gboolean only_need_update;
575 gboolean keyunit_sync;
580 guint packet, speed_count = 1;
582 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
583 demux->num_packets == 0 || demux->play_time == 0)) {
584 GST_LOG_OBJECT (demux, "stream is not seekable");
588 if (G_UNLIKELY (!demux->activated_streams)) {
589 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
593 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
596 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
597 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
601 if (G_UNLIKELY (rate <= 0.0)) {
602 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
606 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
608 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
609 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
611 if (G_UNLIKELY (demux->streaming)) {
612 /* support it safely needs more segment handling, e.g. closing etc */
614 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
617 /* we can (re)construct the start later on, but not the end */
618 if (stop_type != GST_SEEK_TYPE_NONE) {
619 GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
622 gst_event_ref (event);
623 /* upstream might handle TIME seek, e.g. mms or rtsp,
624 * or not, e.g. http, then we give it a hand */
625 if (!gst_pad_push_event (demux->sinkpad, event))
626 return gst_asf_demux_handle_seek_push (demux, event);
631 /* unlock the streaming thread */
632 if (G_LIKELY (flush)) {
633 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
634 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
636 gst_pad_pause_task (demux->sinkpad);
639 /* grab the stream lock so that streaming cannot continue, for
640 * non flushing seeks when the element is in PAUSED this could block
642 GST_PAD_STREAM_LOCK (demux->sinkpad);
644 /* we now can stop flushing, since we have the stream lock now */
645 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
647 if (G_LIKELY (flush))
648 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop (TRUE));
650 /* operating on copy of segment until we know the seek worked */
651 segment = demux->segment;
653 if (G_UNLIKELY (demux->segment_running && !flush)) {
654 GstSegment newsegment;
657 /* create the segment event to close the current segment */
658 gst_segment_copy_into (&segment, &newsegment);
659 newseg = gst_event_new_segment (&newsegment);
661 gst_asf_demux_send_event_unlocked (demux, newseg);
664 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
665 cur, stop_type, stop, &only_need_update);
667 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
668 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
670 seek_time = segment.start;
672 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
673 * real start of data and segment_start to indexed time for key unit seek*/
674 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
675 &idx_time, &speed_count))) {
676 /* First try to query our source to see if it can convert for us. This is
677 the case when our source is an mms stream, notice that in this case
678 gstmms will do a time based seek to get the byte offset, this is not a
679 problem as the seek to this offset needs to happen anway. */
682 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
683 GST_FORMAT_BYTES, &offset)) {
684 packet = (offset - demux->data_offset) / demux->packet_size;
685 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
686 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
687 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
688 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
689 demux->packet_size, packet);
691 /* FIXME: For streams containing video, seek to an earlier position in
692 * the hope of hitting a keyframe and let the sinks throw away the stuff
693 * before the segment start. For audio-only this is unnecessary as every
695 if (flush && (demux->accurate || keyunit_sync)
696 && demux->num_video_streams > 0) {
697 seek_time -= 5 * GST_SECOND;
702 packet = (guint) gst_util_uint64_scale (demux->num_packets,
703 seek_time, demux->play_time);
705 if (packet > demux->num_packets)
706 packet = demux->num_packets;
709 if (G_LIKELY (keyunit_sync)) {
710 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
711 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
712 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
713 segment.start = idx_time;
714 segment.position = idx_time;
715 segment.time = idx_time;
719 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
721 GST_OBJECT_LOCK (demux);
722 demux->segment = segment;
723 demux->packet = packet;
724 demux->need_newsegment = TRUE;
725 demux->speed_packets = speed_count;
726 gst_asf_demux_reset_stream_state_after_discont (demux);
727 GST_OBJECT_UNLOCK (demux);
729 /* restart our task since it might have been stopped when we did the flush */
730 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
733 /* streaming can continue now */
734 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
740 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
746 demux = GST_ASF_DEMUX (parent);
748 switch (GST_EVENT_TYPE (event)) {
750 GST_LOG_OBJECT (pad, "seek event");
751 ret = gst_asf_demux_handle_seek_event (demux, event);
752 gst_event_unref (event);
755 case GST_EVENT_NAVIGATION:
756 /* just drop these two silently */
757 gst_event_unref (event);
761 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
762 ret = gst_pad_event_default (pad, parent, event);
769 static inline guint32
770 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
774 ret = gst_asf_identify_guid (guids, guid);
776 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
777 gst_asf_get_guid_nick (guids, ret),
778 guid->v1, guid->v2, guid->v3, guid->v4);
790 /* expect is true when the user is expeting an object,
791 * when false, it will give no warnings if the object
795 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
796 guint data_len, AsfObject * object, gboolean expect)
800 if (data_len < ASF_OBJECT_HEADER_SIZE)
803 guid.v1 = GST_READ_UINT32_LE (data + 0);
804 guid.v2 = GST_READ_UINT32_LE (data + 4);
805 guid.v3 = GST_READ_UINT32_LE (data + 8);
806 guid.v4 = GST_READ_UINT32_LE (data + 12);
808 object->size = GST_READ_UINT64_LE (data + 16);
810 /* FIXME: make asf_demux_identify_object_guid() */
811 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
812 if (object->id == ASF_OBJ_UNDEFINED && expect) {
813 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
814 guid.v1, guid.v2, guid.v3, guid.v4);
821 gst_asf_demux_release_old_pads (GstASFDemux * demux)
823 GST_DEBUG_OBJECT (demux, "Releasing old pads");
825 while (demux->old_num_streams > 0) {
826 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
827 gst_event_new_eos ());
828 gst_asf_demux_free_stream (demux,
829 &demux->old_stream[demux->old_num_streams - 1]);
830 --demux->old_num_streams;
832 memset (demux->old_stream, 0, sizeof (demux->old_stream));
833 demux->old_num_streams = 0;
837 gst_asf_demux_chain_headers (GstASFDemux * demux)
841 guint8 *header_data, *data = NULL;
842 const guint8 *cdata = NULL;
845 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
849 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
850 if (obj.id != ASF_OBJ_HEADER)
853 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
855 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
856 if (gst_adapter_available (demux->adapter) < obj.size + 50)
859 data = gst_adapter_take (demux->adapter, obj.size + 50);
862 header_size = obj.size;
863 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
864 if (flow != GST_FLOW_OK)
867 /* calculate where the packet data starts */
868 demux->data_offset = obj.size + 50;
870 /* now parse the beginning of the ASF_OBJ_DATA object */
871 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
874 if (demux->num_streams == 0)
883 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
890 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
891 ("This doesn't seem to be an ASF file"));
893 return GST_FLOW_ERROR;
898 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
899 ("header parsing failed, or no streams found, flow = %s",
900 gst_flow_get_name (flow)));
902 return GST_FLOW_ERROR;
907 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
912 GST_DEBUG_OBJECT (demux, "Aggregating");
914 /* Store the value */
915 stream->last_flow = flow;
917 /* any other error that is not not-linked can be returned right away */
918 if (flow != GST_FLOW_NOT_LINKED)
921 for (i = 0; i < demux->num_streams; i++) {
922 if (demux->stream[i].active) {
923 flow = demux->stream[i].last_flow;
924 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
925 gst_flow_get_name (flow));
926 if (flow != GST_FLOW_NOT_LINKED)
931 /* If we got here, then all our active streams are not linked */
937 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
938 GstBuffer ** p_buf, GstFlowReturn * p_flow)
943 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
946 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
948 if (G_LIKELY (p_flow))
951 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
952 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
953 "+%u", gst_flow_get_name (flow), offset, size);
958 g_assert (*p_buf != NULL);
960 buffer_size = gst_buffer_get_size (*p_buf);
961 if (G_UNLIKELY (buffer_size < size)) {
962 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
963 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
964 gst_buffer_unref (*p_buf);
965 if (G_LIKELY (p_flow))
966 *p_flow = GST_FLOW_EOS;
975 gst_asf_demux_pull_indices (GstASFDemux * demux)
977 GstBuffer *buf = NULL;
981 offset = demux->index_offset;
983 if (G_UNLIKELY (offset == 0)) {
984 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
988 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
994 gst_buffer_map (buf, &map, GST_MAP_READ);
995 g_assert (map.size >= 16 + 8);
996 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
997 gst_buffer_unmap (buf, &map);
998 gst_buffer_replace (&buf, NULL);
1000 /* check for sanity */
1001 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1002 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1006 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1010 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1011 ", size %u", offset, (guint) obj.size);
1013 offset += obj.size; /* increase before _process_object changes it */
1015 gst_buffer_map (buf, &map, GST_MAP_READ);
1016 g_assert (map.size >= obj.size);
1017 bufdata = (guint8 *) map.data;
1018 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1019 gst_buffer_unmap (buf, &map);
1020 gst_buffer_replace (&buf, NULL);
1022 if (G_UNLIKELY (flow != GST_FLOW_OK))
1027 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1031 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1035 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1036 if (obj.id != ASF_OBJ_DATA) {
1037 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1041 demux->state = GST_ASF_DEMUX_STATE_DATA;
1043 if (!demux->broadcast && obj.size > 50) {
1044 demux->data_size = obj.size - 50;
1045 /* CHECKME: for at least one file this is off by +158 bytes?! */
1046 demux->index_offset = demux->data_offset + demux->data_size;
1048 demux->data_size = 0;
1049 demux->index_offset = 0;
1054 if (!demux->broadcast) {
1055 /* skip object header (24 bytes) and file GUID (16 bytes) */
1056 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1058 demux->num_packets = 0;
1061 if (demux->num_packets == 0)
1062 demux->seekable = FALSE;
1064 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1065 if (demux->data_size == 0 && demux->num_packets > 0) {
1066 demux->data_size = demux->num_packets * demux->packet_size;
1067 demux->index_offset = demux->data_offset + demux->data_size;
1070 /* process pending stream objects and create pads for those */
1071 gst_asf_demux_process_queued_extended_stream_objects (demux);
1073 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1074 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1075 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1076 demux->data_offset, demux->data_size, demux->index_offset);
1082 gst_asf_demux_pull_headers (GstASFDemux * demux)
1086 GstBuffer *buf = NULL;
1091 GST_LOG_OBJECT (demux, "reading headers");
1093 /* pull HEADER object header, so we know its size */
1094 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1097 gst_buffer_map (buf, &map, GST_MAP_READ);
1098 g_assert (map.size >= 16 + 8);
1099 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1100 gst_buffer_unmap (buf, &map);
1101 gst_buffer_replace (&buf, NULL);
1103 if (obj.id != ASF_OBJ_HEADER)
1106 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1108 /* pull HEADER object */
1109 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1113 size = obj.size; /* don't want obj.size changed */
1114 gst_buffer_map (buf, &map, GST_MAP_READ);
1115 g_assert (map.size >= size);
1116 bufdata = (guint8 *) map.data;
1117 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1118 gst_buffer_unmap (buf, &map);
1119 gst_buffer_replace (&buf, NULL);
1121 if (flow != GST_FLOW_OK) {
1122 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1126 /* calculate where the packet data starts */
1127 demux->data_offset = demux->base_offset + obj.size + 50;
1129 /* now pull beginning of DATA object before packet data */
1130 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1134 gst_buffer_map (buf, &map, GST_MAP_READ);
1135 g_assert (map.size >= size);
1136 bufdata = (guint8 *) map.data;
1137 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1140 if (demux->num_streams == 0)
1143 gst_buffer_unmap (buf, &map);
1144 gst_buffer_replace (&buf, NULL);
1152 gst_buffer_unmap (buf, &map);
1153 gst_buffer_replace (&buf, NULL);
1155 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1156 ("This doesn't seem to be an ASF file"));
1165 gst_buffer_unmap (buf, &map);
1166 gst_buffer_replace (&buf, NULL);
1167 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1173 all_streams_prerolled (GstASFDemux * demux)
1175 GstClockTime preroll_time;
1176 guint i, num_no_data = 0;
1178 /* Allow at least 500ms of preroll_time */
1179 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1181 /* returns TRUE as long as there isn't a stream which (a) has data queued
1182 * and (b) the timestamp of last piece of data queued is < demux->preroll
1183 * AND there is at least one other stream with data queued */
1184 for (i = 0; i < demux->num_streams; ++i) {
1185 AsfPayload *last_payload;
1189 stream = &demux->stream[i];
1190 if (G_UNLIKELY (stream->payloads->len == 0)) {
1192 GST_LOG_OBJECT (stream->pad, "no data queued");
1196 last_idx = stream->payloads->len - 1;
1197 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1199 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1200 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1201 GST_TIME_ARGS (preroll_time));
1202 if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1203 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1208 if (G_UNLIKELY (num_no_data == demux->num_streams))
1216 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1221 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1224 /* check for each mutual exclusion group whether it affects this stream */
1225 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1226 if (*mes == stream->id) {
1227 /* we are in this group; let's check if we've already activated streams
1228 * that are in the same group (and hence mutually exclusive to this
1230 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1233 for (i = 0; i < demux->num_streams; ++i) {
1234 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1235 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1236 "to already active stream with ID %d", stream->id,
1237 demux->stream[i].id);
1242 /* we can only be in this group once, let's break out and move on to
1243 * the next mutual exclusion group */
1254 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1258 if (demux->activated_streams)
1261 if (!all_streams_prerolled (demux) && !force) {
1262 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1266 for (i = 0; i < demux->num_streams; ++i) {
1267 AsfStream *stream = &demux->stream[i];
1269 if (stream->payloads->len > 0) {
1270 /* we don't check mutual exclusion stuff here; either we have data for
1271 * a stream, then we active it, or we don't, then we'll ignore it */
1272 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1273 gst_asf_demux_activate_stream (demux, stream);
1275 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1279 gst_asf_demux_release_old_pads (demux);
1281 demux->activated_streams = TRUE;
1282 GST_LOG_OBJECT (demux, "signalling no more pads");
1283 gst_element_no_more_pads (GST_ELEMENT (demux));
1287 /* returns the stream that has a complete payload with the lowest timestamp
1288 * queued, or NULL (we push things by timestamp because during the internal
1289 * prerolling we might accumulate more data then the external queues can take,
1290 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1292 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1294 AsfPayload *best_payload = NULL;
1295 AsfStream *best_stream = NULL;
1298 for (i = 0; i < demux->num_streams; ++i) {
1301 stream = &demux->stream[i];
1303 /* Don't push any data until we have at least one payload that falls within
1304 * the current segment. This way we can remove out-of-segment payloads that
1305 * don't need to be decoded after a seek, sending only data from the
1306 * keyframe directly before our segment start */
1307 if (stream->payloads->len > 0) {
1308 AsfPayload *payload;
1311 last_idx = stream->payloads->len - 1;
1312 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1313 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1314 (payload->ts < demux->segment.start))) {
1315 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1316 GST_DEBUG_OBJECT (stream->pad,
1317 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1318 GST_TIME_ARGS (payload->ts));
1319 demux->segment.start = payload->ts;
1320 demux->segment.time = payload->ts;
1322 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1323 GST_TIME_FORMAT " which is before our segment start %"
1324 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1325 GST_TIME_ARGS (demux->segment.start));
1330 /* Now see if there's a complete payload queued for this stream */
1332 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1333 if (!gst_asf_payload_is_complete (payload))
1336 /* ... and whether its timestamp is lower than the current best */
1337 if (best_stream == NULL || best_payload->ts > payload->ts) {
1338 best_stream = stream;
1339 best_payload = payload;
1347 static GstFlowReturn
1348 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1351 GstFlowReturn ret = GST_FLOW_OK;
1353 if (G_UNLIKELY (!demux->activated_streams)) {
1354 if (!gst_asf_demux_check_activate_streams (demux, force))
1356 /* streams are now activated */
1359 /* wait until we had a chance to "lock on" some payload's timestamp */
1360 if (G_UNLIKELY (demux->need_newsegment
1361 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1364 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1365 AsfPayload *payload;
1367 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1369 /* do we need to send a newsegment event */
1370 if ((G_UNLIKELY (demux->need_newsegment))) {
1372 /* safe default if insufficient upstream info */
1373 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1376 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1377 demux->segment.duration > 0) {
1378 /* slight HACK; prevent clipping of last bit */
1379 demux->segment.stop = demux->segment.duration + demux->in_gap;
1382 /* FIXME : only if ACCURATE ! */
1383 if (G_LIKELY (!demux->accurate
1384 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1385 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1386 GST_TIME_ARGS (payload->ts));
1387 demux->segment.start = payload->ts;
1388 demux->segment.time = payload->ts;
1391 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1394 /* note: we fix up all timestamps to start from 0, so this should be ok */
1395 gst_asf_demux_send_event_unlocked (demux,
1396 gst_event_new_segment (&demux->segment));
1398 /* now post any global tags we may have found */
1399 if (demux->taglist == NULL)
1400 demux->taglist = gst_tag_list_new_empty ();
1402 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1403 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1405 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1406 gst_asf_demux_send_event_unlocked (demux,
1407 gst_event_new_tag (demux->taglist));
1408 demux->taglist = NULL;
1410 demux->need_newsegment = FALSE;
1411 demux->segment_running = TRUE;
1414 /* Do we have tags pending for this stream? */
1415 if (G_UNLIKELY (stream->pending_tags)) {
1416 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1417 gst_pad_push_event (stream->pad,
1418 gst_event_new_tag (stream->pending_tags));
1419 stream->pending_tags = NULL;
1422 /* We have the whole packet now so we should push the packet to
1423 * the src pad now. First though we should check if we need to do
1425 if (G_UNLIKELY (demux->span > 1)) {
1426 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1429 payload->buf = gst_buffer_make_writable (payload->buf);
1431 if (G_LIKELY (!payload->keyframe)) {
1432 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1435 if (G_UNLIKELY (stream->discont)) {
1436 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1437 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1438 stream->discont = FALSE;
1441 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1442 (payload->par_x != stream->par_x) &&
1443 (payload->par_y != stream->par_y))) {
1444 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1445 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1446 stream->par_x = payload->par_x;
1447 stream->par_y = payload->par_y;
1448 stream->caps = gst_caps_make_writable (stream->caps);
1449 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1450 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1451 gst_pad_set_caps (stream->pad, stream->caps);
1454 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1455 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1456 payload->interlaced);
1457 stream->interlaced = payload->interlaced;
1458 stream->caps = gst_caps_make_writable (stream->caps);
1459 gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
1460 stream->interlaced, NULL);
1461 gst_pad_set_caps (stream->pad, stream->caps);
1464 /* (sort of) interpolate timestamps using upstream "frame of reference",
1465 * typically useful for live src, but might (unavoidably) mess with
1466 * position reporting if a live src is playing not so live content
1467 * (e.g. rtspsrc taking some time to fall back to tcp) */
1468 GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1469 if (payload->duration == GST_CLOCK_TIME_NONE
1470 && stream->ext_props.avg_time_per_frame != 0)
1471 GST_BUFFER_DURATION (payload->buf) =
1472 stream->ext_props.avg_time_per_frame * 100;
1474 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1476 /* FIXME: we should really set durations on buffers if we can */
1478 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1479 ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
1480 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1481 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1482 gst_buffer_get_size (payload->buf));
1484 ret = gst_pad_push (stream->pad, payload->buf);
1485 ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1486 payload->buf = NULL;
1487 g_array_remove_index (stream->payloads, 0);
1489 /* Break out as soon as we have an issue */
1490 if (G_UNLIKELY (ret != GST_FLOW_OK))
1498 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1502 g_assert (buf != NULL);
1504 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1506 gst_buffer_map (buf, &map, GST_MAP_READ);
1508 /* we return false on buffer too small */
1509 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1510 gst_buffer_unmap (buf, &map);
1514 /* check if it is a header */
1515 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1516 gst_buffer_unmap (buf, &map);
1517 if (obj.id == ASF_OBJ_HEADER) {
1524 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1526 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1527 GstFlowReturn ret = GST_FLOW_OK;
1528 GstBuffer *buf = NULL;
1529 gboolean header = FALSE;
1531 /* TODO maybe we should skip index objects after the data and look
1532 * further for a new header */
1533 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1534 g_assert (buf != NULL);
1535 /* check if it is a header */
1536 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1537 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1538 demux->base_offset = off;
1542 gst_buffer_unref (buf);
1549 gst_asf_demux_loop (GstASFDemux * demux)
1551 GstFlowReturn flow = GST_FLOW_OK;
1552 GstBuffer *buf = NULL;
1554 gboolean sent_eos = FALSE;
1556 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1557 if (!gst_asf_demux_pull_headers (demux)) {
1558 flow = GST_FLOW_ERROR;
1562 gst_asf_demux_pull_indices (demux);
1565 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1567 if (G_UNLIKELY (demux->num_packets != 0
1568 && demux->packet >= demux->num_packets))
1571 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1572 (guint) demux->num_packets);
1574 off = demux->data_offset + (demux->packet * demux->packet_size);
1576 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1577 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1578 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1579 if (flow == GST_FLOW_EOS)
1581 else if (flow == GST_FLOW_FLUSHING) {
1582 GST_DEBUG_OBJECT (demux, "Not fatal");
1588 if (G_LIKELY (demux->speed_packets == 1)) {
1589 /* FIXME: maybe we should just skip broken packets and error out only
1590 * after a few broken packets in a row? */
1591 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1592 /* when we don't know when the data object ends, we should check
1593 * for a chained asf */
1594 if (demux->num_packets == 0) {
1595 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1596 GST_INFO_OBJECT (demux, "Chained asf found");
1597 demux->base_offset = off;
1598 gst_asf_demux_reset (demux, TRUE);
1599 gst_buffer_unref (buf);
1606 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1612 for (n = 0; n < demux->speed_packets; n++) {
1616 gst_buffer_copy_region (buf, GST_BUFFER_COPY_NONE,
1617 n * demux->packet_size, demux->packet_size);
1618 /* FIXME: maybe we should just skip broken packets and error out only
1619 * after a few broken packets in a row? */
1620 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub))) {
1621 /* when we don't know when the data object ends, we should check
1622 * for a chained asf */
1623 if (demux->num_packets == 0) {
1624 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1625 GST_INFO_OBJECT (demux, "Chained asf found");
1626 demux->base_offset = off + n * demux->packet_size;
1627 gst_asf_demux_reset (demux, TRUE);
1628 gst_buffer_unref (sub);
1629 gst_buffer_unref (buf);
1636 gst_buffer_unref (sub);
1638 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1644 /* reset speed pull */
1645 demux->speed_packets = 1;
1648 gst_buffer_unref (buf);
1650 if (G_UNLIKELY (demux->num_packets > 0
1651 && demux->packet >= demux->num_packets)) {
1652 GST_LOG_OBJECT (demux, "reached EOS");
1656 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1657 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1661 /* check if we're at the end of the configured segment */
1662 /* FIXME: check if segment end reached etc. */
1668 /* if we haven't activated our streams yet, this might be because we have
1669 * less data queued than required for preroll; force stream activation and
1670 * send any pending payloads before sending EOS */
1671 if (!demux->activated_streams)
1672 gst_asf_demux_push_complete_payloads (demux, TRUE);
1674 /* we want to push an eos or post a segment-done in any case */
1675 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1678 /* for segment playback we need to post when (in stream time)
1679 * we stopped, this is either stop (when set) or the duration. */
1680 if ((stop = demux->segment.stop) == -1)
1681 stop = demux->segment.duration;
1683 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1684 gst_element_post_message (GST_ELEMENT_CAST (demux),
1685 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1687 } else if (flow != GST_FLOW_EOS) {
1688 /* check if we have a chained asf, in case, we don't eos yet */
1689 if (gst_asf_demux_check_chained_asf (demux)) {
1690 GST_INFO_OBJECT (demux, "Chained ASF starting");
1691 gst_asf_demux_reset (demux, TRUE);
1695 /* normal playback, send EOS to all linked pads */
1696 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1697 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1699 /* ... and fall through to pause */
1703 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1704 gst_flow_get_name (flow));
1705 demux->segment_running = FALSE;
1706 gst_pad_pause_task (demux->sinkpad);
1708 /* For the error cases (not EOS) */
1710 if (flow == GST_FLOW_EOS)
1711 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1712 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1713 /* Post an error. Hopefully something else already has, but if not... */
1714 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1715 (_("Internal data stream error.")),
1716 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1725 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1726 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1727 flow = GST_FLOW_EOS;
1732 gst_buffer_unref (buf);
1733 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1734 ("Error parsing ASF packet %u", (guint) demux->packet));
1735 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1736 flow = GST_FLOW_ERROR;
1741 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1742 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1743 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1746 gst_asf_demux_check_header (GstASFDemux * demux)
1749 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
1750 ASF_OBJECT_HEADER_SIZE);
1751 if (cdata == NULL) /* need more data */
1752 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1754 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1755 if (obj.id != ASF_OBJ_HEADER) {
1756 return GST_ASF_DEMUX_CHECK_HEADER_NO;
1758 return GST_ASF_DEMUX_CHECK_HEADER_YES;
1762 static GstFlowReturn
1763 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1765 GstFlowReturn ret = GST_FLOW_OK;
1768 demux = GST_ASF_DEMUX (parent);
1770 GST_LOG_OBJECT (demux,
1771 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
1772 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
1773 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1775 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1776 GST_DEBUG_OBJECT (demux, "received DISCONT");
1777 gst_asf_demux_mark_discont (demux);
1780 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1781 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1782 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1783 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1784 ", interpolation gap: %" GST_TIME_FORMAT,
1785 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1788 gst_adapter_push (demux->adapter, buf);
1790 switch (demux->state) {
1791 case GST_ASF_DEMUX_STATE_INDEX:{
1792 gint result = gst_asf_demux_check_header (demux);
1793 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
1796 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1797 /* we don't care about this, probably an index */
1798 /* TODO maybe would be smarter to skip all the indices
1799 * until we got a new header or EOS to decide */
1800 GST_LOG_OBJECT (demux, "Received index object, its EOS");
1803 GST_INFO_OBJECT (demux, "Chained asf starting");
1804 /* cleanup and get ready for a chained asf */
1805 gst_asf_demux_reset (demux, TRUE);
1809 case GST_ASF_DEMUX_STATE_HEADER:{
1810 ret = gst_asf_demux_chain_headers (demux);
1811 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1813 /* otherwise fall through */
1815 case GST_ASF_DEMUX_STATE_DATA:
1819 data_size = demux->packet_size;
1821 while (gst_adapter_available (demux->adapter) >= data_size) {
1824 /* we don't know the length of the stream
1825 * check for a chained asf everytime */
1826 if (demux->num_packets == 0) {
1827 gint result = gst_asf_demux_check_header (demux);
1829 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1830 GST_INFO_OBJECT (demux, "Chained asf starting");
1831 /* cleanup and get ready for a chained asf */
1832 gst_asf_demux_reset (demux, TRUE);
1835 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1836 && demux->packet >= demux->num_packets)) {
1837 /* do not overshoot data section when streaming */
1841 buf = gst_adapter_take_buffer (demux->adapter, data_size);
1843 /* FIXME: maybe we should just skip broken packets and error out only
1844 * after a few broken packets in a row? */
1845 if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1846 GST_WARNING_OBJECT (demux, "Parse error");
1849 gst_buffer_unref (buf);
1851 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1853 if (demux->packet >= 0)
1856 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1857 && demux->packet >= demux->num_packets)) {
1858 demux->state = GST_ASF_DEMUX_STATE_INDEX;
1863 g_assert_not_reached ();
1867 if (ret != GST_FLOW_OK)
1868 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1874 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1880 static inline gboolean
1881 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1883 if (*p_size < num_bytes)
1886 *p_data += num_bytes;
1887 *p_size -= num_bytes;
1891 static inline guint8
1892 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1896 g_assert (*p_size >= 1);
1897 ret = GST_READ_UINT8 (*p_data);
1898 *p_data += sizeof (guint8);
1899 *p_size -= sizeof (guint8);
1903 static inline guint16
1904 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1908 g_assert (*p_size >= 2);
1909 ret = GST_READ_UINT16_LE (*p_data);
1910 *p_data += sizeof (guint16);
1911 *p_size -= sizeof (guint16);
1915 static inline guint32
1916 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1920 g_assert (*p_size >= 4);
1921 ret = GST_READ_UINT32_LE (*p_data);
1922 *p_data += sizeof (guint32);
1923 *p_size -= sizeof (guint32);
1927 static inline guint64
1928 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1932 g_assert (*p_size >= 8);
1933 ret = GST_READ_UINT64_LE (*p_data);
1934 *p_data += sizeof (guint64);
1935 *p_size -= sizeof (guint64);
1939 static inline guint32
1940 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1947 g_assert (*p_size >= 1);
1948 return gst_asf_demux_get_uint8 (p_data, p_size);
1951 g_assert (*p_size >= 2);
1952 return gst_asf_demux_get_uint16 (p_data, p_size);
1955 g_assert (*p_size >= 4);
1956 return gst_asf_demux_get_uint32 (p_data, p_size);
1959 g_assert_not_reached ();
1966 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1967 guint8 ** p_data, guint64 * p_size)
1971 if (*p_size < num_bytes_to_read)
1974 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1975 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
1977 *p_data += num_bytes_to_read;
1978 *p_size -= num_bytes_to_read;
1984 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1985 guint8 ** p_data, guint64 * p_size)
1989 if (*p_size < num_bytes_to_read)
1992 *p_buf = g_memdup (*p_data, num_bytes_to_read);
1993 *p_data += num_bytes_to_read;
1994 *p_size -= num_bytes_to_read;
1999 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2000 guint8 ** p_data, guint64 * p_size)
2010 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2013 *p_strlen = s_length;
2015 if (s_length == 0) {
2016 GST_WARNING ("zero-length string");
2017 *p_str = g_strdup ("");
2021 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2024 g_assert (s != NULL);
2026 /* just because They don't exist doesn't
2027 * mean They are not out to get you ... */
2028 if (s[s_length - 1] != '\0') {
2029 s = g_realloc (s, s_length + 1);
2033 *p_str = (gchar *) s;
2039 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2041 g_assert (*p_size >= 4 * sizeof (guint32));
2043 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2044 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2045 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2046 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2050 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2053 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2056 /* WAVEFORMATEX Structure */
2057 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2058 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2059 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2060 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2061 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2062 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2063 /* Codec specific data size */
2064 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2069 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2072 if (*p_size < (4 + 4 + 1 + 2))
2075 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2076 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2077 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2078 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2083 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2084 guint8 ** p_data, guint64 * p_size)
2086 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2089 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2090 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2091 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2092 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2093 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2094 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2095 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2096 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2097 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2098 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2099 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2104 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2108 for (i = 0; i < demux->num_streams; i++) {
2109 if (demux->stream[i].id == id)
2110 return &demux->stream[i];
2113 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2118 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2119 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2123 gst_pad_use_fixed_caps (src_pad);
2124 gst_pad_set_caps (src_pad, caps);
2126 gst_pad_set_event_function (src_pad,
2127 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2128 gst_pad_set_query_function (src_pad,
2129 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2131 stream = &demux->stream[demux->num_streams];
2132 stream->caps = caps;
2133 stream->pad = src_pad;
2135 stream->fps_known = !is_video; /* bit hacky for audio */
2136 stream->is_video = is_video;
2137 stream->pending_tags = tags;
2138 stream->discont = TRUE;
2142 st = gst_caps_get_structure (caps, 0);
2143 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2144 par_x > 0 && par_y > 0) {
2145 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2146 stream->par_x = par_x;
2147 stream->par_y = par_y;
2151 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2153 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2154 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2156 ++demux->num_streams;
2158 stream->active = FALSE;
2162 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2163 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2165 GstTagList *tags = NULL;
2166 GstBuffer *extradata = NULL;
2169 guint16 size_left = 0;
2170 gchar *codec_name = NULL;
2173 size_left = audio->size;
2175 /* Create the audio pad */
2176 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2178 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2181 /* Swallow up any left over data and set up the
2182 * standard properties from the header info */
2184 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2185 "codec specific data", size_left);
2187 g_assert (size_left <= *p_size);
2188 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2191 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2192 * additional two bytes indicating extradata. */
2193 /* FIXME: Handle the channel reorder map here */
2194 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2195 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2198 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2199 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2202 /* Informing about that audio format we just added */
2204 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2205 g_free (codec_name);
2209 gst_buffer_unref (extradata);
2211 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2212 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2213 audio->codec_tag, tags);
2215 ++demux->num_audio_streams;
2217 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2221 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2222 asf_stream_video_format * video, guint16 id,
2223 guint8 ** p_data, guint64 * p_size)
2225 GstTagList *tags = NULL;
2226 GstBuffer *extradata = NULL;
2230 gchar *codec_name = NULL;
2231 gint size_left = video->size - 40;
2233 /* Create the video pad */
2234 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2235 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2238 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2240 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2241 g_assert (size_left <= *p_size);
2242 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2245 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2247 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2248 caps = gst_riff_create_video_caps (video->tag, NULL,
2249 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2252 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2253 G_TYPE_UINT, video->tag, NULL);
2258 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2259 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2260 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2261 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2266 /* retry with the global metadata */
2267 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2268 demux->global_metadata);
2269 s = demux->global_metadata;
2270 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2271 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2272 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2273 if (ax > 0 && ay > 0)
2274 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2278 s = gst_caps_get_structure (caps, 0);
2279 gst_structure_remove_field (s, "framerate");
2282 /* add fourcc format to caps, some proprietary decoders seem to need it */
2283 gst_caps_set_simple (caps, "format", G_TYPE_UINT, video->tag, NULL);
2286 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2287 g_free (codec_name);
2291 gst_buffer_unref (extradata);
2293 GST_INFO ("Adding video stream #%u, id %u, codec %"
2294 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2295 GST_FOURCC_ARGS (video->tag), video->tag);
2297 ++demux->num_video_streams;
2299 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2303 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2305 if (!stream->active) {
2306 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2307 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2308 gst_pad_set_active (stream->pad, TRUE);
2309 gst_pad_set_caps (stream->pad, stream->caps);
2310 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2311 stream->active = TRUE;
2316 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2319 AsfCorrectionType correction_type;
2320 AsfStreamType stream_type;
2321 GstClockTime time_offset;
2322 gboolean is_encrypted G_GNUC_UNUSED;
2326 guint stream_specific_size;
2327 guint type_specific_size G_GNUC_UNUSED;
2328 guint unknown G_GNUC_UNUSED;
2330 /* Get the rest of the header's header */
2331 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2332 goto not_enough_data;
2334 gst_asf_demux_get_guid (&guid, &data, &size);
2335 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2337 gst_asf_demux_get_guid (&guid, &data, &size);
2338 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2340 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2342 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2343 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2345 flags = gst_asf_demux_get_uint16 (&data, &size);
2346 stream_id = flags & 0x7f;
2347 is_encrypted = ! !((flags & 0x8000) << 15);
2348 unknown = gst_asf_demux_get_uint32 (&data, &size);
2350 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2351 stream_id, GST_TIME_ARGS (time_offset));
2353 switch (stream_type) {
2354 case ASF_STREAM_AUDIO:{
2355 asf_stream_audio audio_object;
2357 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2358 goto not_enough_data;
2360 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2363 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2366 switch (correction_type) {
2367 case ASF_CORRECTION_ON:{
2368 guint span, packet_size, chunk_size, data_size, silence_data;
2370 GST_INFO ("Using error correction");
2372 if (size < (1 + 2 + 2 + 2 + 1))
2373 goto not_enough_data;
2375 span = gst_asf_demux_get_uint8 (&data, &size);
2376 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2377 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2378 data_size = gst_asf_demux_get_uint16 (&data, &size);
2379 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2381 /* FIXME: shouldn't this be per-stream? */
2384 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2385 packet_size, chunk_size, data_size, span, silence_data);
2387 if (demux->span > 1) {
2388 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2389 /* Disable descrambling */
2392 /* FIXME: this else branch was added for
2393 * weird_al_yankovic - the saga begins.asf */
2394 demux->ds_packet_size = packet_size;
2395 demux->ds_chunk_size = chunk_size;
2398 /* Descambling is enabled */
2399 demux->ds_packet_size = packet_size;
2400 demux->ds_chunk_size = chunk_size;
2403 /* Now skip the rest of the silence data */
2405 gst_bytestream_flush (demux->bs, data_size - 1);
2407 /* FIXME: CHECKME. And why -1? */
2408 if (data_size > 1) {
2409 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2410 goto not_enough_data;
2416 case ASF_CORRECTION_OFF:{
2417 GST_INFO ("Error correction off");
2418 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2419 goto not_enough_data;
2423 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2424 ("Audio stream using unknown error correction"));
2431 case ASF_STREAM_VIDEO:{
2432 asf_stream_video_format video_format_object;
2433 asf_stream_video video_object;
2436 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2437 goto not_enough_data;
2439 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2441 GST_INFO ("object is a video stream with %u bytes of "
2442 "additional data", vsize);
2444 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2446 goto not_enough_data;
2449 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2456 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2461 return gst_asf_demux_get_stream (demux, stream_id);
2465 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2466 /* we'll error out later if we found no streams */
2471 static const gchar *
2472 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2476 const gchar *asf_name;
2477 const gchar *gst_name;
2480 "WM/Genre", GST_TAG_GENRE}, {
2481 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2482 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2483 "WM/Picture", GST_TAG_IMAGE}, {
2484 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2485 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2486 "WM/Year", GST_TAG_DATE}
2487 /* { "WM/Composer", GST_TAG_COMPOSER } */
2492 if (name_utf8 == NULL) {
2493 GST_WARNING ("Failed to convert name to UTF8, skipping");
2497 out = strlen (name_utf8);
2499 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2500 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2501 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2502 return tags[i].gst_name;
2509 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2511 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2515 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2517 if (taglist == NULL)
2520 if (gst_tag_list_is_empty (taglist)) {
2521 gst_tag_list_free (taglist);
2525 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2527 gst_tag_list_free (demux->taglist);
2528 gst_tag_list_free (taglist);
2530 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2533 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2534 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2535 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2538 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2542 const guint8 *img_data = NULL;
2543 guint32 img_data_len = 0;
2544 guint8 pic_type = 0;
2546 gst_byte_reader_init (&r, tag_data, tag_data_len);
2548 /* skip mime type string (we don't trust it and do our own typefinding),
2549 * and also skip the description string, since we don't use it */
2550 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2551 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2552 !gst_byte_reader_skip_string_utf16 (&r) ||
2553 !gst_byte_reader_skip_string_utf16 (&r) ||
2554 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2555 goto not_enough_data;
2559 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2560 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2566 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2567 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2572 /* Extended Content Description Object */
2573 static GstFlowReturn
2574 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2577 /* Other known (and unused) 'text/unicode' metadata available :
2580 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2581 * WMFSDKVersion = 9.00.00.2980
2582 * WMFSDKNeeded = 0.0.0.0000
2583 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2584 * WM/Publisher = 4AD
2586 * WM/ProviderRating = 8
2587 * WM/ProviderStyle = Rock (similar to WM/Genre)
2588 * WM/GenreID (similar to WM/Genre)
2589 * WM/TrackNumber (same as WM/Track but as a string)
2591 * Other known (and unused) 'non-text' metadata available :
2597 * We might want to read WM/TrackNumber and use atoi() if we don't have
2601 GstTagList *taglist;
2602 guint16 blockcount, i;
2604 GST_INFO_OBJECT (demux, "object is an extended content description");
2606 taglist = gst_tag_list_new_empty ();
2608 /* Content Descriptor Count */
2610 goto not_enough_data;
2612 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2614 for (i = 1; i <= blockcount; ++i) {
2615 const gchar *gst_tag_name;
2619 GValue tag_value = { 0, };
2622 gchar *name_utf8 = NULL;
2626 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2627 goto not_enough_data;
2631 goto not_enough_data;
2633 /* Descriptor Value Data Type */
2634 datatype = gst_asf_demux_get_uint16 (&data, &size);
2636 /* Descriptor Value (not really a string, but same thing reading-wise) */
2637 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2639 goto not_enough_data;
2643 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2645 if (name_utf8 != NULL) {
2646 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2648 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2649 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2652 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2655 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2658 /* get rid of tags with empty value */
2659 if (value_utf8 != NULL && *value_utf8 != '\0') {
2660 GST_DEBUG ("string value %s", value_utf8);
2662 value_utf8[out] = '\0';
2664 if (gst_tag_name != NULL) {
2665 if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2666 guint year = atoi (value_utf8);
2669 /* FIXME: really want a GDateTime with just the year field */
2670 g_value_init (&tag_value, G_TYPE_DATE);
2671 g_value_take_boxed (&tag_value, g_date_new_dmy (1, 1, year));
2673 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2674 guint id3v1_genre_id;
2675 const gchar *genre_str;
2677 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2678 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2679 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2680 g_free (value_utf8);
2681 value_utf8 = g_strdup (genre_str);
2686 /* convert tag from string to other type if required */
2687 tag_type = gst_tag_get_type (gst_tag_name);
2688 g_value_init (&tag_value, tag_type);
2689 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2690 GValue from_val = { 0, };
2692 g_value_init (&from_val, G_TYPE_STRING);
2693 g_value_set_string (&from_val, value_utf8);
2694 if (!g_value_transform (&from_val, &tag_value)) {
2695 GST_WARNING_OBJECT (demux,
2696 "Could not transform string tag to " "%s tag type %s",
2697 gst_tag_name, g_type_name (tag_type));
2698 g_value_unset (&tag_value);
2700 g_value_unset (&from_val);
2705 GST_DEBUG ("Setting metadata");
2706 g_value_init (&tag_value, G_TYPE_STRING);
2707 g_value_set_string (&tag_value, value_utf8);
2709 } else if (value_utf8 == NULL) {
2710 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2712 GST_DEBUG ("Skipping empty string value for %s",
2713 GST_STR_NULL (gst_tag_name));
2715 g_free (value_utf8);
2718 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2720 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2721 GST_FIXME ("Unhandled byte array tag %s",
2722 GST_STR_NULL (gst_tag_name));
2725 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2731 case ASF_DEMUX_DATA_TYPE_DWORD:{
2732 guint uint_val = GST_READ_UINT32_LE (value);
2734 /* this is the track number */
2735 g_value_init (&tag_value, G_TYPE_UINT);
2737 /* WM/Track counts from 0 */
2738 if (!strcmp (name_utf8, "WM/Track"))
2741 g_value_set_uint (&tag_value, uint_val);
2745 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2750 if (G_IS_VALUE (&tag_value)) {
2752 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2754 /* WM/TrackNumber is more reliable than WM/Track, since the latter
2755 * is supposed to have a 0 base but is often wrongly written to start
2756 * from 1 as well, so prefer WM/TrackNumber when we have it: either
2757 * replace the value added earlier from WM/Track or put it first in
2758 * the list, so that it will get picked up by _get_uint() */
2759 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2760 merge_mode = GST_TAG_MERGE_REPLACE;
2762 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2765 GST_DEBUG ("Setting global metadata %s", name_utf8);
2766 gst_structure_set_value (demux->global_metadata, name_utf8,
2770 g_value_unset (&tag_value);
2779 gst_asf_demux_add_global_tags (demux, taglist);
2786 GST_WARNING ("Unexpected end of data parsing ext content desc object");
2787 gst_tag_list_free (taglist);
2788 return GST_FLOW_OK; /* not really fatal */
2792 static GstStructure *
2793 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2798 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2800 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2803 s = gst_caps_get_structure (demux->metadata, i);
2804 if (gst_structure_has_name (s, sname))
2808 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
2810 /* try lookup again; demux->metadata took ownership of the structure, so we
2811 * can't really make any assumptions about what happened to it, so we can't
2812 * just return it directly after appending it */
2813 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2816 static GstFlowReturn
2817 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2820 guint16 blockcount, i;
2822 GST_INFO_OBJECT (demux, "object is a metadata object");
2824 /* Content Descriptor Count */
2826 goto not_enough_data;
2828 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2830 for (i = 0; i < blockcount; ++i) {
2832 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
2833 guint32 data_len, ival;
2836 if (size < (2 + 2 + 2 + 2 + 4))
2837 goto not_enough_data;
2839 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2840 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2841 name_len = gst_asf_demux_get_uint16 (&data, &size);
2842 data_type = gst_asf_demux_get_uint16 (&data, &size);
2843 data_len = gst_asf_demux_get_uint32 (&data, &size);
2845 if (size < name_len + data_len)
2846 goto not_enough_data;
2848 /* convert name to UTF-8 */
2849 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2851 gst_asf_demux_skip_bytes (name_len, &data, &size);
2853 if (name_utf8 == NULL) {
2854 GST_WARNING ("Failed to convert value name to UTF8, skipping");
2855 gst_asf_demux_skip_bytes (data_len, &data, &size);
2859 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2860 gst_asf_demux_skip_bytes (data_len, &data, &size);
2868 goto not_enough_data;
2871 ival = gst_asf_demux_get_uint32 (&data, &size);
2873 /* skip anything else there may be, just in case */
2874 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2876 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2877 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2881 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2887 GST_WARNING ("Unexpected end of data parsing metadata object");
2888 return GST_FLOW_OK; /* not really fatal */
2892 static GstFlowReturn
2893 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2895 GstFlowReturn ret = GST_FLOW_OK;
2896 guint32 i, num_objects;
2897 guint8 unknown G_GNUC_UNUSED;
2899 /* Get the rest of the header's header */
2900 if (size < (4 + 1 + 1))
2901 goto not_enough_data;
2903 num_objects = gst_asf_demux_get_uint32 (&data, &size);
2904 unknown = gst_asf_demux_get_uint8 (&data, &size);
2905 unknown = gst_asf_demux_get_uint8 (&data, &size);
2907 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2909 /* Loop through the header's objects, processing those */
2910 for (i = 0; i < num_objects; ++i) {
2911 GST_INFO_OBJECT (demux, "reading header part %u", i);
2912 ret = gst_asf_demux_process_object (demux, &data, &size);
2913 if (ret != GST_FLOW_OK) {
2914 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2923 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2924 ("short read parsing HEADER object"));
2925 return GST_FLOW_ERROR;
2929 static GstFlowReturn
2930 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2932 guint64 creation_time G_GNUC_UNUSED;
2933 guint64 file_size G_GNUC_UNUSED;
2934 guint64 send_time G_GNUC_UNUSED;
2935 guint64 packets_count, play_time, preroll;
2936 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
2938 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2939 goto not_enough_data;
2941 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
2942 file_size = gst_asf_demux_get_uint64 (&data, &size);
2943 creation_time = gst_asf_demux_get_uint64 (&data, &size);
2944 packets_count = gst_asf_demux_get_uint64 (&data, &size);
2945 play_time = gst_asf_demux_get_uint64 (&data, &size);
2946 send_time = gst_asf_demux_get_uint64 (&data, &size);
2947 preroll = gst_asf_demux_get_uint64 (&data, &size);
2948 flags = gst_asf_demux_get_uint32 (&data, &size);
2949 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2950 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2951 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2953 demux->broadcast = ! !(flags & 0x01);
2954 demux->seekable = ! !(flags & 0x02);
2956 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2957 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2958 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
2960 if (demux->broadcast) {
2961 /* these fields are invalid if the broadcast flag is set */
2966 if (min_pktsize != max_pktsize)
2967 goto non_fixed_packet_size;
2969 demux->packet_size = max_pktsize;
2971 /* FIXME: do we need send_time as well? what is it? */
2972 if ((play_time * 100) >= (preroll * GST_MSECOND))
2973 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2975 demux->play_time = 0;
2977 demux->preroll = preroll * GST_MSECOND;
2979 /* initial latency */
2980 demux->latency = demux->preroll;
2982 if (demux->play_time == 0)
2983 demux->seekable = FALSE;
2985 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2986 GST_TIME_ARGS (demux->play_time));
2987 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
2988 GST_TIME_ARGS (demux->preroll));
2990 if (demux->play_time > 0) {
2991 demux->segment.duration = demux->play_time;
2994 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2996 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3001 non_fixed_packet_size:
3003 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3004 ("packet size must be fixed"));
3005 return GST_FLOW_ERROR;
3009 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3010 ("short read parsing FILE object"));
3011 return GST_FLOW_ERROR;
3015 /* Content Description Object */
3016 static GstFlowReturn
3017 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3021 const gchar *gst_tag;
3026 GST_TAG_TITLE, 0, NULL}, {
3027 GST_TAG_ARTIST, 0, NULL}, {
3028 GST_TAG_COPYRIGHT, 0, NULL}, {
3029 GST_TAG_DESCRIPTION, 0, NULL}, {
3030 GST_TAG_COMMENT, 0, NULL}
3032 GstTagList *taglist;
3033 GValue value = { 0 };
3037 GST_INFO_OBJECT (demux, "object is a comment");
3039 if (size < (2 + 2 + 2 + 2 + 2))
3040 goto not_enough_data;
3042 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3043 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3044 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3045 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3046 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3048 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3049 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3050 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3052 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3053 if (size < tags[i].val_length)
3054 goto not_enough_data;
3056 /* might be just '/0', '/0'... */
3057 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3058 /* convert to UTF-8 */
3059 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3060 "UTF-8", "UTF-16LE", &in, &out, NULL);
3062 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3065 /* parse metadata into taglist */
3066 taglist = gst_tag_list_new_empty ();
3067 g_value_init (&value, G_TYPE_STRING);
3068 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3069 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3070 g_value_set_string (&value, tags[i].val_utf8);
3071 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3072 tags[i].gst_tag, &value, NULL);
3075 g_value_unset (&value);
3077 gst_asf_demux_add_global_tags (demux, taglist);
3079 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3080 g_free (tags[i].val_utf8);
3086 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3087 "comment tag section %d, skipping comment object", i);
3088 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3089 g_free (tags[i].val_utf8);
3090 return GST_FLOW_OK; /* not really fatal */
3094 static GstFlowReturn
3095 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3098 guint16 num_streams, i;
3102 goto not_enough_data;
3104 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3106 GST_INFO ("object is a bitrate properties object with %u streams",
3109 if (size < (num_streams * (2 + 4)))
3110 goto not_enough_data;
3112 for (i = 0; i < num_streams; ++i) {
3116 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3117 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3119 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3120 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3121 stream = gst_asf_demux_get_stream (demux, stream_id);
3123 if (stream->pending_tags == NULL) {
3124 stream->pending_tags =
3125 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3128 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3131 GST_WARNING ("stream id %u is too large", stream_id);
3139 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3140 return GST_FLOW_OK; /* not really fatal */
3144 static GstFlowReturn
3145 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3148 GstFlowReturn ret = GST_FLOW_OK;
3151 /* Get the rest of the header's header */
3152 if (size < (16 + 2 + 4))
3153 goto not_enough_data;
3155 /* skip GUID and two other bytes */
3156 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3157 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3159 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3161 /* FIXME: does data_size include the rest of the header that we have read? */
3162 if (hdr_size > size)
3163 goto not_enough_data;
3165 while (hdr_size > 0) {
3166 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3167 if (ret != GST_FLOW_OK)
3175 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3176 ("short read parsing extended header object"));
3177 return GST_FLOW_ERROR;
3181 static GstFlowReturn
3182 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3188 goto not_enough_data;
3190 if (demux->languages) {
3191 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3192 g_strfreev (demux->languages);
3193 demux->languages = NULL;
3194 demux->num_languages = 0;
3197 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3198 GST_LOG ("%u languages:", demux->num_languages);
3200 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3201 for (i = 0; i < demux->num_languages; ++i) {
3202 guint8 len, *lang_data = NULL;
3205 goto not_enough_data;
3206 len = gst_asf_demux_get_uint8 (&data, &size);
3207 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3210 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3213 /* truncate "en-us" etc. to just "en" */
3214 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3217 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3218 demux->languages[i] = utf8;
3221 goto not_enough_data;
3229 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3230 g_free (demux->languages);
3231 demux->languages = NULL;
3232 return GST_FLOW_OK; /* not fatal */
3236 static GstFlowReturn
3237 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3240 GstClockTime interval;
3243 if (size < (16 + 8 + 4 + 4))
3244 goto not_enough_data;
3247 gst_asf_demux_skip_bytes (16, &data, &size);
3248 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3249 gst_asf_demux_skip_bytes (4, &data, &size);
3250 count = gst_asf_demux_get_uint32 (&data, &size);
3252 demux->sidx_interval = interval;
3253 demux->sidx_num_entries = count;
3254 g_free (demux->sidx_entries);
3255 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3257 for (i = 0; i < count; ++i) {
3258 if (G_UNLIKELY (size <= 6))
3260 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3261 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3262 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3263 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3264 demux->sidx_entries[i].count);
3267 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3274 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3275 return GST_FLOW_OK; /* not fatal */
3279 static GstFlowReturn
3280 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3281 guint8 * data, guint64 size)
3287 if (size < 16 + 2 + (2 * 2))
3288 goto not_enough_data;
3290 gst_asf_demux_get_guid (&guid, &data, &size);
3291 num = gst_asf_demux_get_uint16 (&data, &size);
3294 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3298 if (size < (num * sizeof (guint16)))
3299 goto not_enough_data;
3301 /* read mutually exclusive stream numbers */
3302 mes = g_new (guint8, num + 1);
3303 for (i = 0; i < num; ++i) {
3304 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3305 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3308 /* add terminator so we can easily get the count or know when to stop */
3309 mes[i] = (guint8) - 1;
3311 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3318 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3319 return GST_FLOW_OK; /* not absolutely fatal */
3323 static GstFlowReturn
3324 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3327 AsfStreamExtProps esp;
3328 AsfStream *stream = NULL;
3329 AsfObject stream_obj;
3330 guint16 stream_name_count;
3331 guint16 num_payload_ext;
3333 guint8 *stream_obj_data = NULL;
3336 guint i, stream_num;
3339 obj_size = (guint) size;
3342 goto not_enough_data;
3345 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3346 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3347 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3348 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3349 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3350 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3351 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3352 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3353 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3354 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3355 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3356 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3357 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3358 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3359 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3361 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3362 GST_TIME_ARGS (esp.start_time));
3363 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3364 GST_TIME_ARGS (esp.end_time));
3365 GST_INFO ("flags = %08x", esp.flags);
3366 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3367 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3368 GST_INFO ("stream number = %u", stream_num);
3369 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3370 (esp.lang_idx < demux->num_languages) ?
3371 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3372 GST_INFO ("stream name count = %u", stream_name_count);
3374 /* read stream names */
3375 for (i = 0; i < stream_name_count; ++i) {
3376 guint16 stream_lang_idx G_GNUC_UNUSED;
3377 gchar *stream_name = NULL;
3380 goto not_enough_data;
3381 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3382 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3383 goto not_enough_data;
3384 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3385 g_free (stream_name); /* TODO: store names in struct */
3388 /* read payload extension systems stuff */
3389 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3391 if (num_payload_ext > 0)
3392 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3394 esp.payload_extensions = NULL;
3396 for (i = 0; i < num_payload_ext; ++i) {
3397 AsfPayloadExtension ext;
3399 guint32 sys_info_len;
3401 if (size < 16 + 2 + 4)
3402 goto not_enough_data;
3404 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3405 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3406 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3408 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3409 GST_LOG ("payload systems info len = %u", sys_info_len);
3410 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3411 goto not_enough_data;
3413 esp.payload_extensions[i] = ext;
3416 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3418 /* there might be an optional STREAM_INFO object here now; if not, we
3419 * should have parsed the corresponding stream info object already (since
3420 * we are parsing the extended stream properties objects delayed) */
3422 stream = gst_asf_demux_get_stream (demux, stream_num);
3426 /* get size of the stream object */
3427 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3428 goto not_enough_data;
3430 if (stream_obj.id != ASF_OBJ_STREAM)
3431 goto expected_stream_object;
3433 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3434 stream_obj.size > (10 * 1024 * 1024))
3435 goto not_enough_data;
3437 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3439 /* process this stream object later after all the other 'normal' ones
3440 * have been processed (since the others are more important/non-hidden) */
3441 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3442 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3443 goto not_enough_data;
3445 /* parse stream object */
3446 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3447 g_free (stream_obj_data);
3452 stream->ext_props = esp;
3454 /* try to set the framerate */
3455 if (stream->is_video && stream->caps) {
3456 GValue framerate = { 0 };
3460 g_value_init (&framerate, GST_TYPE_FRACTION);
3462 num = GST_SECOND / 100;
3463 denom = esp.avg_time_per_frame;
3465 /* avoid division by 0, assume 25/1 framerate */
3466 denom = GST_SECOND / 2500;
3469 gst_value_set_fraction (&framerate, num, denom);
3471 stream->caps = gst_caps_make_writable (stream->caps);
3472 s = gst_caps_get_structure (stream->caps, 0);
3473 gst_structure_set_value (s, "framerate", &framerate);
3474 g_value_unset (&framerate);
3475 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3476 num, denom, ((gdouble) num) / denom);
3479 /* add language info now if we have it */
3480 if (stream->ext_props.lang_idx < demux->num_languages) {
3481 if (stream->pending_tags == NULL)
3482 stream->pending_tags = gst_tag_list_new_empty ();
3483 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3484 demux->languages[stream->ext_props.lang_idx]);
3485 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3486 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3490 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3498 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3499 return GST_FLOW_OK; /* not absolutely fatal */
3501 expected_stream_object:
3503 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3504 "object: expected embedded stream object, but got %s object instead!",
3505 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3506 return GST_FLOW_OK; /* not absolutely fatal */
3510 static const gchar *
3511 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3515 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3516 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3517 nick += strlen ("ASF_OBJ_");
3519 if (demux->objpath == NULL) {
3520 demux->objpath = g_strdup (nick);
3524 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3525 g_free (demux->objpath);
3526 demux->objpath = newpath;
3529 return (const gchar *) demux->objpath;
3533 gst_asf_demux_pop_obj (GstASFDemux * demux)
3537 if ((s = g_strrstr (demux->objpath, "/"))) {
3540 g_free (demux->objpath);
3541 demux->objpath = NULL;
3546 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3551 /* Parse the queued extended stream property objects and add the info
3552 * to the existing streams or add the new embedded streams, but without
3553 * activating them yet */
3554 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3555 g_slist_length (demux->ext_stream_props));
3557 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3558 GstBuffer *buf = GST_BUFFER (l->data);
3561 gst_buffer_map (buf, &map, GST_MAP_READ);
3563 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3564 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
3565 gst_buffer_unmap (buf, &map);
3566 gst_buffer_unref (buf);
3568 g_slist_free (demux->ext_stream_props);
3569 demux->ext_stream_props = NULL;
3574 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3578 for (i = 0; i < demux->num_streams; ++i) {
3583 stream = &demux->stream[i];
3585 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3587 if (stream->active) {
3588 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3593 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3596 /* check for each mutual exclusion whether it affects this stream */
3597 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3598 if (*mes == stream->id) {
3599 /* if yes, check if we've already added streams that are mutually
3600 * exclusive with the stream we're about to add */
3601 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3602 for (j = 0; j < demux->num_streams; ++j) {
3603 /* if the broadcast flag is set, assume the hidden streams aren't
3604 * actually streamed and hide them (or playbin won't work right),
3605 * otherwise assume their data is available */
3606 if (demux->stream[j].id == *mes && demux->broadcast) {
3608 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3609 "mutually exclusive with already existing stream ID %d, "
3610 "hiding stream", stream->id, demux->stream[j].id);
3622 /* FIXME: we should do stream activation based on preroll data in
3623 * streaming mode too */
3624 if (demux->streaming && !is_hidden)
3625 gst_asf_demux_activate_stream (demux, stream);
3630 static GstFlowReturn
3631 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3634 GstFlowReturn ret = GST_FLOW_OK;
3636 guint64 obj_data_size;
3638 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3639 return ASF_FLOW_NEED_MORE_DATA;
3641 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3642 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3644 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3646 if (*p_size < obj_data_size)
3647 return ASF_FLOW_NEED_MORE_DATA;
3649 gst_asf_demux_push_obj (demux, obj.id);
3651 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3654 case ASF_OBJ_STREAM:
3655 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3659 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3661 case ASF_OBJ_HEADER:
3662 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3664 case ASF_OBJ_COMMENT:
3665 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3668 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3670 case ASF_OBJ_BITRATE_PROPS:
3672 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3675 case ASF_OBJ_EXT_CONTENT_DESC:
3677 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3680 case ASF_OBJ_METADATA_OBJECT:
3681 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3683 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3686 /* process these later, we might not have parsed the corresponding
3687 * stream object yet */
3688 GST_LOG ("%s: queued for later parsing", demux->objpath);
3689 buf = gst_buffer_new_and_alloc (obj_data_size);
3690 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
3691 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3695 case ASF_OBJ_LANGUAGE_LIST:
3696 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3698 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3699 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3702 case ASF_OBJ_SIMPLE_INDEX:
3703 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3705 case ASF_OBJ_CONTENT_ENCRYPTION:
3706 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3707 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3708 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
3709 goto error_encrypted;
3710 case ASF_OBJ_CONCEAL_NONE:
3712 case ASF_OBJ_UNDEFINED:
3713 case ASF_OBJ_CODEC_COMMENT:
3715 case ASF_OBJ_PADDING:
3716 case ASF_OBJ_BITRATE_MUTEX:
3717 case ASF_OBJ_COMPATIBILITY:
3718 case ASF_OBJ_INDEX_PLACEHOLDER:
3719 case ASF_OBJ_INDEX_PARAMETERS:
3720 case ASF_OBJ_STREAM_PRIORITIZATION:
3721 case ASF_OBJ_SCRIPT_COMMAND:
3723 /* Unknown/unhandled object, skip it and hope for the best */
3724 GST_INFO ("%s: skipping object", demux->objpath);
3729 /* this can't fail, we checked the number of bytes available before */
3730 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3732 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3734 gst_asf_demux_pop_obj (demux);
3741 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3742 return GST_FLOW_ERROR;
3747 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3748 GstBuffer ** p_buffer)
3750 GstBuffer *descrambled_buffer;
3751 GstBuffer *scrambled_buffer;
3752 GstBuffer *sub_buffer;
3759 /* descrambled_buffer is initialised in the first iteration */
3760 descrambled_buffer = NULL;
3761 scrambled_buffer = *p_buffer;
3763 if (gst_buffer_get_size (scrambled_buffer) <
3764 demux->ds_packet_size * demux->span)
3767 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
3768 offset += demux->ds_chunk_size) {
3769 off = offset / demux->ds_chunk_size;
3770 row = off / demux->span;
3771 col = off % demux->span;
3772 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3773 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3774 col, off, demux->ds_chunk_size);
3775 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
3776 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
3777 demux->span, demux->ds_packet_size);
3778 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
3779 gst_buffer_get_size (scrambled_buffer));
3781 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_NONE,
3782 idx * demux->ds_chunk_size, demux->ds_chunk_size);
3784 descrambled_buffer = sub_buffer;
3786 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
3790 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
3791 GST_BUFFER_TIMESTAMP (scrambled_buffer);
3792 GST_BUFFER_DURATION (descrambled_buffer) =
3793 GST_BUFFER_DURATION (scrambled_buffer);
3794 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
3795 GST_BUFFER_OFFSET_END (descrambled_buffer) =
3796 GST_BUFFER_OFFSET_END (scrambled_buffer);
3798 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3800 gst_buffer_unref (scrambled_buffer);
3801 *p_buffer = descrambled_buffer;
3805 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3807 GstASFDemux *demux = GST_ASF_DEMUX (element);
3810 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3812 for (i = 0; i < demux->num_streams; ++i) {
3813 gst_event_ref (event);
3814 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
3815 GST_OBJECT_CAST (element), event)) {
3816 gst_event_unref (event);
3821 gst_event_unref (event);
3825 /* takes ownership of the passed event */
3827 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3829 gboolean ret = TRUE;
3832 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3833 GST_EVENT_TYPE_NAME (event));
3835 for (i = 0; i < demux->num_streams; ++i) {
3836 gst_event_ref (event);
3837 ret &= gst_pad_push_event (demux->stream[i].pad, event);
3839 gst_event_unref (event);
3844 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
3848 gboolean res = FALSE;
3850 demux = GST_ASF_DEMUX (parent);
3852 GST_DEBUG ("handling %s query",
3853 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3855 switch (GST_QUERY_TYPE (query)) {
3856 case GST_QUERY_DURATION:
3860 gst_query_parse_duration (query, &format, NULL);
3862 if (format != GST_FORMAT_TIME) {
3863 GST_LOG ("only support duration queries in TIME format");
3867 GST_OBJECT_LOCK (demux);
3869 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3870 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3871 GST_TIME_ARGS (demux->segment.duration));
3873 gst_query_set_duration (query, GST_FORMAT_TIME,
3874 demux->segment.duration);
3878 GST_LOG ("duration not known yet");
3881 GST_OBJECT_UNLOCK (demux);
3885 case GST_QUERY_POSITION:{
3888 gst_query_parse_position (query, &format, NULL);
3890 if (format != GST_FORMAT_TIME) {
3891 GST_LOG ("only support position queries in TIME format");
3895 GST_OBJECT_LOCK (demux);
3897 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
3898 GST_LOG ("returning position: %" GST_TIME_FORMAT,
3899 GST_TIME_ARGS (demux->segment.position));
3901 gst_query_set_position (query, GST_FORMAT_TIME,
3902 demux->segment.position);
3906 GST_LOG ("position not known yet");
3909 GST_OBJECT_UNLOCK (demux);
3913 case GST_QUERY_SEEKING:{
3916 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3917 if (format == GST_FORMAT_TIME) {
3920 GST_OBJECT_LOCK (demux);
3921 duration = demux->segment.duration;
3922 GST_OBJECT_UNLOCK (demux);
3924 if (!demux->streaming || !demux->seekable) {
3925 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3932 /* try downstream first in TIME */
3933 res = gst_pad_query_default (pad, parent, query);
3935 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3936 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3937 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3938 /* if no luck, maybe in BYTES */
3939 if (!seekable || fmt != GST_FORMAT_TIME) {
3942 q = gst_query_new_seeking (GST_FORMAT_BYTES);
3943 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3944 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3945 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3946 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3947 if (fmt != GST_FORMAT_BYTES)
3950 gst_query_unref (q);
3951 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3957 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3961 case GST_QUERY_LATENCY:
3964 GstClockTime min, max;
3966 /* preroll delay does not matter in non-live pipeline,
3967 * but we might end up in a live (rtsp) one ... */
3970 res = gst_pad_query_default (pad, parent, query);
3974 gst_query_parse_latency (query, &live, &min, &max);
3976 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
3977 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3978 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3980 GST_OBJECT_LOCK (demux);
3982 min += demux->latency;
3984 max += demux->latency;
3985 GST_OBJECT_UNLOCK (demux);
3987 gst_query_set_latency (query, live, min, max);
3991 res = gst_pad_query_default (pad, parent, query);
3998 static GstStateChangeReturn
3999 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4001 GstASFDemux *demux = GST_ASF_DEMUX (element);
4002 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4004 switch (transition) {
4005 case GST_STATE_CHANGE_NULL_TO_READY:{
4006 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4007 demux->need_newsegment = TRUE;
4008 demux->segment_running = FALSE;
4009 demux->accurate = FALSE;
4010 demux->adapter = gst_adapter_new ();
4011 demux->metadata = gst_caps_new_empty ();
4012 demux->global_metadata = gst_structure_new_empty ("metadata");
4013 demux->data_size = 0;
4014 demux->data_offset = 0;
4015 demux->index_offset = 0;
4016 demux->base_offset = 0;
4023 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4024 if (ret == GST_STATE_CHANGE_FAILURE)
4027 switch (transition) {
4028 case GST_STATE_CHANGE_PAUSED_TO_READY:
4029 case GST_STATE_CHANGE_READY_TO_NULL:
4030 gst_asf_demux_reset (demux, FALSE);