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,
443 gboolean next, gboolean * eos)
445 GstClockTime idx_time;
451 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
454 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
457 /* if we want the next keyframe, we have to go forward till we find
458 a different packet number */
460 if (idx >= demux->sidx_num_entries - 1) {
461 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
466 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
467 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
474 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
480 *packet = demux->sidx_entries[idx].packet;
482 *speed = demux->sidx_entries[idx].count;
484 /* so we get closer to the actual time of the packet ... actually, let's not
485 * do this, since we throw away superfluous payloads before the seek position
486 * anyway; this way, our key unit seek 'snap resolution' is a bit better
487 * (ie. same as index resolution) */
489 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
493 idx_time = demux->sidx_interval * idx;
494 if (G_LIKELY (idx_time >= demux->preroll))
495 idx_time -= demux->preroll;
497 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
498 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
499 GST_TIME_ARGS (idx_time));
501 if (G_LIKELY (p_idx_time))
502 *p_idx_time = idx_time;
508 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
512 gst_adapter_clear (demux->adapter);
514 GST_DEBUG_OBJECT (demux, "reset stream state");
516 for (n = 0; n < demux->num_streams; n++) {
517 demux->stream[n].discont = TRUE;
518 demux->stream[n].last_flow = GST_FLOW_OK;
520 while (demux->stream[n].payloads->len > 0) {
524 last = demux->stream[n].payloads->len - 1;
525 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
526 gst_buffer_replace (&payload->buf, NULL);
527 g_array_remove_index (demux->stream[n].payloads, last);
533 gst_asf_demux_mark_discont (GstASFDemux * demux)
537 GST_DEBUG_OBJECT (demux, "Mark stream discont");
539 for (n = 0; n < demux->num_streams; n++)
540 demux->stream[n].discont = TRUE;
543 /* do a seek in push based mode */
545 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
550 GstSeekType cur_type, stop_type;
555 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
558 stop_type = GST_SEEK_TYPE_NONE;
561 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
563 /* determine packet, by index or by estimation */
564 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
567 (guint) gst_util_uint64_scale (demux->num_packets, cur,
571 if (packet > demux->num_packets) {
572 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
577 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
579 cur = demux->data_offset + (packet * demux->packet_size);
581 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
582 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
583 /* BYTE seek event */
584 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
586 res = gst_pad_push_event (demux->sinkpad, event);
592 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
594 GstClockTime idx_time;
597 GstSeekType cur_type, stop_type;
599 gboolean only_need_update;
600 gboolean keyunit_sync, after, before, next;
605 guint packet, speed_count = 1;
608 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
609 demux->num_packets == 0 || demux->play_time == 0)) {
610 GST_LOG_OBJECT (demux, "stream is not seekable");
614 if (G_UNLIKELY (!demux->activated_streams)) {
615 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
619 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
622 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
623 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
627 if (G_UNLIKELY (rate <= 0.0)) {
628 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
632 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
634 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
635 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
636 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
637 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
638 next = after && !before;
640 if (G_UNLIKELY (demux->streaming)) {
641 /* support it safely needs more segment handling, e.g. closing etc */
643 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
646 /* we can (re)construct the start later on, but not the end */
647 if (stop_type != GST_SEEK_TYPE_NONE) {
648 GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
651 gst_event_ref (event);
652 /* upstream might handle TIME seek, e.g. mms or rtsp,
653 * or not, e.g. http, then we give it a hand */
654 if (!gst_pad_push_event (demux->sinkpad, event))
655 return gst_asf_demux_handle_seek_push (demux, event);
660 /* unlock the streaming thread */
661 if (G_LIKELY (flush)) {
662 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
663 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
665 gst_pad_pause_task (demux->sinkpad);
668 /* grab the stream lock so that streaming cannot continue, for
669 * non flushing seeks when the element is in PAUSED this could block
671 GST_PAD_STREAM_LOCK (demux->sinkpad);
673 /* we now can stop flushing, since we have the stream lock now */
674 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
676 if (G_LIKELY (flush))
677 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop (TRUE));
679 /* operating on copy of segment until we know the seek worked */
680 segment = demux->segment;
682 if (G_UNLIKELY (demux->segment_running && !flush)) {
683 GstSegment newsegment;
686 /* create the segment event to close the current segment */
687 gst_segment_copy_into (&segment, &newsegment);
688 newseg = gst_event_new_segment (&newsegment);
690 gst_asf_demux_send_event_unlocked (demux, newseg);
693 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
694 cur, stop_type, stop, &only_need_update);
696 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
697 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
699 seek_time = segment.start;
701 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
702 * real start of data and segment_start to indexed time for key unit seek*/
703 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
704 &idx_time, &speed_count, next, &eos))) {
708 demux->packet = demux->num_packets;
712 /* First try to query our source to see if it can convert for us. This is
713 the case when our source is an mms stream, notice that in this case
714 gstmms will do a time based seek to get the byte offset, this is not a
715 problem as the seek to this offset needs to happen anway. */
716 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
717 GST_FORMAT_BYTES, &offset)) {
718 packet = (offset - demux->data_offset) / demux->packet_size;
719 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
720 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
721 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
722 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
723 demux->packet_size, packet);
725 /* FIXME: For streams containing video, seek to an earlier position in
726 * the hope of hitting a keyframe and let the sinks throw away the stuff
727 * before the segment start. For audio-only this is unnecessary as every
729 if (flush && (demux->accurate || (keyunit_sync && !next))
730 && demux->num_video_streams > 0) {
731 seek_time -= 5 * GST_SECOND;
736 packet = (guint) gst_util_uint64_scale (demux->num_packets,
737 seek_time, demux->play_time);
739 if (packet > demux->num_packets)
740 packet = demux->num_packets;
743 if (G_LIKELY (keyunit_sync)) {
744 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
745 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
746 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
747 segment.start = idx_time;
748 segment.position = idx_time;
749 segment.time = idx_time;
753 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
755 GST_OBJECT_LOCK (demux);
756 demux->segment = segment;
757 demux->packet = packet;
758 demux->need_newsegment = TRUE;
759 demux->speed_packets = speed_count;
760 gst_asf_demux_reset_stream_state_after_discont (demux);
761 GST_OBJECT_UNLOCK (demux);
764 /* restart our task since it might have been stopped when we did the flush */
765 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
768 /* streaming can continue now */
769 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
775 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
781 demux = GST_ASF_DEMUX (parent);
783 switch (GST_EVENT_TYPE (event)) {
785 GST_LOG_OBJECT (pad, "seek event");
786 ret = gst_asf_demux_handle_seek_event (demux, event);
787 gst_event_unref (event);
790 case GST_EVENT_NAVIGATION:
791 /* just drop these two silently */
792 gst_event_unref (event);
796 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
797 ret = gst_pad_event_default (pad, parent, event);
804 static inline guint32
805 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
809 ret = gst_asf_identify_guid (guids, guid);
811 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
812 gst_asf_get_guid_nick (guids, ret),
813 guid->v1, guid->v2, guid->v3, guid->v4);
825 /* expect is true when the user is expeting an object,
826 * when false, it will give no warnings if the object
830 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
831 guint data_len, AsfObject * object, gboolean expect)
835 if (data_len < ASF_OBJECT_HEADER_SIZE)
838 guid.v1 = GST_READ_UINT32_LE (data + 0);
839 guid.v2 = GST_READ_UINT32_LE (data + 4);
840 guid.v3 = GST_READ_UINT32_LE (data + 8);
841 guid.v4 = GST_READ_UINT32_LE (data + 12);
843 object->size = GST_READ_UINT64_LE (data + 16);
845 /* FIXME: make asf_demux_identify_object_guid() */
846 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
847 if (object->id == ASF_OBJ_UNDEFINED && expect) {
848 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
849 guid.v1, guid.v2, guid.v3, guid.v4);
856 gst_asf_demux_release_old_pads (GstASFDemux * demux)
858 GST_DEBUG_OBJECT (demux, "Releasing old pads");
860 while (demux->old_num_streams > 0) {
861 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
862 gst_event_new_eos ());
863 gst_asf_demux_free_stream (demux,
864 &demux->old_stream[demux->old_num_streams - 1]);
865 --demux->old_num_streams;
867 memset (demux->old_stream, 0, sizeof (demux->old_stream));
868 demux->old_num_streams = 0;
872 gst_asf_demux_chain_headers (GstASFDemux * demux)
876 guint8 *header_data, *data = NULL;
877 const guint8 *cdata = NULL;
880 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
884 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
885 if (obj.id != ASF_OBJ_HEADER)
888 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
890 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
891 if (gst_adapter_available (demux->adapter) < obj.size + 50)
894 data = gst_adapter_take (demux->adapter, obj.size + 50);
897 header_size = obj.size;
898 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
899 if (flow != GST_FLOW_OK)
902 /* calculate where the packet data starts */
903 demux->data_offset = obj.size + 50;
905 /* now parse the beginning of the ASF_OBJ_DATA object */
906 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
909 if (demux->num_streams == 0)
918 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
925 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
926 ("This doesn't seem to be an ASF file"));
928 return GST_FLOW_ERROR;
933 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
934 ("header parsing failed, or no streams found, flow = %s",
935 gst_flow_get_name (flow)));
937 return GST_FLOW_ERROR;
942 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
947 GST_DEBUG_OBJECT (demux, "Aggregating");
949 /* Store the value */
950 stream->last_flow = flow;
952 /* any other error that is not not-linked can be returned right away */
953 if (flow != GST_FLOW_NOT_LINKED)
956 for (i = 0; i < demux->num_streams; i++) {
957 if (demux->stream[i].active) {
958 flow = demux->stream[i].last_flow;
959 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
960 gst_flow_get_name (flow));
961 if (flow != GST_FLOW_NOT_LINKED)
966 /* If we got here, then all our active streams are not linked */
972 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
973 GstBuffer ** p_buf, GstFlowReturn * p_flow)
978 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
981 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
983 if (G_LIKELY (p_flow))
986 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
987 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
988 "+%u", gst_flow_get_name (flow), offset, size);
993 g_assert (*p_buf != NULL);
995 buffer_size = gst_buffer_get_size (*p_buf);
996 if (G_UNLIKELY (buffer_size < size)) {
997 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
998 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
999 gst_buffer_unref (*p_buf);
1000 if (G_LIKELY (p_flow))
1001 *p_flow = GST_FLOW_EOS;
1010 gst_asf_demux_pull_indices (GstASFDemux * demux)
1012 GstBuffer *buf = NULL;
1016 offset = demux->index_offset;
1018 if (G_UNLIKELY (offset == 0)) {
1019 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1023 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1029 gst_buffer_map (buf, &map, GST_MAP_READ);
1030 g_assert (map.size >= 16 + 8);
1031 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1032 gst_buffer_unmap (buf, &map);
1033 gst_buffer_replace (&buf, NULL);
1035 /* check for sanity */
1036 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1037 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1041 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1045 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1046 ", size %u", offset, (guint) obj.size);
1048 offset += obj.size; /* increase before _process_object changes it */
1050 gst_buffer_map (buf, &map, GST_MAP_READ);
1051 g_assert (map.size >= obj.size);
1052 bufdata = (guint8 *) map.data;
1053 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1054 gst_buffer_unmap (buf, &map);
1055 gst_buffer_replace (&buf, NULL);
1057 if (G_UNLIKELY (flow != GST_FLOW_OK))
1062 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1066 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1070 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1071 if (obj.id != ASF_OBJ_DATA) {
1072 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1076 demux->state = GST_ASF_DEMUX_STATE_DATA;
1078 if (!demux->broadcast && obj.size > 50) {
1079 demux->data_size = obj.size - 50;
1080 /* CHECKME: for at least one file this is off by +158 bytes?! */
1081 demux->index_offset = demux->data_offset + demux->data_size;
1083 demux->data_size = 0;
1084 demux->index_offset = 0;
1089 if (!demux->broadcast) {
1090 /* skip object header (24 bytes) and file GUID (16 bytes) */
1091 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1093 demux->num_packets = 0;
1096 if (demux->num_packets == 0)
1097 demux->seekable = FALSE;
1099 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1100 if (demux->data_size == 0 && demux->num_packets > 0) {
1101 demux->data_size = demux->num_packets * demux->packet_size;
1102 demux->index_offset = demux->data_offset + demux->data_size;
1105 /* process pending stream objects and create pads for those */
1106 gst_asf_demux_process_queued_extended_stream_objects (demux);
1108 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1109 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1110 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1111 demux->data_offset, demux->data_size, demux->index_offset);
1117 gst_asf_demux_pull_headers (GstASFDemux * demux)
1121 GstBuffer *buf = NULL;
1126 GST_LOG_OBJECT (demux, "reading headers");
1128 /* pull HEADER object header, so we know its size */
1129 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1132 gst_buffer_map (buf, &map, GST_MAP_READ);
1133 g_assert (map.size >= 16 + 8);
1134 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1135 gst_buffer_unmap (buf, &map);
1136 gst_buffer_replace (&buf, NULL);
1138 if (obj.id != ASF_OBJ_HEADER)
1141 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1143 /* pull HEADER object */
1144 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1148 size = obj.size; /* don't want obj.size changed */
1149 gst_buffer_map (buf, &map, GST_MAP_READ);
1150 g_assert (map.size >= size);
1151 bufdata = (guint8 *) map.data;
1152 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1153 gst_buffer_unmap (buf, &map);
1154 gst_buffer_replace (&buf, NULL);
1156 if (flow != GST_FLOW_OK) {
1157 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1161 /* calculate where the packet data starts */
1162 demux->data_offset = demux->base_offset + obj.size + 50;
1164 /* now pull beginning of DATA object before packet data */
1165 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1169 gst_buffer_map (buf, &map, GST_MAP_READ);
1170 g_assert (map.size >= size);
1171 bufdata = (guint8 *) map.data;
1172 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1175 if (demux->num_streams == 0)
1178 gst_buffer_unmap (buf, &map);
1179 gst_buffer_replace (&buf, NULL);
1187 gst_buffer_unmap (buf, &map);
1188 gst_buffer_replace (&buf, NULL);
1190 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1191 ("This doesn't seem to be an ASF file"));
1200 gst_buffer_unmap (buf, &map);
1201 gst_buffer_replace (&buf, NULL);
1202 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1208 all_streams_prerolled (GstASFDemux * demux)
1210 GstClockTime preroll_time;
1211 guint i, num_no_data = 0;
1213 /* Allow at least 500ms of preroll_time */
1214 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1216 /* returns TRUE as long as there isn't a stream which (a) has data queued
1217 * and (b) the timestamp of last piece of data queued is < demux->preroll
1218 * AND there is at least one other stream with data queued */
1219 for (i = 0; i < demux->num_streams; ++i) {
1220 AsfPayload *last_payload;
1224 stream = &demux->stream[i];
1225 if (G_UNLIKELY (stream->payloads->len == 0)) {
1227 GST_LOG_OBJECT (stream->pad, "no data queued");
1231 last_idx = stream->payloads->len - 1;
1232 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1234 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1235 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1236 GST_TIME_ARGS (preroll_time));
1237 if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1238 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1243 if (G_UNLIKELY (num_no_data == demux->num_streams))
1251 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1256 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1259 /* check for each mutual exclusion group whether it affects this stream */
1260 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1261 if (*mes == stream->id) {
1262 /* we are in this group; let's check if we've already activated streams
1263 * that are in the same group (and hence mutually exclusive to this
1265 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1268 for (i = 0; i < demux->num_streams; ++i) {
1269 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1270 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1271 "to already active stream with ID %d", stream->id,
1272 demux->stream[i].id);
1277 /* we can only be in this group once, let's break out and move on to
1278 * the next mutual exclusion group */
1289 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1293 if (demux->activated_streams)
1296 if (!all_streams_prerolled (demux) && !force) {
1297 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1301 for (i = 0; i < demux->num_streams; ++i) {
1302 AsfStream *stream = &demux->stream[i];
1304 if (stream->payloads->len > 0) {
1305 /* we don't check mutual exclusion stuff here; either we have data for
1306 * a stream, then we active it, or we don't, then we'll ignore it */
1307 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1308 gst_asf_demux_activate_stream (demux, stream);
1310 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1314 gst_asf_demux_release_old_pads (demux);
1316 demux->activated_streams = TRUE;
1317 GST_LOG_OBJECT (demux, "signalling no more pads");
1318 gst_element_no_more_pads (GST_ELEMENT (demux));
1322 /* returns the stream that has a complete payload with the lowest timestamp
1323 * queued, or NULL (we push things by timestamp because during the internal
1324 * prerolling we might accumulate more data then the external queues can take,
1325 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1327 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1329 AsfPayload *best_payload = NULL;
1330 AsfStream *best_stream = NULL;
1333 for (i = 0; i < demux->num_streams; ++i) {
1336 stream = &demux->stream[i];
1338 /* Don't push any data until we have at least one payload that falls within
1339 * the current segment. This way we can remove out-of-segment payloads that
1340 * don't need to be decoded after a seek, sending only data from the
1341 * keyframe directly before our segment start */
1342 if (stream->payloads->len > 0) {
1343 AsfPayload *payload;
1346 last_idx = stream->payloads->len - 1;
1347 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1348 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1349 (payload->ts < demux->segment.start))) {
1350 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1351 GST_DEBUG_OBJECT (stream->pad,
1352 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1353 GST_TIME_ARGS (payload->ts));
1354 demux->segment.start = payload->ts;
1355 demux->segment.time = payload->ts;
1357 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1358 GST_TIME_FORMAT " which is before our segment start %"
1359 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1360 GST_TIME_ARGS (demux->segment.start));
1365 /* Now see if there's a complete payload queued for this stream */
1367 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1368 if (!gst_asf_payload_is_complete (payload))
1371 /* ... and whether its timestamp is lower than the current best */
1372 if (best_stream == NULL || best_payload->ts > payload->ts) {
1373 best_stream = stream;
1374 best_payload = payload;
1382 static GstFlowReturn
1383 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1386 GstFlowReturn ret = GST_FLOW_OK;
1388 if (G_UNLIKELY (!demux->activated_streams)) {
1389 if (!gst_asf_demux_check_activate_streams (demux, force))
1391 /* streams are now activated */
1394 /* wait until we had a chance to "lock on" some payload's timestamp */
1395 if (G_UNLIKELY (demux->need_newsegment
1396 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1399 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1400 AsfPayload *payload;
1402 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1404 /* do we need to send a newsegment event */
1405 if ((G_UNLIKELY (demux->need_newsegment))) {
1407 /* safe default if insufficient upstream info */
1408 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1411 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1412 demux->segment.duration > 0) {
1413 /* slight HACK; prevent clipping of last bit */
1414 demux->segment.stop = demux->segment.duration + demux->in_gap;
1417 /* FIXME : only if ACCURATE ! */
1418 if (G_LIKELY (!demux->accurate
1419 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1420 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1421 GST_TIME_ARGS (payload->ts));
1422 demux->segment.start = payload->ts;
1423 demux->segment.time = payload->ts;
1426 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1429 /* note: we fix up all timestamps to start from 0, so this should be ok */
1430 gst_asf_demux_send_event_unlocked (demux,
1431 gst_event_new_segment (&demux->segment));
1433 /* now post any global tags we may have found */
1434 if (demux->taglist == NULL)
1435 demux->taglist = gst_tag_list_new_empty ();
1437 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1438 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1440 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1441 gst_asf_demux_send_event_unlocked (demux,
1442 gst_event_new_tag ("GstDemuxer", demux->taglist));
1443 demux->taglist = NULL;
1445 demux->need_newsegment = FALSE;
1446 demux->segment_running = TRUE;
1449 /* Do we have tags pending for this stream? */
1450 if (G_UNLIKELY (stream->pending_tags)) {
1451 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1452 gst_pad_push_event (stream->pad,
1453 gst_event_new_tag ("GstDemuxer", stream->pending_tags));
1454 stream->pending_tags = NULL;
1457 /* We have the whole packet now so we should push the packet to
1458 * the src pad now. First though we should check if we need to do
1460 if (G_UNLIKELY (demux->span > 1)) {
1461 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1464 payload->buf = gst_buffer_make_writable (payload->buf);
1466 if (G_LIKELY (!payload->keyframe)) {
1467 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1470 if (G_UNLIKELY (stream->discont)) {
1471 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1472 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1473 stream->discont = FALSE;
1476 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1477 (payload->par_x != stream->par_x) &&
1478 (payload->par_y != stream->par_y))) {
1479 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1480 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1481 stream->par_x = payload->par_x;
1482 stream->par_y = payload->par_y;
1483 stream->caps = gst_caps_make_writable (stream->caps);
1484 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1485 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1486 gst_pad_set_caps (stream->pad, stream->caps);
1489 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1490 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1491 payload->interlaced);
1492 stream->interlaced = payload->interlaced;
1493 stream->caps = gst_caps_make_writable (stream->caps);
1494 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1495 (stream->interlaced ? "mixed" : "progressive"), NULL);
1496 gst_pad_set_caps (stream->pad, stream->caps);
1499 /* (sort of) interpolate timestamps using upstream "frame of reference",
1500 * typically useful for live src, but might (unavoidably) mess with
1501 * position reporting if a live src is playing not so live content
1502 * (e.g. rtspsrc taking some time to fall back to tcp) */
1503 GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1504 if (payload->duration == GST_CLOCK_TIME_NONE
1505 && stream->ext_props.avg_time_per_frame != 0)
1506 GST_BUFFER_DURATION (payload->buf) =
1507 stream->ext_props.avg_time_per_frame * 100;
1509 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1511 /* FIXME: we should really set durations on buffers if we can */
1513 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1514 ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
1515 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1516 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1517 gst_buffer_get_size (payload->buf));
1519 if (stream->active) {
1520 ret = gst_pad_push (stream->pad, payload->buf);
1521 ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1523 gst_buffer_unref (payload->buf);
1526 payload->buf = NULL;
1527 g_array_remove_index (stream->payloads, 0);
1529 /* Break out as soon as we have an issue */
1530 if (G_UNLIKELY (ret != GST_FLOW_OK))
1538 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1542 g_assert (buf != NULL);
1544 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1546 gst_buffer_map (buf, &map, GST_MAP_READ);
1548 /* we return false on buffer too small */
1549 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1550 gst_buffer_unmap (buf, &map);
1554 /* check if it is a header */
1555 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1556 gst_buffer_unmap (buf, &map);
1557 if (obj.id == ASF_OBJ_HEADER) {
1564 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1566 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1567 GstFlowReturn ret = GST_FLOW_OK;
1568 GstBuffer *buf = NULL;
1569 gboolean header = FALSE;
1571 /* TODO maybe we should skip index objects after the data and look
1572 * further for a new header */
1573 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1574 g_assert (buf != NULL);
1575 /* check if it is a header */
1576 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1577 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1578 demux->base_offset = off;
1582 gst_buffer_unref (buf);
1589 gst_asf_demux_loop (GstASFDemux * demux)
1591 GstFlowReturn flow = GST_FLOW_OK;
1592 GstBuffer *buf = NULL;
1594 gboolean sent_eos = FALSE;
1596 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1597 if (!gst_asf_demux_pull_headers (demux)) {
1598 flow = GST_FLOW_ERROR;
1602 gst_asf_demux_pull_indices (demux);
1605 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1607 if (G_UNLIKELY (demux->num_packets != 0
1608 && demux->packet >= demux->num_packets))
1611 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1612 (guint) demux->num_packets);
1614 off = demux->data_offset + (demux->packet * demux->packet_size);
1616 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1617 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1618 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1619 if (flow == GST_FLOW_EOS)
1621 else if (flow == GST_FLOW_FLUSHING) {
1622 GST_DEBUG_OBJECT (demux, "Not fatal");
1628 if (G_LIKELY (demux->speed_packets == 1)) {
1629 GstAsfDemuxParsePacketError err;
1630 err = gst_asf_demux_parse_packet (demux, buf);
1631 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1632 /* when we don't know when the data object ends, we should check
1633 * for a chained asf */
1634 if (demux->num_packets == 0) {
1635 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1636 GST_INFO_OBJECT (demux, "Chained asf found");
1637 demux->base_offset = off;
1638 gst_asf_demux_reset (demux, TRUE);
1639 gst_buffer_unref (buf);
1643 /* FIXME: We should tally up fatal errors and error out only
1644 * after a few broken packets in a row? */
1646 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1647 gst_buffer_unref (buf);
1652 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1658 for (n = 0; n < demux->speed_packets; n++) {
1660 GstAsfDemuxParsePacketError err;
1663 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1664 n * demux->packet_size, demux->packet_size);
1665 err = gst_asf_demux_parse_packet (demux, sub);
1666 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1667 /* when we don't know when the data object ends, we should check
1668 * for a chained asf */
1669 if (demux->num_packets == 0) {
1670 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1671 GST_INFO_OBJECT (demux, "Chained asf found");
1672 demux->base_offset = off + n * demux->packet_size;
1673 gst_asf_demux_reset (demux, TRUE);
1674 gst_buffer_unref (sub);
1675 gst_buffer_unref (buf);
1679 /* FIXME: We should tally up fatal errors and error out only
1680 * after a few broken packets in a row? */
1682 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1686 gst_buffer_unref (sub);
1688 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1689 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1695 /* reset speed pull */
1696 demux->speed_packets = 1;
1699 gst_buffer_unref (buf);
1701 if (G_UNLIKELY (demux->num_packets > 0
1702 && demux->packet >= demux->num_packets)) {
1703 GST_LOG_OBJECT (demux, "reached EOS");
1707 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1708 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1712 /* check if we're at the end of the configured segment */
1713 /* FIXME: check if segment end reached etc. */
1719 /* if we haven't activated our streams yet, this might be because we have
1720 * less data queued than required for preroll; force stream activation and
1721 * send any pending payloads before sending EOS */
1722 if (!demux->activated_streams)
1723 gst_asf_demux_push_complete_payloads (demux, TRUE);
1725 /* we want to push an eos or post a segment-done in any case */
1726 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1729 /* for segment playback we need to post when (in stream time)
1730 * we stopped, this is either stop (when set) or the duration. */
1731 if ((stop = demux->segment.stop) == -1)
1732 stop = demux->segment.duration;
1734 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1735 gst_element_post_message (GST_ELEMENT_CAST (demux),
1736 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1738 gst_asf_demux_send_event_unlocked (demux,
1739 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1740 } else if (flow != GST_FLOW_EOS) {
1741 /* check if we have a chained asf, in case, we don't eos yet */
1742 if (gst_asf_demux_check_chained_asf (demux)) {
1743 GST_INFO_OBJECT (demux, "Chained ASF starting");
1744 gst_asf_demux_reset (demux, TRUE);
1748 /* normal playback, send EOS to all linked pads */
1749 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1750 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1752 /* ... and fall through to pause */
1756 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1757 gst_flow_get_name (flow));
1758 demux->segment_running = FALSE;
1759 gst_pad_pause_task (demux->sinkpad);
1761 /* For the error cases (not EOS) */
1763 if (flow == GST_FLOW_EOS)
1764 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1765 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1766 /* Post an error. Hopefully something else already has, but if not... */
1767 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1768 (_("Internal data stream error.")),
1769 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1778 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1779 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1780 flow = GST_FLOW_EOS;
1784 /* See FIXMEs above */
1787 gst_buffer_unref (buf);
1788 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1789 ("Error parsing ASF packet %u", (guint) demux->packet));
1790 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1791 flow = GST_FLOW_ERROR;
1797 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1798 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1799 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1802 gst_asf_demux_check_header (GstASFDemux * demux)
1805 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
1806 ASF_OBJECT_HEADER_SIZE);
1807 if (cdata == NULL) /* need more data */
1808 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1810 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1811 if (obj.id != ASF_OBJ_HEADER) {
1812 return GST_ASF_DEMUX_CHECK_HEADER_NO;
1814 return GST_ASF_DEMUX_CHECK_HEADER_YES;
1818 static GstFlowReturn
1819 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1821 GstFlowReturn ret = GST_FLOW_OK;
1824 demux = GST_ASF_DEMUX (parent);
1826 GST_LOG_OBJECT (demux,
1827 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
1828 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
1829 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1831 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1832 GST_DEBUG_OBJECT (demux, "received DISCONT");
1833 gst_asf_demux_mark_discont (demux);
1836 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1837 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1838 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1839 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1840 ", interpolation gap: %" GST_TIME_FORMAT,
1841 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1844 gst_adapter_push (demux->adapter, buf);
1846 switch (demux->state) {
1847 case GST_ASF_DEMUX_STATE_INDEX:{
1848 gint result = gst_asf_demux_check_header (demux);
1849 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
1852 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1853 /* we don't care about this, probably an index */
1854 /* TODO maybe would be smarter to skip all the indices
1855 * until we got a new header or EOS to decide */
1856 GST_LOG_OBJECT (demux, "Received index object, its EOS");
1859 GST_INFO_OBJECT (demux, "Chained asf starting");
1860 /* cleanup and get ready for a chained asf */
1861 gst_asf_demux_reset (demux, TRUE);
1865 case GST_ASF_DEMUX_STATE_HEADER:{
1866 ret = gst_asf_demux_chain_headers (demux);
1867 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1869 /* otherwise fall through */
1871 case GST_ASF_DEMUX_STATE_DATA:
1875 data_size = demux->packet_size;
1877 while (gst_adapter_available (demux->adapter) >= data_size) {
1879 GstAsfDemuxParsePacketError err;
1881 /* we don't know the length of the stream
1882 * check for a chained asf everytime */
1883 if (demux->num_packets == 0) {
1884 gint result = gst_asf_demux_check_header (demux);
1886 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1887 GST_INFO_OBJECT (demux, "Chained asf starting");
1888 /* cleanup and get ready for a chained asf */
1889 gst_asf_demux_reset (demux, TRUE);
1892 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1893 && demux->packet >= demux->num_packets)) {
1894 /* do not overshoot data section when streaming */
1898 buf = gst_adapter_take_buffer (demux->adapter, data_size);
1900 /* FIXME: We should tally up fatal errors and error out only
1901 * after a few broken packets in a row? */
1902 err = gst_asf_demux_parse_packet (demux, buf);
1904 gst_buffer_unref (buf);
1906 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
1907 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1909 GST_WARNING_OBJECT (demux, "Parse error");
1911 if (demux->packet >= 0)
1914 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1915 && demux->packet >= demux->num_packets)) {
1916 demux->state = GST_ASF_DEMUX_STATE_INDEX;
1921 g_assert_not_reached ();
1925 if (ret != GST_FLOW_OK)
1926 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1932 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1938 static inline gboolean
1939 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1941 if (*p_size < num_bytes)
1944 *p_data += num_bytes;
1945 *p_size -= num_bytes;
1949 static inline guint8
1950 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1954 g_assert (*p_size >= 1);
1955 ret = GST_READ_UINT8 (*p_data);
1956 *p_data += sizeof (guint8);
1957 *p_size -= sizeof (guint8);
1961 static inline guint16
1962 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1966 g_assert (*p_size >= 2);
1967 ret = GST_READ_UINT16_LE (*p_data);
1968 *p_data += sizeof (guint16);
1969 *p_size -= sizeof (guint16);
1973 static inline guint32
1974 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1978 g_assert (*p_size >= 4);
1979 ret = GST_READ_UINT32_LE (*p_data);
1980 *p_data += sizeof (guint32);
1981 *p_size -= sizeof (guint32);
1985 static inline guint64
1986 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1990 g_assert (*p_size >= 8);
1991 ret = GST_READ_UINT64_LE (*p_data);
1992 *p_data += sizeof (guint64);
1993 *p_size -= sizeof (guint64);
1997 static inline guint32
1998 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
2005 g_assert (*p_size >= 1);
2006 return gst_asf_demux_get_uint8 (p_data, p_size);
2009 g_assert (*p_size >= 2);
2010 return gst_asf_demux_get_uint16 (p_data, p_size);
2013 g_assert (*p_size >= 4);
2014 return gst_asf_demux_get_uint32 (p_data, p_size);
2017 g_assert_not_reached ();
2024 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2025 guint8 ** p_data, guint64 * p_size)
2029 if (*p_size < num_bytes_to_read)
2032 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2033 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2035 *p_data += num_bytes_to_read;
2036 *p_size -= num_bytes_to_read;
2042 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2043 guint8 ** p_data, guint64 * p_size)
2047 if (*p_size < num_bytes_to_read)
2050 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2051 *p_data += num_bytes_to_read;
2052 *p_size -= num_bytes_to_read;
2057 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2058 guint8 ** p_data, guint64 * p_size)
2068 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2071 *p_strlen = s_length;
2073 if (s_length == 0) {
2074 GST_WARNING ("zero-length string");
2075 *p_str = g_strdup ("");
2079 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2082 g_assert (s != NULL);
2084 /* just because They don't exist doesn't
2085 * mean They are not out to get you ... */
2086 if (s[s_length - 1] != '\0') {
2087 s = g_realloc (s, s_length + 1);
2091 *p_str = (gchar *) s;
2097 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2099 g_assert (*p_size >= 4 * sizeof (guint32));
2101 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2102 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2103 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2104 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2108 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2111 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2114 /* WAVEFORMATEX Structure */
2115 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2116 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2117 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2118 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2119 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2120 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2121 /* Codec specific data size */
2122 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2127 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2130 if (*p_size < (4 + 4 + 1 + 2))
2133 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2134 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2135 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2136 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2141 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2142 guint8 ** p_data, guint64 * p_size)
2144 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2147 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2148 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2149 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2150 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2151 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2152 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2153 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2154 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2155 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2156 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2157 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2162 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2166 for (i = 0; i < demux->num_streams; i++) {
2167 if (demux->stream[i].id == id)
2168 return &demux->stream[i];
2171 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2176 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2177 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2181 gst_pad_use_fixed_caps (src_pad);
2182 gst_pad_set_caps (src_pad, caps);
2184 gst_pad_set_event_function (src_pad,
2185 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2186 gst_pad_set_query_function (src_pad,
2187 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2189 stream = &demux->stream[demux->num_streams];
2190 stream->caps = caps;
2191 stream->pad = src_pad;
2193 stream->fps_known = !is_video; /* bit hacky for audio */
2194 stream->is_video = is_video;
2195 stream->pending_tags = tags;
2196 stream->discont = TRUE;
2200 st = gst_caps_get_structure (caps, 0);
2201 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2202 par_x > 0 && par_y > 0) {
2203 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2204 stream->par_x = par_x;
2205 stream->par_y = par_y;
2209 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2211 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2212 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2214 ++demux->num_streams;
2216 stream->active = FALSE;
2220 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2221 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2223 GstTagList *tags = NULL;
2224 GstBuffer *extradata = NULL;
2227 guint16 size_left = 0;
2228 gchar *codec_name = NULL;
2231 size_left = audio->size;
2233 /* Create the audio pad */
2234 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2236 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2239 /* Swallow up any left over data and set up the
2240 * standard properties from the header info */
2242 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2243 "codec specific data", size_left);
2245 g_assert (size_left <= *p_size);
2246 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2249 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2250 * additional two bytes indicating extradata. */
2251 /* FIXME: Handle the channel reorder map here */
2252 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2253 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2256 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2257 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2260 /* Informing about that audio format we just added */
2262 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2263 g_free (codec_name);
2267 gst_buffer_unref (extradata);
2269 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2270 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2271 audio->codec_tag, tags);
2273 ++demux->num_audio_streams;
2275 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2279 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2280 asf_stream_video_format * video, guint16 id,
2281 guint8 ** p_data, guint64 * p_size)
2283 GstTagList *tags = NULL;
2284 GstBuffer *extradata = NULL;
2289 gchar *codec_name = NULL;
2290 gint size_left = video->size - 40;
2292 /* Create the video pad */
2293 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2294 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2297 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2299 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2300 g_assert (size_left <= *p_size);
2301 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2304 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2306 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2307 caps = gst_riff_create_video_caps (video->tag, NULL,
2308 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2311 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2312 G_TYPE_UINT, video->tag, NULL);
2317 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2318 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2319 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2320 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2325 /* retry with the global metadata */
2326 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2327 demux->global_metadata);
2328 s = demux->global_metadata;
2329 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2330 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2331 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2332 if (ax > 0 && ay > 0)
2333 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2337 s = gst_caps_get_structure (caps, 0);
2338 gst_structure_remove_field (s, "framerate");
2341 /* add fourcc format to caps, some proprietary decoders seem to need it */
2342 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2343 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2347 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2348 g_free (codec_name);
2352 gst_buffer_unref (extradata);
2354 GST_INFO ("Adding video stream #%u, id %u, codec %"
2355 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2356 GST_FOURCC_ARGS (video->tag), video->tag);
2358 ++demux->num_video_streams;
2360 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2364 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2366 if (!stream->active) {
2367 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2368 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2369 gst_pad_set_active (stream->pad, TRUE);
2370 gst_pad_set_caps (stream->pad, stream->caps);
2371 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2372 gst_pad_push_event (stream->pad, gst_event_new_stream_start ());
2373 stream->active = TRUE;
2378 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2381 AsfCorrectionType correction_type;
2382 AsfStreamType stream_type;
2383 GstClockTime time_offset;
2384 gboolean is_encrypted G_GNUC_UNUSED;
2388 guint stream_specific_size;
2389 guint type_specific_size G_GNUC_UNUSED;
2390 guint unknown G_GNUC_UNUSED;
2392 /* Get the rest of the header's header */
2393 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2394 goto not_enough_data;
2396 gst_asf_demux_get_guid (&guid, &data, &size);
2397 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2399 gst_asf_demux_get_guid (&guid, &data, &size);
2400 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2402 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2404 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2405 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2407 flags = gst_asf_demux_get_uint16 (&data, &size);
2408 stream_id = flags & 0x7f;
2409 is_encrypted = ! !((flags & 0x8000) << 15);
2410 unknown = gst_asf_demux_get_uint32 (&data, &size);
2412 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2413 stream_id, GST_TIME_ARGS (time_offset));
2415 switch (stream_type) {
2416 case ASF_STREAM_AUDIO:{
2417 asf_stream_audio audio_object;
2419 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2420 goto not_enough_data;
2422 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2425 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2428 switch (correction_type) {
2429 case ASF_CORRECTION_ON:{
2430 guint span, packet_size, chunk_size, data_size, silence_data;
2432 GST_INFO ("Using error correction");
2434 if (size < (1 + 2 + 2 + 2 + 1))
2435 goto not_enough_data;
2437 span = gst_asf_demux_get_uint8 (&data, &size);
2438 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2439 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2440 data_size = gst_asf_demux_get_uint16 (&data, &size);
2441 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2443 /* FIXME: shouldn't this be per-stream? */
2446 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2447 packet_size, chunk_size, data_size, span, silence_data);
2449 if (demux->span > 1) {
2450 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2451 /* Disable descrambling */
2454 /* FIXME: this else branch was added for
2455 * weird_al_yankovic - the saga begins.asf */
2456 demux->ds_packet_size = packet_size;
2457 demux->ds_chunk_size = chunk_size;
2460 /* Descambling is enabled */
2461 demux->ds_packet_size = packet_size;
2462 demux->ds_chunk_size = chunk_size;
2465 /* Now skip the rest of the silence data */
2467 gst_bytestream_flush (demux->bs, data_size - 1);
2469 /* FIXME: CHECKME. And why -1? */
2470 if (data_size > 1) {
2471 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2472 goto not_enough_data;
2478 case ASF_CORRECTION_OFF:{
2479 GST_INFO ("Error correction off");
2480 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2481 goto not_enough_data;
2485 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2486 ("Audio stream using unknown error correction"));
2493 case ASF_STREAM_VIDEO:{
2494 asf_stream_video_format video_format_object;
2495 asf_stream_video video_object;
2498 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2499 goto not_enough_data;
2501 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2503 GST_INFO ("object is a video stream with %u bytes of "
2504 "additional data", vsize);
2506 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2508 goto not_enough_data;
2511 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2518 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2523 return gst_asf_demux_get_stream (demux, stream_id);
2527 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2528 /* we'll error out later if we found no streams */
2533 static const gchar *
2534 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2538 const gchar *asf_name;
2539 const gchar *gst_name;
2542 "WM/Genre", GST_TAG_GENRE}, {
2543 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2544 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2545 "WM/Picture", GST_TAG_IMAGE}, {
2546 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2547 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2548 "WM/Year", GST_TAG_DATE_TIME}
2549 /* { "WM/Composer", GST_TAG_COMPOSER } */
2554 if (name_utf8 == NULL) {
2555 GST_WARNING ("Failed to convert name to UTF8, skipping");
2559 out = strlen (name_utf8);
2561 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2562 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2563 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2564 return tags[i].gst_name;
2571 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2573 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2577 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2579 if (taglist == NULL)
2582 if (gst_tag_list_is_empty (taglist)) {
2583 gst_tag_list_free (taglist);
2587 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2589 gst_tag_list_free (demux->taglist);
2590 gst_tag_list_free (taglist);
2592 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2595 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2596 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2597 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2600 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2604 const guint8 *img_data = NULL;
2605 guint32 img_data_len = 0;
2606 guint8 pic_type = 0;
2608 gst_byte_reader_init (&r, tag_data, tag_data_len);
2610 /* skip mime type string (we don't trust it and do our own typefinding),
2611 * and also skip the description string, since we don't use it */
2612 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2613 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2614 !gst_byte_reader_skip_string_utf16 (&r) ||
2615 !gst_byte_reader_skip_string_utf16 (&r) ||
2616 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2617 goto not_enough_data;
2621 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2622 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2628 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2629 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2634 /* Extended Content Description Object */
2635 static GstFlowReturn
2636 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2639 /* Other known (and unused) 'text/unicode' metadata available :
2642 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2643 * WMFSDKVersion = 9.00.00.2980
2644 * WMFSDKNeeded = 0.0.0.0000
2645 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2646 * WM/Publisher = 4AD
2648 * WM/ProviderRating = 8
2649 * WM/ProviderStyle = Rock (similar to WM/Genre)
2650 * WM/GenreID (similar to WM/Genre)
2651 * WM/TrackNumber (same as WM/Track but as a string)
2653 * Other known (and unused) 'non-text' metadata available :
2659 * We might want to read WM/TrackNumber and use atoi() if we don't have
2663 GstTagList *taglist;
2664 guint16 blockcount, i;
2666 GST_INFO_OBJECT (demux, "object is an extended content description");
2668 taglist = gst_tag_list_new_empty ();
2670 /* Content Descriptor Count */
2672 goto not_enough_data;
2674 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2676 for (i = 1; i <= blockcount; ++i) {
2677 const gchar *gst_tag_name;
2681 GValue tag_value = { 0, };
2684 gchar *name_utf8 = NULL;
2688 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2689 goto not_enough_data;
2693 goto not_enough_data;
2695 /* Descriptor Value Data Type */
2696 datatype = gst_asf_demux_get_uint16 (&data, &size);
2698 /* Descriptor Value (not really a string, but same thing reading-wise) */
2699 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2701 goto not_enough_data;
2705 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2707 if (name_utf8 != NULL) {
2708 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2710 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2711 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2714 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2717 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2720 /* get rid of tags with empty value */
2721 if (value_utf8 != NULL && *value_utf8 != '\0') {
2722 GST_DEBUG ("string value %s", value_utf8);
2724 value_utf8[out] = '\0';
2726 if (gst_tag_name != NULL) {
2727 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
2728 guint year = atoi (value_utf8);
2731 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
2732 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
2734 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2735 guint id3v1_genre_id;
2736 const gchar *genre_str;
2738 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2739 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2740 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2741 g_free (value_utf8);
2742 value_utf8 = g_strdup (genre_str);
2747 /* convert tag from string to other type if required */
2748 tag_type = gst_tag_get_type (gst_tag_name);
2749 g_value_init (&tag_value, tag_type);
2750 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2751 GValue from_val = { 0, };
2753 g_value_init (&from_val, G_TYPE_STRING);
2754 g_value_set_string (&from_val, value_utf8);
2755 if (!g_value_transform (&from_val, &tag_value)) {
2756 GST_WARNING_OBJECT (demux,
2757 "Could not transform string tag to " "%s tag type %s",
2758 gst_tag_name, g_type_name (tag_type));
2759 g_value_unset (&tag_value);
2761 g_value_unset (&from_val);
2766 GST_DEBUG ("Setting metadata");
2767 g_value_init (&tag_value, G_TYPE_STRING);
2768 g_value_set_string (&tag_value, value_utf8);
2770 } else if (value_utf8 == NULL) {
2771 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2773 GST_DEBUG ("Skipping empty string value for %s",
2774 GST_STR_NULL (gst_tag_name));
2776 g_free (value_utf8);
2779 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2781 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2782 GST_FIXME ("Unhandled byte array tag %s",
2783 GST_STR_NULL (gst_tag_name));
2786 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2792 case ASF_DEMUX_DATA_TYPE_DWORD:{
2793 guint uint_val = GST_READ_UINT32_LE (value);
2795 /* this is the track number */
2796 g_value_init (&tag_value, G_TYPE_UINT);
2798 /* WM/Track counts from 0 */
2799 if (!strcmp (name_utf8, "WM/Track"))
2802 g_value_set_uint (&tag_value, uint_val);
2806 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2811 if (G_IS_VALUE (&tag_value)) {
2813 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2815 /* WM/TrackNumber is more reliable than WM/Track, since the latter
2816 * is supposed to have a 0 base but is often wrongly written to start
2817 * from 1 as well, so prefer WM/TrackNumber when we have it: either
2818 * replace the value added earlier from WM/Track or put it first in
2819 * the list, so that it will get picked up by _get_uint() */
2820 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2821 merge_mode = GST_TAG_MERGE_REPLACE;
2823 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2826 GST_DEBUG ("Setting global metadata %s", name_utf8);
2827 gst_structure_set_value (demux->global_metadata, name_utf8,
2831 g_value_unset (&tag_value);
2840 gst_asf_demux_add_global_tags (demux, taglist);
2847 GST_WARNING ("Unexpected end of data parsing ext content desc object");
2848 gst_tag_list_free (taglist);
2849 return GST_FLOW_OK; /* not really fatal */
2853 static GstStructure *
2854 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2859 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2861 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2864 s = gst_caps_get_structure (demux->metadata, i);
2865 if (gst_structure_has_name (s, sname))
2869 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
2871 /* try lookup again; demux->metadata took ownership of the structure, so we
2872 * can't really make any assumptions about what happened to it, so we can't
2873 * just return it directly after appending it */
2874 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2877 static GstFlowReturn
2878 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2881 guint16 blockcount, i;
2883 GST_INFO_OBJECT (demux, "object is a metadata object");
2885 /* Content Descriptor Count */
2887 goto not_enough_data;
2889 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2891 for (i = 0; i < blockcount; ++i) {
2893 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
2894 guint32 data_len, ival;
2897 if (size < (2 + 2 + 2 + 2 + 4))
2898 goto not_enough_data;
2900 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2901 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2902 name_len = gst_asf_demux_get_uint16 (&data, &size);
2903 data_type = gst_asf_demux_get_uint16 (&data, &size);
2904 data_len = gst_asf_demux_get_uint32 (&data, &size);
2906 if (size < name_len + data_len)
2907 goto not_enough_data;
2909 /* convert name to UTF-8 */
2910 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2912 gst_asf_demux_skip_bytes (name_len, &data, &size);
2914 if (name_utf8 == NULL) {
2915 GST_WARNING ("Failed to convert value name to UTF8, skipping");
2916 gst_asf_demux_skip_bytes (data_len, &data, &size);
2920 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2921 gst_asf_demux_skip_bytes (data_len, &data, &size);
2929 goto not_enough_data;
2932 ival = gst_asf_demux_get_uint32 (&data, &size);
2934 /* skip anything else there may be, just in case */
2935 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2937 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2938 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2942 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2948 GST_WARNING ("Unexpected end of data parsing metadata object");
2949 return GST_FLOW_OK; /* not really fatal */
2953 static GstFlowReturn
2954 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2956 GstFlowReturn ret = GST_FLOW_OK;
2957 guint32 i, num_objects;
2958 guint8 unknown G_GNUC_UNUSED;
2960 /* Get the rest of the header's header */
2961 if (size < (4 + 1 + 1))
2962 goto not_enough_data;
2964 num_objects = gst_asf_demux_get_uint32 (&data, &size);
2965 unknown = gst_asf_demux_get_uint8 (&data, &size);
2966 unknown = gst_asf_demux_get_uint8 (&data, &size);
2968 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2970 /* Loop through the header's objects, processing those */
2971 for (i = 0; i < num_objects; ++i) {
2972 GST_INFO_OBJECT (demux, "reading header part %u", i);
2973 ret = gst_asf_demux_process_object (demux, &data, &size);
2974 if (ret != GST_FLOW_OK) {
2975 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2984 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2985 ("short read parsing HEADER object"));
2986 return GST_FLOW_ERROR;
2990 static GstFlowReturn
2991 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2993 guint64 creation_time G_GNUC_UNUSED;
2994 guint64 file_size G_GNUC_UNUSED;
2995 guint64 send_time G_GNUC_UNUSED;
2996 guint64 packets_count, play_time, preroll;
2997 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
2999 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3000 goto not_enough_data;
3002 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3003 file_size = gst_asf_demux_get_uint64 (&data, &size);
3004 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3005 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3006 play_time = gst_asf_demux_get_uint64 (&data, &size);
3007 send_time = gst_asf_demux_get_uint64 (&data, &size);
3008 preroll = gst_asf_demux_get_uint64 (&data, &size);
3009 flags = gst_asf_demux_get_uint32 (&data, &size);
3010 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3011 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3012 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3014 demux->broadcast = ! !(flags & 0x01);
3015 demux->seekable = ! !(flags & 0x02);
3017 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3018 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3019 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3021 if (demux->broadcast) {
3022 /* these fields are invalid if the broadcast flag is set */
3027 if (min_pktsize != max_pktsize)
3028 goto non_fixed_packet_size;
3030 demux->packet_size = max_pktsize;
3032 /* FIXME: do we need send_time as well? what is it? */
3033 if ((play_time * 100) >= (preroll * GST_MSECOND))
3034 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3036 demux->play_time = 0;
3038 demux->preroll = preroll * GST_MSECOND;
3040 /* initial latency */
3041 demux->latency = demux->preroll;
3043 if (demux->play_time == 0)
3044 demux->seekable = FALSE;
3046 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3047 GST_TIME_ARGS (demux->play_time));
3048 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3049 GST_TIME_ARGS (demux->preroll));
3051 if (demux->play_time > 0) {
3052 demux->segment.duration = demux->play_time;
3055 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3057 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3062 non_fixed_packet_size:
3064 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3065 ("packet size must be fixed"));
3066 return GST_FLOW_ERROR;
3070 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3071 ("short read parsing FILE object"));
3072 return GST_FLOW_ERROR;
3076 /* Content Description Object */
3077 static GstFlowReturn
3078 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3082 const gchar *gst_tag;
3087 GST_TAG_TITLE, 0, NULL}, {
3088 GST_TAG_ARTIST, 0, NULL}, {
3089 GST_TAG_COPYRIGHT, 0, NULL}, {
3090 GST_TAG_DESCRIPTION, 0, NULL}, {
3091 GST_TAG_COMMENT, 0, NULL}
3093 GstTagList *taglist;
3094 GValue value = { 0 };
3098 GST_INFO_OBJECT (demux, "object is a comment");
3100 if (size < (2 + 2 + 2 + 2 + 2))
3101 goto not_enough_data;
3103 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3104 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3105 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3106 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3107 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3109 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3110 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3111 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3113 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3114 if (size < tags[i].val_length)
3115 goto not_enough_data;
3117 /* might be just '/0', '/0'... */
3118 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3119 /* convert to UTF-8 */
3120 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3121 "UTF-8", "UTF-16LE", &in, &out, NULL);
3123 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3126 /* parse metadata into taglist */
3127 taglist = gst_tag_list_new_empty ();
3128 g_value_init (&value, G_TYPE_STRING);
3129 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3130 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3131 g_value_set_string (&value, tags[i].val_utf8);
3132 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3133 tags[i].gst_tag, &value, NULL);
3136 g_value_unset (&value);
3138 gst_asf_demux_add_global_tags (demux, taglist);
3140 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3141 g_free (tags[i].val_utf8);
3147 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3148 "comment tag section %d, skipping comment object", i);
3149 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3150 g_free (tags[i].val_utf8);
3151 return GST_FLOW_OK; /* not really fatal */
3155 static GstFlowReturn
3156 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3159 guint16 num_streams, i;
3163 goto not_enough_data;
3165 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3167 GST_INFO ("object is a bitrate properties object with %u streams",
3170 if (size < (num_streams * (2 + 4)))
3171 goto not_enough_data;
3173 for (i = 0; i < num_streams; ++i) {
3177 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3178 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3180 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3181 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3182 stream = gst_asf_demux_get_stream (demux, stream_id);
3184 if (stream->pending_tags == NULL) {
3185 stream->pending_tags =
3186 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3189 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3192 GST_WARNING ("stream id %u is too large", stream_id);
3200 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3201 return GST_FLOW_OK; /* not really fatal */
3205 static GstFlowReturn
3206 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3209 GstFlowReturn ret = GST_FLOW_OK;
3212 /* Get the rest of the header's header */
3213 if (size < (16 + 2 + 4))
3214 goto not_enough_data;
3216 /* skip GUID and two other bytes */
3217 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3218 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3220 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3222 /* FIXME: does data_size include the rest of the header that we have read? */
3223 if (hdr_size > size)
3224 goto not_enough_data;
3226 while (hdr_size > 0) {
3227 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3228 if (ret != GST_FLOW_OK)
3236 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3237 ("short read parsing extended header object"));
3238 return GST_FLOW_ERROR;
3242 static GstFlowReturn
3243 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3249 goto not_enough_data;
3251 if (demux->languages) {
3252 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3253 g_strfreev (demux->languages);
3254 demux->languages = NULL;
3255 demux->num_languages = 0;
3258 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3259 GST_LOG ("%u languages:", demux->num_languages);
3261 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3262 for (i = 0; i < demux->num_languages; ++i) {
3263 guint8 len, *lang_data = NULL;
3266 goto not_enough_data;
3267 len = gst_asf_demux_get_uint8 (&data, &size);
3268 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3271 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3274 /* truncate "en-us" etc. to just "en" */
3275 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3278 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3279 demux->languages[i] = utf8;
3282 goto not_enough_data;
3290 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3291 g_free (demux->languages);
3292 demux->languages = NULL;
3293 return GST_FLOW_OK; /* not fatal */
3297 static GstFlowReturn
3298 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3301 GstClockTime interval;
3304 if (size < (16 + 8 + 4 + 4))
3305 goto not_enough_data;
3308 gst_asf_demux_skip_bytes (16, &data, &size);
3309 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3310 gst_asf_demux_skip_bytes (4, &data, &size);
3311 count = gst_asf_demux_get_uint32 (&data, &size);
3313 demux->sidx_interval = interval;
3314 demux->sidx_num_entries = count;
3315 g_free (demux->sidx_entries);
3316 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3318 for (i = 0; i < count; ++i) {
3319 if (G_UNLIKELY (size <= 6))
3321 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3322 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3323 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3324 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3325 demux->sidx_entries[i].count);
3328 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3335 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3336 return GST_FLOW_OK; /* not fatal */
3340 static GstFlowReturn
3341 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3342 guint8 * data, guint64 size)
3348 if (size < 16 + 2 + (2 * 2))
3349 goto not_enough_data;
3351 gst_asf_demux_get_guid (&guid, &data, &size);
3352 num = gst_asf_demux_get_uint16 (&data, &size);
3355 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3359 if (size < (num * sizeof (guint16)))
3360 goto not_enough_data;
3362 /* read mutually exclusive stream numbers */
3363 mes = g_new (guint8, num + 1);
3364 for (i = 0; i < num; ++i) {
3365 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3366 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3369 /* add terminator so we can easily get the count or know when to stop */
3370 mes[i] = (guint8) - 1;
3372 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3379 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3380 return GST_FLOW_OK; /* not absolutely fatal */
3384 static GstFlowReturn
3385 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3388 AsfStreamExtProps esp;
3389 AsfStream *stream = NULL;
3390 AsfObject stream_obj;
3391 guint16 stream_name_count;
3392 guint16 num_payload_ext;
3394 guint8 *stream_obj_data = NULL;
3397 guint i, stream_num;
3400 obj_size = (guint) size;
3403 goto not_enough_data;
3406 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3407 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3408 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3409 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3410 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3411 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3412 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3413 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3414 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3415 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3416 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3417 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3418 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3419 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3420 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3422 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3423 GST_TIME_ARGS (esp.start_time));
3424 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3425 GST_TIME_ARGS (esp.end_time));
3426 GST_INFO ("flags = %08x", esp.flags);
3427 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3428 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3429 GST_INFO ("stream number = %u", stream_num);
3430 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3431 (esp.lang_idx < demux->num_languages) ?
3432 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3433 GST_INFO ("stream name count = %u", stream_name_count);
3435 /* read stream names */
3436 for (i = 0; i < stream_name_count; ++i) {
3437 guint16 stream_lang_idx G_GNUC_UNUSED;
3438 gchar *stream_name = NULL;
3441 goto not_enough_data;
3442 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3443 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3444 goto not_enough_data;
3445 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3446 g_free (stream_name); /* TODO: store names in struct */
3449 /* read payload extension systems stuff */
3450 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3452 if (num_payload_ext > 0)
3453 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3455 esp.payload_extensions = NULL;
3457 for (i = 0; i < num_payload_ext; ++i) {
3458 AsfPayloadExtension ext;
3460 guint32 sys_info_len;
3462 if (size < 16 + 2 + 4)
3463 goto not_enough_data;
3465 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3466 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3467 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3469 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3470 GST_LOG ("payload systems info len = %u", sys_info_len);
3471 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3472 goto not_enough_data;
3474 esp.payload_extensions[i] = ext;
3477 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3479 /* there might be an optional STREAM_INFO object here now; if not, we
3480 * should have parsed the corresponding stream info object already (since
3481 * we are parsing the extended stream properties objects delayed) */
3483 stream = gst_asf_demux_get_stream (demux, stream_num);
3487 /* get size of the stream object */
3488 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3489 goto not_enough_data;
3491 if (stream_obj.id != ASF_OBJ_STREAM)
3492 goto expected_stream_object;
3494 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3495 stream_obj.size > (10 * 1024 * 1024))
3496 goto not_enough_data;
3498 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3500 /* process this stream object later after all the other 'normal' ones
3501 * have been processed (since the others are more important/non-hidden) */
3502 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3503 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3504 goto not_enough_data;
3506 /* parse stream object */
3507 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3508 g_free (stream_obj_data);
3513 stream->ext_props = esp;
3515 /* try to set the framerate */
3516 if (stream->is_video && stream->caps) {
3517 GValue framerate = { 0 };
3521 g_value_init (&framerate, GST_TYPE_FRACTION);
3523 num = GST_SECOND / 100;
3524 denom = esp.avg_time_per_frame;
3526 /* avoid division by 0, assume 25/1 framerate */
3527 denom = GST_SECOND / 2500;
3530 gst_value_set_fraction (&framerate, num, denom);
3532 stream->caps = gst_caps_make_writable (stream->caps);
3533 s = gst_caps_get_structure (stream->caps, 0);
3534 gst_structure_set_value (s, "framerate", &framerate);
3535 g_value_unset (&framerate);
3536 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3537 num, denom, ((gdouble) num) / denom);
3540 /* add language info now if we have it */
3541 if (stream->ext_props.lang_idx < demux->num_languages) {
3542 if (stream->pending_tags == NULL)
3543 stream->pending_tags = gst_tag_list_new_empty ();
3544 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3545 demux->languages[stream->ext_props.lang_idx]);
3546 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3547 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3551 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3559 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3560 return GST_FLOW_OK; /* not absolutely fatal */
3562 expected_stream_object:
3564 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3565 "object: expected embedded stream object, but got %s object instead!",
3566 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3567 return GST_FLOW_OK; /* not absolutely fatal */
3571 static const gchar *
3572 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3576 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3577 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3578 nick += strlen ("ASF_OBJ_");
3580 if (demux->objpath == NULL) {
3581 demux->objpath = g_strdup (nick);
3585 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3586 g_free (demux->objpath);
3587 demux->objpath = newpath;
3590 return (const gchar *) demux->objpath;
3594 gst_asf_demux_pop_obj (GstASFDemux * demux)
3598 if ((s = g_strrstr (demux->objpath, "/"))) {
3601 g_free (demux->objpath);
3602 demux->objpath = NULL;
3607 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3612 /* Parse the queued extended stream property objects and add the info
3613 * to the existing streams or add the new embedded streams, but without
3614 * activating them yet */
3615 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3616 g_slist_length (demux->ext_stream_props));
3618 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3619 GstBuffer *buf = GST_BUFFER (l->data);
3622 gst_buffer_map (buf, &map, GST_MAP_READ);
3624 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3625 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
3626 gst_buffer_unmap (buf, &map);
3627 gst_buffer_unref (buf);
3629 g_slist_free (demux->ext_stream_props);
3630 demux->ext_stream_props = NULL;
3635 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3639 for (i = 0; i < demux->num_streams; ++i) {
3644 stream = &demux->stream[i];
3646 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3648 if (stream->active) {
3649 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3654 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3657 /* check for each mutual exclusion whether it affects this stream */
3658 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3659 if (*mes == stream->id) {
3660 /* if yes, check if we've already added streams that are mutually
3661 * exclusive with the stream we're about to add */
3662 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3663 for (j = 0; j < demux->num_streams; ++j) {
3664 /* if the broadcast flag is set, assume the hidden streams aren't
3665 * actually streamed and hide them (or playbin won't work right),
3666 * otherwise assume their data is available */
3667 if (demux->stream[j].id == *mes && demux->broadcast) {
3669 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3670 "mutually exclusive with already existing stream ID %d, "
3671 "hiding stream", stream->id, demux->stream[j].id);
3683 /* FIXME: we should do stream activation based on preroll data in
3684 * streaming mode too */
3685 if (demux->streaming && !is_hidden)
3686 gst_asf_demux_activate_stream (demux, stream);
3691 static GstFlowReturn
3692 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3695 GstFlowReturn ret = GST_FLOW_OK;
3697 guint64 obj_data_size;
3699 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3700 return ASF_FLOW_NEED_MORE_DATA;
3702 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3703 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3705 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3707 if (*p_size < obj_data_size)
3708 return ASF_FLOW_NEED_MORE_DATA;
3710 gst_asf_demux_push_obj (demux, obj.id);
3712 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3715 case ASF_OBJ_STREAM:
3716 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3720 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3722 case ASF_OBJ_HEADER:
3723 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3725 case ASF_OBJ_COMMENT:
3726 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3729 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3731 case ASF_OBJ_BITRATE_PROPS:
3733 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3736 case ASF_OBJ_EXT_CONTENT_DESC:
3738 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3741 case ASF_OBJ_METADATA_OBJECT:
3742 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3744 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3747 /* process these later, we might not have parsed the corresponding
3748 * stream object yet */
3749 GST_LOG ("%s: queued for later parsing", demux->objpath);
3750 buf = gst_buffer_new_and_alloc (obj_data_size);
3751 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
3752 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3756 case ASF_OBJ_LANGUAGE_LIST:
3757 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3759 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3760 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3763 case ASF_OBJ_SIMPLE_INDEX:
3764 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3766 case ASF_OBJ_CONTENT_ENCRYPTION:
3767 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3768 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3769 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
3770 goto error_encrypted;
3771 case ASF_OBJ_CONCEAL_NONE:
3773 case ASF_OBJ_UNDEFINED:
3774 case ASF_OBJ_CODEC_COMMENT:
3776 case ASF_OBJ_PADDING:
3777 case ASF_OBJ_BITRATE_MUTEX:
3778 case ASF_OBJ_COMPATIBILITY:
3779 case ASF_OBJ_INDEX_PLACEHOLDER:
3780 case ASF_OBJ_INDEX_PARAMETERS:
3781 case ASF_OBJ_STREAM_PRIORITIZATION:
3782 case ASF_OBJ_SCRIPT_COMMAND:
3784 /* Unknown/unhandled object, skip it and hope for the best */
3785 GST_INFO ("%s: skipping object", demux->objpath);
3790 /* this can't fail, we checked the number of bytes available before */
3791 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3793 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3795 gst_asf_demux_pop_obj (demux);
3802 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3803 return GST_FLOW_ERROR;
3808 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3809 GstBuffer ** p_buffer)
3811 GstBuffer *descrambled_buffer;
3812 GstBuffer *scrambled_buffer;
3813 GstBuffer *sub_buffer;
3820 /* descrambled_buffer is initialised in the first iteration */
3821 descrambled_buffer = NULL;
3822 scrambled_buffer = *p_buffer;
3824 if (gst_buffer_get_size (scrambled_buffer) <
3825 demux->ds_packet_size * demux->span)
3828 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
3829 offset += demux->ds_chunk_size) {
3830 off = offset / demux->ds_chunk_size;
3831 row = off / demux->span;
3832 col = off % demux->span;
3833 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3834 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3835 col, off, demux->ds_chunk_size);
3836 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
3837 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
3838 demux->span, demux->ds_packet_size);
3839 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
3840 gst_buffer_get_size (scrambled_buffer));
3842 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_NONE,
3843 idx * demux->ds_chunk_size, demux->ds_chunk_size);
3845 descrambled_buffer = sub_buffer;
3847 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
3851 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
3852 GST_BUFFER_TIMESTAMP (scrambled_buffer);
3853 GST_BUFFER_DURATION (descrambled_buffer) =
3854 GST_BUFFER_DURATION (scrambled_buffer);
3855 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
3856 GST_BUFFER_OFFSET_END (descrambled_buffer) =
3857 GST_BUFFER_OFFSET_END (scrambled_buffer);
3859 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3861 gst_buffer_unref (scrambled_buffer);
3862 *p_buffer = descrambled_buffer;
3866 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3868 GstASFDemux *demux = GST_ASF_DEMUX (element);
3871 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3873 for (i = 0; i < demux->num_streams; ++i) {
3874 gst_event_ref (event);
3875 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
3876 GST_OBJECT_CAST (element), event)) {
3877 gst_event_unref (event);
3882 gst_event_unref (event);
3886 /* takes ownership of the passed event */
3888 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3890 gboolean ret = TRUE;
3893 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3894 GST_EVENT_TYPE_NAME (event));
3896 for (i = 0; i < demux->num_streams; ++i) {
3897 gst_event_ref (event);
3898 ret &= gst_pad_push_event (demux->stream[i].pad, event);
3900 gst_event_unref (event);
3905 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
3909 gboolean res = FALSE;
3911 demux = GST_ASF_DEMUX (parent);
3913 GST_DEBUG ("handling %s query",
3914 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3916 switch (GST_QUERY_TYPE (query)) {
3917 case GST_QUERY_DURATION:
3921 gst_query_parse_duration (query, &format, NULL);
3923 if (format != GST_FORMAT_TIME) {
3924 GST_LOG ("only support duration queries in TIME format");
3928 GST_OBJECT_LOCK (demux);
3930 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3931 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3932 GST_TIME_ARGS (demux->segment.duration));
3934 gst_query_set_duration (query, GST_FORMAT_TIME,
3935 demux->segment.duration);
3939 GST_LOG ("duration not known yet");
3942 GST_OBJECT_UNLOCK (demux);
3946 case GST_QUERY_POSITION:{
3949 gst_query_parse_position (query, &format, NULL);
3951 if (format != GST_FORMAT_TIME) {
3952 GST_LOG ("only support position queries in TIME format");
3956 GST_OBJECT_LOCK (demux);
3958 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
3959 GST_LOG ("returning position: %" GST_TIME_FORMAT,
3960 GST_TIME_ARGS (demux->segment.position));
3962 gst_query_set_position (query, GST_FORMAT_TIME,
3963 demux->segment.position);
3967 GST_LOG ("position not known yet");
3970 GST_OBJECT_UNLOCK (demux);
3974 case GST_QUERY_SEEKING:{
3977 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3978 if (format == GST_FORMAT_TIME) {
3981 GST_OBJECT_LOCK (demux);
3982 duration = demux->segment.duration;
3983 GST_OBJECT_UNLOCK (demux);
3985 if (!demux->streaming || !demux->seekable) {
3986 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3993 /* try downstream first in TIME */
3994 res = gst_pad_query_default (pad, parent, query);
3996 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3997 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3998 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3999 /* if no luck, maybe in BYTES */
4000 if (!seekable || fmt != GST_FORMAT_TIME) {
4003 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4004 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4005 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4006 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4007 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4008 if (fmt != GST_FORMAT_BYTES)
4011 gst_query_unref (q);
4012 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4018 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4022 case GST_QUERY_LATENCY:
4025 GstClockTime min, max;
4027 /* preroll delay does not matter in non-live pipeline,
4028 * but we might end up in a live (rtsp) one ... */
4031 res = gst_pad_query_default (pad, parent, query);
4035 gst_query_parse_latency (query, &live, &min, &max);
4037 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4038 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4039 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4041 GST_OBJECT_LOCK (demux);
4043 min += demux->latency;
4045 max += demux->latency;
4046 GST_OBJECT_UNLOCK (demux);
4048 gst_query_set_latency (query, live, min, max);
4052 res = gst_pad_query_default (pad, parent, query);
4059 static GstStateChangeReturn
4060 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4062 GstASFDemux *demux = GST_ASF_DEMUX (element);
4063 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4065 switch (transition) {
4066 case GST_STATE_CHANGE_NULL_TO_READY:{
4067 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4068 demux->need_newsegment = TRUE;
4069 demux->segment_running = FALSE;
4070 demux->accurate = FALSE;
4071 demux->adapter = gst_adapter_new ();
4072 demux->metadata = gst_caps_new_empty ();
4073 demux->global_metadata = gst_structure_new_empty ("metadata");
4074 demux->data_size = 0;
4075 demux->data_offset = 0;
4076 demux->index_offset = 0;
4077 demux->base_offset = 0;
4084 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4085 if (ret == GST_STATE_CHANGE_FAILURE)
4088 switch (transition) {
4089 case GST_STATE_CHANGE_PAUSED_TO_READY:
4090 case GST_STATE_CHANGE_READY_TO_NULL:
4091 gst_asf_demux_reset (demux, FALSE);