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 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
649 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
652 gst_event_ref (event);
653 /* upstream might handle TIME seek, e.g. mms or rtsp,
654 * or not, e.g. http, then we give it a hand */
655 if (!gst_pad_push_event (demux->sinkpad, event))
656 return gst_asf_demux_handle_seek_push (demux, event);
661 /* unlock the streaming thread */
662 if (G_LIKELY (flush)) {
663 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
664 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
666 gst_pad_pause_task (demux->sinkpad);
669 /* grab the stream lock so that streaming cannot continue, for
670 * non flushing seeks when the element is in PAUSED this could block
672 GST_PAD_STREAM_LOCK (demux->sinkpad);
674 /* we now can stop flushing, since we have the stream lock now */
675 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
677 if (G_LIKELY (flush))
678 gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop (TRUE));
680 /* operating on copy of segment until we know the seek worked */
681 segment = demux->segment;
683 if (G_UNLIKELY (demux->segment_running && !flush)) {
684 GstSegment newsegment;
687 /* create the segment event to close the current segment */
688 gst_segment_copy_into (&segment, &newsegment);
689 newseg = gst_event_new_segment (&newsegment);
691 gst_asf_demux_send_event_unlocked (demux, newseg);
694 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
695 cur, stop_type, stop, &only_need_update);
697 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
698 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
700 seek_time = segment.start;
702 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
703 * real start of data and segment_start to indexed time for key unit seek*/
704 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
705 &idx_time, &speed_count, next, &eos))) {
709 demux->packet = demux->num_packets;
713 /* First try to query our source to see if it can convert for us. This is
714 the case when our source is an mms stream, notice that in this case
715 gstmms will do a time based seek to get the byte offset, this is not a
716 problem as the seek to this offset needs to happen anway. */
717 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
718 GST_FORMAT_BYTES, &offset)) {
719 packet = (offset - demux->data_offset) / demux->packet_size;
720 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
721 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
722 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
723 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
724 demux->packet_size, packet);
726 /* FIXME: For streams containing video, seek to an earlier position in
727 * the hope of hitting a keyframe and let the sinks throw away the stuff
728 * before the segment start. For audio-only this is unnecessary as every
730 if (flush && (demux->accurate || (keyunit_sync && !next))
731 && demux->num_video_streams > 0) {
732 seek_time -= 5 * GST_SECOND;
737 packet = (guint) gst_util_uint64_scale (demux->num_packets,
738 seek_time, demux->play_time);
740 if (packet > demux->num_packets)
741 packet = demux->num_packets;
744 if (G_LIKELY (keyunit_sync)) {
745 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
746 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
747 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
748 segment.start = idx_time;
749 segment.position = idx_time;
750 segment.time = idx_time;
754 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
756 GST_OBJECT_LOCK (demux);
757 demux->segment = segment;
758 demux->packet = packet;
759 demux->need_newsegment = TRUE;
760 demux->speed_packets = speed_count;
761 gst_asf_demux_reset_stream_state_after_discont (demux);
762 GST_OBJECT_UNLOCK (demux);
765 /* restart our task since it might have been stopped when we did the flush */
766 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
769 /* streaming can continue now */
770 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
776 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
782 demux = GST_ASF_DEMUX (parent);
784 switch (GST_EVENT_TYPE (event)) {
786 GST_LOG_OBJECT (pad, "seek event");
787 ret = gst_asf_demux_handle_seek_event (demux, event);
788 gst_event_unref (event);
791 case GST_EVENT_NAVIGATION:
792 /* just drop these two silently */
793 gst_event_unref (event);
797 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
798 ret = gst_pad_event_default (pad, parent, event);
805 static inline guint32
806 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
810 ret = gst_asf_identify_guid (guids, guid);
812 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
813 gst_asf_get_guid_nick (guids, ret),
814 guid->v1, guid->v2, guid->v3, guid->v4);
826 /* expect is true when the user is expeting an object,
827 * when false, it will give no warnings if the object
831 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
832 guint data_len, AsfObject * object, gboolean expect)
836 if (data_len < ASF_OBJECT_HEADER_SIZE)
839 guid.v1 = GST_READ_UINT32_LE (data + 0);
840 guid.v2 = GST_READ_UINT32_LE (data + 4);
841 guid.v3 = GST_READ_UINT32_LE (data + 8);
842 guid.v4 = GST_READ_UINT32_LE (data + 12);
844 object->size = GST_READ_UINT64_LE (data + 16);
846 /* FIXME: make asf_demux_identify_object_guid() */
847 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
848 if (object->id == ASF_OBJ_UNDEFINED && expect) {
849 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
850 guid.v1, guid.v2, guid.v3, guid.v4);
857 gst_asf_demux_release_old_pads (GstASFDemux * demux)
859 GST_DEBUG_OBJECT (demux, "Releasing old pads");
861 while (demux->old_num_streams > 0) {
862 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
863 gst_event_new_eos ());
864 gst_asf_demux_free_stream (demux,
865 &demux->old_stream[demux->old_num_streams - 1]);
866 --demux->old_num_streams;
868 memset (demux->old_stream, 0, sizeof (demux->old_stream));
869 demux->old_num_streams = 0;
873 gst_asf_demux_chain_headers (GstASFDemux * demux)
877 guint8 *header_data, *data = NULL;
878 const guint8 *cdata = NULL;
881 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
885 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
886 if (obj.id != ASF_OBJ_HEADER)
889 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
891 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
892 if (gst_adapter_available (demux->adapter) < obj.size + 50)
895 data = gst_adapter_take (demux->adapter, obj.size + 50);
898 header_size = obj.size;
899 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
900 if (flow != GST_FLOW_OK)
903 /* calculate where the packet data starts */
904 demux->data_offset = obj.size + 50;
906 /* now parse the beginning of the ASF_OBJ_DATA object */
907 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
910 if (demux->num_streams == 0)
919 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
926 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
927 ("This doesn't seem to be an ASF file"));
929 return GST_FLOW_ERROR;
934 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
935 ("header parsing failed, or no streams found, flow = %s",
936 gst_flow_get_name (flow)));
938 return GST_FLOW_ERROR;
943 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
948 GST_DEBUG_OBJECT (demux, "Aggregating");
950 /* Store the value */
951 stream->last_flow = flow;
953 /* any other error that is not not-linked can be returned right away */
954 if (flow != GST_FLOW_NOT_LINKED)
957 for (i = 0; i < demux->num_streams; i++) {
958 if (demux->stream[i].active) {
959 flow = demux->stream[i].last_flow;
960 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
961 gst_flow_get_name (flow));
962 if (flow != GST_FLOW_NOT_LINKED)
967 /* If we got here, then all our active streams are not linked */
973 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
974 GstBuffer ** p_buf, GstFlowReturn * p_flow)
979 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
982 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
984 if (G_LIKELY (p_flow))
987 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
988 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
989 "+%u", gst_flow_get_name (flow), offset, size);
994 g_assert (*p_buf != NULL);
996 buffer_size = gst_buffer_get_size (*p_buf);
997 if (G_UNLIKELY (buffer_size < size)) {
998 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
999 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1000 gst_buffer_unref (*p_buf);
1001 if (G_LIKELY (p_flow))
1002 *p_flow = GST_FLOW_EOS;
1011 gst_asf_demux_pull_indices (GstASFDemux * demux)
1013 GstBuffer *buf = NULL;
1017 offset = demux->index_offset;
1019 if (G_UNLIKELY (offset == 0)) {
1020 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1024 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1030 gst_buffer_map (buf, &map, GST_MAP_READ);
1031 g_assert (map.size >= 16 + 8);
1032 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1033 gst_buffer_unmap (buf, &map);
1034 gst_buffer_replace (&buf, NULL);
1036 /* check for sanity */
1037 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1038 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1042 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1046 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1047 ", size %u", offset, (guint) obj.size);
1049 offset += obj.size; /* increase before _process_object changes it */
1051 gst_buffer_map (buf, &map, GST_MAP_READ);
1052 g_assert (map.size >= obj.size);
1053 bufdata = (guint8 *) map.data;
1054 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1055 gst_buffer_unmap (buf, &map);
1056 gst_buffer_replace (&buf, NULL);
1058 if (G_UNLIKELY (flow != GST_FLOW_OK))
1063 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1067 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1071 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1072 if (obj.id != ASF_OBJ_DATA) {
1073 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1077 demux->state = GST_ASF_DEMUX_STATE_DATA;
1079 if (!demux->broadcast && obj.size > 50) {
1080 demux->data_size = obj.size - 50;
1081 /* CHECKME: for at least one file this is off by +158 bytes?! */
1082 demux->index_offset = demux->data_offset + demux->data_size;
1084 demux->data_size = 0;
1085 demux->index_offset = 0;
1090 if (!demux->broadcast) {
1091 /* skip object header (24 bytes) and file GUID (16 bytes) */
1092 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1094 demux->num_packets = 0;
1097 if (demux->num_packets == 0)
1098 demux->seekable = FALSE;
1100 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1101 if (demux->data_size == 0 && demux->num_packets > 0) {
1102 demux->data_size = demux->num_packets * demux->packet_size;
1103 demux->index_offset = demux->data_offset + demux->data_size;
1106 /* process pending stream objects and create pads for those */
1107 gst_asf_demux_process_queued_extended_stream_objects (demux);
1109 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1110 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1111 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1112 demux->data_offset, demux->data_size, demux->index_offset);
1118 gst_asf_demux_pull_headers (GstASFDemux * demux)
1122 GstBuffer *buf = NULL;
1127 GST_LOG_OBJECT (demux, "reading headers");
1129 /* pull HEADER object header, so we know its size */
1130 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1133 gst_buffer_map (buf, &map, GST_MAP_READ);
1134 g_assert (map.size >= 16 + 8);
1135 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1136 gst_buffer_unmap (buf, &map);
1137 gst_buffer_replace (&buf, NULL);
1139 if (obj.id != ASF_OBJ_HEADER)
1142 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1144 /* pull HEADER object */
1145 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1149 size = obj.size; /* don't want obj.size changed */
1150 gst_buffer_map (buf, &map, GST_MAP_READ);
1151 g_assert (map.size >= size);
1152 bufdata = (guint8 *) map.data;
1153 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1154 gst_buffer_unmap (buf, &map);
1155 gst_buffer_replace (&buf, NULL);
1157 if (flow != GST_FLOW_OK) {
1158 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1162 /* calculate where the packet data starts */
1163 demux->data_offset = demux->base_offset + obj.size + 50;
1165 /* now pull beginning of DATA object before packet data */
1166 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1170 gst_buffer_map (buf, &map, GST_MAP_READ);
1171 g_assert (map.size >= size);
1172 bufdata = (guint8 *) map.data;
1173 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1176 if (demux->num_streams == 0)
1179 gst_buffer_unmap (buf, &map);
1180 gst_buffer_replace (&buf, NULL);
1188 gst_buffer_unmap (buf, &map);
1189 gst_buffer_replace (&buf, NULL);
1191 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1192 ("This doesn't seem to be an ASF file"));
1201 gst_buffer_unmap (buf, &map);
1202 gst_buffer_replace (&buf, NULL);
1203 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1209 all_streams_prerolled (GstASFDemux * demux)
1211 GstClockTime preroll_time;
1212 guint i, num_no_data = 0;
1214 /* Allow at least 500ms of preroll_time */
1215 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1217 /* returns TRUE as long as there isn't a stream which (a) has data queued
1218 * and (b) the timestamp of last piece of data queued is < demux->preroll
1219 * AND there is at least one other stream with data queued */
1220 for (i = 0; i < demux->num_streams; ++i) {
1221 AsfPayload *last_payload;
1225 stream = &demux->stream[i];
1226 if (G_UNLIKELY (stream->payloads->len == 0)) {
1228 GST_LOG_OBJECT (stream->pad, "no data queued");
1232 last_idx = stream->payloads->len - 1;
1233 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1235 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1236 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1237 GST_TIME_ARGS (preroll_time));
1238 if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1239 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1244 if (G_UNLIKELY (num_no_data == demux->num_streams))
1252 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1257 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1260 /* check for each mutual exclusion group whether it affects this stream */
1261 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1262 if (*mes == stream->id) {
1263 /* we are in this group; let's check if we've already activated streams
1264 * that are in the same group (and hence mutually exclusive to this
1266 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1269 for (i = 0; i < demux->num_streams; ++i) {
1270 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1271 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1272 "to already active stream with ID %d", stream->id,
1273 demux->stream[i].id);
1278 /* we can only be in this group once, let's break out and move on to
1279 * the next mutual exclusion group */
1290 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1294 if (demux->activated_streams)
1297 if (!all_streams_prerolled (demux) && !force) {
1298 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1302 for (i = 0; i < demux->num_streams; ++i) {
1303 AsfStream *stream = &demux->stream[i];
1305 if (stream->payloads->len > 0) {
1306 /* we don't check mutual exclusion stuff here; either we have data for
1307 * a stream, then we active it, or we don't, then we'll ignore it */
1308 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1309 gst_asf_demux_activate_stream (demux, stream);
1311 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1315 gst_asf_demux_release_old_pads (demux);
1317 demux->activated_streams = TRUE;
1318 GST_LOG_OBJECT (demux, "signalling no more pads");
1319 gst_element_no_more_pads (GST_ELEMENT (demux));
1323 /* returns the stream that has a complete payload with the lowest timestamp
1324 * queued, or NULL (we push things by timestamp because during the internal
1325 * prerolling we might accumulate more data then the external queues can take,
1326 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1328 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1330 AsfPayload *best_payload = NULL;
1331 AsfStream *best_stream = NULL;
1334 for (i = 0; i < demux->num_streams; ++i) {
1337 stream = &demux->stream[i];
1339 /* Don't push any data until we have at least one payload that falls within
1340 * the current segment. This way we can remove out-of-segment payloads that
1341 * don't need to be decoded after a seek, sending only data from the
1342 * keyframe directly before our segment start */
1343 if (stream->payloads->len > 0) {
1344 AsfPayload *payload;
1347 last_idx = stream->payloads->len - 1;
1348 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1349 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1350 (payload->ts < demux->segment.start))) {
1351 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1352 GST_DEBUG_OBJECT (stream->pad,
1353 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1354 GST_TIME_ARGS (payload->ts));
1355 demux->segment.start = payload->ts;
1356 demux->segment.time = payload->ts;
1358 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1359 GST_TIME_FORMAT " which is before our segment start %"
1360 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1361 GST_TIME_ARGS (demux->segment.start));
1366 /* Now see if there's a complete payload queued for this stream */
1368 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1369 if (!gst_asf_payload_is_complete (payload))
1372 /* ... and whether its timestamp is lower than the current best */
1373 if (best_stream == NULL || best_payload->ts > payload->ts) {
1374 best_stream = stream;
1375 best_payload = payload;
1383 static GstFlowReturn
1384 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1387 GstFlowReturn ret = GST_FLOW_OK;
1389 if (G_UNLIKELY (!demux->activated_streams)) {
1390 if (!gst_asf_demux_check_activate_streams (demux, force))
1392 /* streams are now activated */
1395 /* wait until we had a chance to "lock on" some payload's timestamp */
1396 if (G_UNLIKELY (demux->need_newsegment
1397 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1400 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1401 AsfPayload *payload;
1403 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1405 /* do we need to send a newsegment event */
1406 if ((G_UNLIKELY (demux->need_newsegment))) {
1408 /* safe default if insufficient upstream info */
1409 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1412 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1413 demux->segment.duration > 0) {
1414 /* slight HACK; prevent clipping of last bit */
1415 demux->segment.stop = demux->segment.duration + demux->in_gap;
1418 /* FIXME : only if ACCURATE ! */
1419 if (G_LIKELY (!demux->accurate
1420 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1421 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1422 GST_TIME_ARGS (payload->ts));
1423 demux->segment.start = payload->ts;
1424 demux->segment.time = payload->ts;
1427 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1430 /* note: we fix up all timestamps to start from 0, so this should be ok */
1431 gst_asf_demux_send_event_unlocked (demux,
1432 gst_event_new_segment (&demux->segment));
1434 /* now post any global tags we may have found */
1435 if (demux->taglist == NULL) {
1436 demux->taglist = gst_tag_list_new_empty ();
1437 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1440 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1441 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1443 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1444 gst_asf_demux_send_event_unlocked (demux,
1445 gst_event_new_tag (demux->taglist));
1446 demux->taglist = NULL;
1448 demux->need_newsegment = FALSE;
1449 demux->segment_running = TRUE;
1452 /* Do we have tags pending for this stream? */
1453 if (G_UNLIKELY (stream->pending_tags)) {
1454 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1455 gst_pad_push_event (stream->pad,
1456 gst_event_new_tag (stream->pending_tags));
1457 stream->pending_tags = NULL;
1460 /* We have the whole packet now so we should push the packet to
1461 * the src pad now. First though we should check if we need to do
1463 if (G_UNLIKELY (demux->span > 1)) {
1464 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1467 payload->buf = gst_buffer_make_writable (payload->buf);
1469 if (G_LIKELY (!payload->keyframe)) {
1470 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1473 if (G_UNLIKELY (stream->discont)) {
1474 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1475 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1476 stream->discont = FALSE;
1479 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1480 (payload->par_x != stream->par_x) &&
1481 (payload->par_y != stream->par_y))) {
1482 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1483 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1484 stream->par_x = payload->par_x;
1485 stream->par_y = payload->par_y;
1486 stream->caps = gst_caps_make_writable (stream->caps);
1487 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1488 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1489 gst_pad_set_caps (stream->pad, stream->caps);
1492 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1493 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1494 payload->interlaced);
1495 stream->interlaced = payload->interlaced;
1496 stream->caps = gst_caps_make_writable (stream->caps);
1497 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1498 (stream->interlaced ? "mixed" : "progressive"), NULL);
1499 gst_pad_set_caps (stream->pad, stream->caps);
1502 /* (sort of) interpolate timestamps using upstream "frame of reference",
1503 * typically useful for live src, but might (unavoidably) mess with
1504 * position reporting if a live src is playing not so live content
1505 * (e.g. rtspsrc taking some time to fall back to tcp) */
1506 GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1507 if (payload->duration == GST_CLOCK_TIME_NONE
1508 && stream->ext_props.avg_time_per_frame != 0)
1509 GST_BUFFER_DURATION (payload->buf) =
1510 stream->ext_props.avg_time_per_frame * 100;
1512 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1514 /* FIXME: we should really set durations on buffers if we can */
1516 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1517 ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
1518 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1519 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1520 gst_buffer_get_size (payload->buf));
1522 if (stream->active) {
1523 ret = gst_pad_push (stream->pad, payload->buf);
1524 ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1526 gst_buffer_unref (payload->buf);
1529 payload->buf = NULL;
1530 g_array_remove_index (stream->payloads, 0);
1532 /* Break out as soon as we have an issue */
1533 if (G_UNLIKELY (ret != GST_FLOW_OK))
1541 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1545 g_assert (buf != NULL);
1547 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1549 gst_buffer_map (buf, &map, GST_MAP_READ);
1551 /* we return false on buffer too small */
1552 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1553 gst_buffer_unmap (buf, &map);
1557 /* check if it is a header */
1558 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1559 gst_buffer_unmap (buf, &map);
1560 if (obj.id == ASF_OBJ_HEADER) {
1567 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1569 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1570 GstFlowReturn ret = GST_FLOW_OK;
1571 GstBuffer *buf = NULL;
1572 gboolean header = FALSE;
1574 /* TODO maybe we should skip index objects after the data and look
1575 * further for a new header */
1576 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1577 g_assert (buf != NULL);
1578 /* check if it is a header */
1579 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1580 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1581 demux->base_offset = off;
1585 gst_buffer_unref (buf);
1592 gst_asf_demux_loop (GstASFDemux * demux)
1594 GstFlowReturn flow = GST_FLOW_OK;
1595 GstBuffer *buf = NULL;
1597 gboolean sent_eos = FALSE;
1599 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1600 if (!gst_asf_demux_pull_headers (demux)) {
1601 flow = GST_FLOW_ERROR;
1605 gst_asf_demux_pull_indices (demux);
1608 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1610 if (G_UNLIKELY (demux->num_packets != 0
1611 && demux->packet >= demux->num_packets))
1614 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1615 (guint) demux->num_packets);
1617 off = demux->data_offset + (demux->packet * demux->packet_size);
1619 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1620 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1621 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1622 if (flow == GST_FLOW_EOS)
1624 else if (flow == GST_FLOW_FLUSHING) {
1625 GST_DEBUG_OBJECT (demux, "Not fatal");
1631 if (G_LIKELY (demux->speed_packets == 1)) {
1632 GstAsfDemuxParsePacketError err;
1633 err = gst_asf_demux_parse_packet (demux, buf);
1634 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1635 /* when we don't know when the data object ends, we should check
1636 * for a chained asf */
1637 if (demux->num_packets == 0) {
1638 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1639 GST_INFO_OBJECT (demux, "Chained asf found");
1640 demux->base_offset = off;
1641 gst_asf_demux_reset (demux, TRUE);
1642 gst_buffer_unref (buf);
1646 /* FIXME: We should tally up fatal errors and error out only
1647 * after a few broken packets in a row? */
1649 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1650 gst_buffer_unref (buf);
1655 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1661 for (n = 0; n < demux->speed_packets; n++) {
1663 GstAsfDemuxParsePacketError err;
1666 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1667 n * demux->packet_size, demux->packet_size);
1668 err = gst_asf_demux_parse_packet (demux, sub);
1669 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1670 /* when we don't know when the data object ends, we should check
1671 * for a chained asf */
1672 if (demux->num_packets == 0) {
1673 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1674 GST_INFO_OBJECT (demux, "Chained asf found");
1675 demux->base_offset = off + n * demux->packet_size;
1676 gst_asf_demux_reset (demux, TRUE);
1677 gst_buffer_unref (sub);
1678 gst_buffer_unref (buf);
1682 /* FIXME: We should tally up fatal errors and error out only
1683 * after a few broken packets in a row? */
1685 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1689 gst_buffer_unref (sub);
1691 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1692 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1698 /* reset speed pull */
1699 demux->speed_packets = 1;
1702 gst_buffer_unref (buf);
1704 if (G_UNLIKELY (demux->num_packets > 0
1705 && demux->packet >= demux->num_packets)) {
1706 GST_LOG_OBJECT (demux, "reached EOS");
1710 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1711 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1715 /* check if we're at the end of the configured segment */
1716 /* FIXME: check if segment end reached etc. */
1722 /* if we haven't activated our streams yet, this might be because we have
1723 * less data queued than required for preroll; force stream activation and
1724 * send any pending payloads before sending EOS */
1725 if (!demux->activated_streams)
1726 gst_asf_demux_push_complete_payloads (demux, TRUE);
1728 /* we want to push an eos or post a segment-done in any case */
1729 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1732 /* for segment playback we need to post when (in stream time)
1733 * we stopped, this is either stop (when set) or the duration. */
1734 if ((stop = demux->segment.stop) == -1)
1735 stop = demux->segment.duration;
1737 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1738 gst_element_post_message (GST_ELEMENT_CAST (demux),
1739 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1741 gst_asf_demux_send_event_unlocked (demux,
1742 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1743 } else if (flow != GST_FLOW_EOS) {
1744 /* check if we have a chained asf, in case, we don't eos yet */
1745 if (gst_asf_demux_check_chained_asf (demux)) {
1746 GST_INFO_OBJECT (demux, "Chained ASF starting");
1747 gst_asf_demux_reset (demux, TRUE);
1751 /* normal playback, send EOS to all linked pads */
1752 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1753 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1755 /* ... and fall through to pause */
1759 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1760 gst_flow_get_name (flow));
1761 demux->segment_running = FALSE;
1762 gst_pad_pause_task (demux->sinkpad);
1764 /* For the error cases (not EOS) */
1766 if (flow == GST_FLOW_EOS)
1767 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1768 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1769 /* Post an error. Hopefully something else already has, but if not... */
1770 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1771 (_("Internal data stream error.")),
1772 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1781 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1782 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1783 flow = GST_FLOW_EOS;
1787 /* See FIXMEs above */
1790 gst_buffer_unref (buf);
1791 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1792 ("Error parsing ASF packet %u", (guint) demux->packet));
1793 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1794 flow = GST_FLOW_ERROR;
1800 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1801 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1802 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1805 gst_asf_demux_check_header (GstASFDemux * demux)
1808 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
1809 ASF_OBJECT_HEADER_SIZE);
1810 if (cdata == NULL) /* need more data */
1811 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1813 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1814 if (obj.id != ASF_OBJ_HEADER) {
1815 return GST_ASF_DEMUX_CHECK_HEADER_NO;
1817 return GST_ASF_DEMUX_CHECK_HEADER_YES;
1821 static GstFlowReturn
1822 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1824 GstFlowReturn ret = GST_FLOW_OK;
1827 demux = GST_ASF_DEMUX (parent);
1829 GST_LOG_OBJECT (demux,
1830 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
1831 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
1832 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1834 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1835 GST_DEBUG_OBJECT (demux, "received DISCONT");
1836 gst_asf_demux_mark_discont (demux);
1839 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1840 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1841 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1842 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1843 ", interpolation gap: %" GST_TIME_FORMAT,
1844 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1847 gst_adapter_push (demux->adapter, buf);
1849 switch (demux->state) {
1850 case GST_ASF_DEMUX_STATE_INDEX:{
1851 gint result = gst_asf_demux_check_header (demux);
1852 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
1855 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1856 /* we don't care about this, probably an index */
1857 /* TODO maybe would be smarter to skip all the indices
1858 * until we got a new header or EOS to decide */
1859 GST_LOG_OBJECT (demux, "Received index object, its EOS");
1862 GST_INFO_OBJECT (demux, "Chained asf starting");
1863 /* cleanup and get ready for a chained asf */
1864 gst_asf_demux_reset (demux, TRUE);
1868 case GST_ASF_DEMUX_STATE_HEADER:{
1869 ret = gst_asf_demux_chain_headers (demux);
1870 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1872 /* otherwise fall through */
1874 case GST_ASF_DEMUX_STATE_DATA:
1878 data_size = demux->packet_size;
1880 while (gst_adapter_available (demux->adapter) >= data_size) {
1882 GstAsfDemuxParsePacketError err;
1884 /* we don't know the length of the stream
1885 * check for a chained asf everytime */
1886 if (demux->num_packets == 0) {
1887 gint result = gst_asf_demux_check_header (demux);
1889 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1890 GST_INFO_OBJECT (demux, "Chained asf starting");
1891 /* cleanup and get ready for a chained asf */
1892 gst_asf_demux_reset (demux, TRUE);
1895 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1896 && demux->packet >= demux->num_packets)) {
1897 /* do not overshoot data section when streaming */
1901 buf = gst_adapter_take_buffer (demux->adapter, data_size);
1903 /* FIXME: We should tally up fatal errors and error out only
1904 * after a few broken packets in a row? */
1905 err = gst_asf_demux_parse_packet (demux, buf);
1907 gst_buffer_unref (buf);
1909 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
1910 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1912 GST_WARNING_OBJECT (demux, "Parse error");
1914 if (demux->packet >= 0)
1917 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1918 && demux->packet >= demux->num_packets)) {
1919 demux->state = GST_ASF_DEMUX_STATE_INDEX;
1924 g_assert_not_reached ();
1928 if (ret != GST_FLOW_OK)
1929 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1935 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1941 static inline gboolean
1942 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1944 if (*p_size < num_bytes)
1947 *p_data += num_bytes;
1948 *p_size -= num_bytes;
1952 static inline guint8
1953 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1957 g_assert (*p_size >= 1);
1958 ret = GST_READ_UINT8 (*p_data);
1959 *p_data += sizeof (guint8);
1960 *p_size -= sizeof (guint8);
1964 static inline guint16
1965 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1969 g_assert (*p_size >= 2);
1970 ret = GST_READ_UINT16_LE (*p_data);
1971 *p_data += sizeof (guint16);
1972 *p_size -= sizeof (guint16);
1976 static inline guint32
1977 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1981 g_assert (*p_size >= 4);
1982 ret = GST_READ_UINT32_LE (*p_data);
1983 *p_data += sizeof (guint32);
1984 *p_size -= sizeof (guint32);
1988 static inline guint64
1989 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1993 g_assert (*p_size >= 8);
1994 ret = GST_READ_UINT64_LE (*p_data);
1995 *p_data += sizeof (guint64);
1996 *p_size -= sizeof (guint64);
2000 static inline guint32
2001 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
2008 g_assert (*p_size >= 1);
2009 return gst_asf_demux_get_uint8 (p_data, p_size);
2012 g_assert (*p_size >= 2);
2013 return gst_asf_demux_get_uint16 (p_data, p_size);
2016 g_assert (*p_size >= 4);
2017 return gst_asf_demux_get_uint32 (p_data, p_size);
2020 g_assert_not_reached ();
2027 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2028 guint8 ** p_data, guint64 * p_size)
2032 if (*p_size < num_bytes_to_read)
2035 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2036 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2038 *p_data += num_bytes_to_read;
2039 *p_size -= num_bytes_to_read;
2045 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2046 guint8 ** p_data, guint64 * p_size)
2050 if (*p_size < num_bytes_to_read)
2053 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2054 *p_data += num_bytes_to_read;
2055 *p_size -= num_bytes_to_read;
2060 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2061 guint8 ** p_data, guint64 * p_size)
2071 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2074 *p_strlen = s_length;
2076 if (s_length == 0) {
2077 GST_WARNING ("zero-length string");
2078 *p_str = g_strdup ("");
2082 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2085 g_assert (s != NULL);
2087 /* just because They don't exist doesn't
2088 * mean They are not out to get you ... */
2089 if (s[s_length - 1] != '\0') {
2090 s = g_realloc (s, s_length + 1);
2094 *p_str = (gchar *) s;
2100 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2102 g_assert (*p_size >= 4 * sizeof (guint32));
2104 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2105 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2106 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2107 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2111 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2114 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2117 /* WAVEFORMATEX Structure */
2118 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2119 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2120 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2121 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2122 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2123 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2124 /* Codec specific data size */
2125 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2130 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2133 if (*p_size < (4 + 4 + 1 + 2))
2136 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2137 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2138 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2139 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2144 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2145 guint8 ** p_data, guint64 * p_size)
2147 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2150 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2151 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2152 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2153 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2154 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2155 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2156 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2157 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2158 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2159 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2160 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2165 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2169 for (i = 0; i < demux->num_streams; i++) {
2170 if (demux->stream[i].id == id)
2171 return &demux->stream[i];
2174 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2179 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2180 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2184 gst_pad_use_fixed_caps (src_pad);
2185 gst_pad_set_caps (src_pad, caps);
2187 gst_pad_set_event_function (src_pad,
2188 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2189 gst_pad_set_query_function (src_pad,
2190 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2192 stream = &demux->stream[demux->num_streams];
2193 stream->caps = caps;
2194 stream->pad = src_pad;
2196 stream->fps_known = !is_video; /* bit hacky for audio */
2197 stream->is_video = is_video;
2198 stream->pending_tags = tags;
2199 stream->discont = TRUE;
2203 st = gst_caps_get_structure (caps, 0);
2204 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2205 par_x > 0 && par_y > 0) {
2206 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2207 stream->par_x = par_x;
2208 stream->par_y = par_y;
2212 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2214 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2215 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2217 ++demux->num_streams;
2219 stream->active = FALSE;
2223 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2224 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2226 GstTagList *tags = NULL;
2227 GstBuffer *extradata = NULL;
2230 guint16 size_left = 0;
2231 gchar *codec_name = NULL;
2234 size_left = audio->size;
2236 /* Create the audio pad */
2237 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2239 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2242 /* Swallow up any left over data and set up the
2243 * standard properties from the header info */
2245 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2246 "codec specific data", size_left);
2248 g_assert (size_left <= *p_size);
2249 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2252 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2253 * additional two bytes indicating extradata. */
2254 /* FIXME: Handle the channel reorder map here */
2255 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2256 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2259 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2260 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2263 /* Informing about that audio format we just added */
2265 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2266 g_free (codec_name);
2270 gst_buffer_unref (extradata);
2272 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2273 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2274 audio->codec_tag, tags);
2276 ++demux->num_audio_streams;
2278 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2282 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2283 asf_stream_video_format * video, guint16 id,
2284 guint8 ** p_data, guint64 * p_size)
2286 GstTagList *tags = NULL;
2287 GstBuffer *extradata = NULL;
2292 gchar *codec_name = NULL;
2293 gint size_left = video->size - 40;
2295 /* Create the video pad */
2296 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2297 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2300 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2302 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2303 g_assert (size_left <= *p_size);
2304 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2307 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2309 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2310 caps = gst_riff_create_video_caps (video->tag, NULL,
2311 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2314 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2315 G_TYPE_UINT, video->tag, NULL);
2320 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2321 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2322 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2323 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2328 /* retry with the global metadata */
2329 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2330 demux->global_metadata);
2331 s = demux->global_metadata;
2332 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2333 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2334 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2335 if (ax > 0 && ay > 0)
2336 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2340 s = gst_caps_get_structure (caps, 0);
2341 gst_structure_remove_field (s, "framerate");
2344 /* add fourcc format to caps, some proprietary decoders seem to need it */
2345 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2346 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2350 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2351 g_free (codec_name);
2355 gst_buffer_unref (extradata);
2357 GST_INFO ("Adding video stream #%u, id %u, codec %"
2358 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2359 GST_FOURCC_ARGS (video->tag), video->tag);
2361 ++demux->num_video_streams;
2363 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2367 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2369 if (!stream->active) {
2370 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2371 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2372 gst_pad_set_active (stream->pad, TRUE);
2373 gst_pad_set_caps (stream->pad, stream->caps);
2374 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2375 gst_pad_push_event (stream->pad, gst_event_new_stream_start ());
2376 stream->active = TRUE;
2381 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2384 AsfCorrectionType correction_type;
2385 AsfStreamType stream_type;
2386 GstClockTime time_offset;
2387 gboolean is_encrypted G_GNUC_UNUSED;
2391 guint stream_specific_size;
2392 guint type_specific_size G_GNUC_UNUSED;
2393 guint unknown G_GNUC_UNUSED;
2395 /* Get the rest of the header's header */
2396 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2397 goto not_enough_data;
2399 gst_asf_demux_get_guid (&guid, &data, &size);
2400 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2402 gst_asf_demux_get_guid (&guid, &data, &size);
2403 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2405 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2407 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2408 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2410 flags = gst_asf_demux_get_uint16 (&data, &size);
2411 stream_id = flags & 0x7f;
2412 is_encrypted = ! !((flags & 0x8000) << 15);
2413 unknown = gst_asf_demux_get_uint32 (&data, &size);
2415 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2416 stream_id, GST_TIME_ARGS (time_offset));
2418 switch (stream_type) {
2419 case ASF_STREAM_AUDIO:{
2420 asf_stream_audio audio_object;
2422 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2423 goto not_enough_data;
2425 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2428 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2431 switch (correction_type) {
2432 case ASF_CORRECTION_ON:{
2433 guint span, packet_size, chunk_size, data_size, silence_data;
2435 GST_INFO ("Using error correction");
2437 if (size < (1 + 2 + 2 + 2 + 1))
2438 goto not_enough_data;
2440 span = gst_asf_demux_get_uint8 (&data, &size);
2441 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2442 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2443 data_size = gst_asf_demux_get_uint16 (&data, &size);
2444 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2446 /* FIXME: shouldn't this be per-stream? */
2449 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2450 packet_size, chunk_size, data_size, span, silence_data);
2452 if (demux->span > 1) {
2453 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2454 /* Disable descrambling */
2457 /* FIXME: this else branch was added for
2458 * weird_al_yankovic - the saga begins.asf */
2459 demux->ds_packet_size = packet_size;
2460 demux->ds_chunk_size = chunk_size;
2463 /* Descambling is enabled */
2464 demux->ds_packet_size = packet_size;
2465 demux->ds_chunk_size = chunk_size;
2468 /* Now skip the rest of the silence data */
2470 gst_bytestream_flush (demux->bs, data_size - 1);
2472 /* FIXME: CHECKME. And why -1? */
2473 if (data_size > 1) {
2474 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2475 goto not_enough_data;
2481 case ASF_CORRECTION_OFF:{
2482 GST_INFO ("Error correction off");
2483 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2484 goto not_enough_data;
2488 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2489 ("Audio stream using unknown error correction"));
2496 case ASF_STREAM_VIDEO:{
2497 asf_stream_video_format video_format_object;
2498 asf_stream_video video_object;
2501 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2502 goto not_enough_data;
2504 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2506 GST_INFO ("object is a video stream with %u bytes of "
2507 "additional data", vsize);
2509 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2511 goto not_enough_data;
2514 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2521 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2526 return gst_asf_demux_get_stream (demux, stream_id);
2530 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2531 /* we'll error out later if we found no streams */
2536 static const gchar *
2537 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2541 const gchar *asf_name;
2542 const gchar *gst_name;
2545 "WM/Genre", GST_TAG_GENRE}, {
2546 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2547 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2548 "WM/Picture", GST_TAG_IMAGE}, {
2549 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2550 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2551 "WM/Year", GST_TAG_DATE_TIME}
2552 /* { "WM/Composer", GST_TAG_COMPOSER } */
2557 if (name_utf8 == NULL) {
2558 GST_WARNING ("Failed to convert name to UTF8, skipping");
2562 out = strlen (name_utf8);
2564 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2565 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2566 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2567 return tags[i].gst_name;
2574 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2576 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2580 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2582 if (taglist == NULL)
2585 if (gst_tag_list_is_empty (taglist)) {
2586 gst_tag_list_free (taglist);
2590 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2591 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
2593 gst_tag_list_free (demux->taglist);
2594 gst_tag_list_free (taglist);
2596 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2599 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2600 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2601 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2604 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2608 const guint8 *img_data = NULL;
2609 guint32 img_data_len = 0;
2610 guint8 pic_type = 0;
2612 gst_byte_reader_init (&r, tag_data, tag_data_len);
2614 /* skip mime type string (we don't trust it and do our own typefinding),
2615 * and also skip the description string, since we don't use it */
2616 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2617 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2618 !gst_byte_reader_skip_string_utf16 (&r) ||
2619 !gst_byte_reader_skip_string_utf16 (&r) ||
2620 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2621 goto not_enough_data;
2625 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2626 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2632 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2633 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2638 /* Extended Content Description Object */
2639 static GstFlowReturn
2640 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2643 /* Other known (and unused) 'text/unicode' metadata available :
2646 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2647 * WMFSDKVersion = 9.00.00.2980
2648 * WMFSDKNeeded = 0.0.0.0000
2649 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2650 * WM/Publisher = 4AD
2652 * WM/ProviderRating = 8
2653 * WM/ProviderStyle = Rock (similar to WM/Genre)
2654 * WM/GenreID (similar to WM/Genre)
2655 * WM/TrackNumber (same as WM/Track but as a string)
2657 * Other known (and unused) 'non-text' metadata available :
2663 * We might want to read WM/TrackNumber and use atoi() if we don't have
2667 GstTagList *taglist;
2668 guint16 blockcount, i;
2670 GST_INFO_OBJECT (demux, "object is an extended content description");
2672 taglist = gst_tag_list_new_empty ();
2674 /* Content Descriptor Count */
2676 goto not_enough_data;
2678 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2680 for (i = 1; i <= blockcount; ++i) {
2681 const gchar *gst_tag_name;
2685 GValue tag_value = { 0, };
2688 gchar *name_utf8 = NULL;
2692 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2693 goto not_enough_data;
2697 goto not_enough_data;
2699 /* Descriptor Value Data Type */
2700 datatype = gst_asf_demux_get_uint16 (&data, &size);
2702 /* Descriptor Value (not really a string, but same thing reading-wise) */
2703 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2705 goto not_enough_data;
2709 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2711 if (name_utf8 != NULL) {
2712 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2714 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2715 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2718 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2721 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2724 /* get rid of tags with empty value */
2725 if (value_utf8 != NULL && *value_utf8 != '\0') {
2726 GST_DEBUG ("string value %s", value_utf8);
2728 value_utf8[out] = '\0';
2730 if (gst_tag_name != NULL) {
2731 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
2732 guint year = atoi (value_utf8);
2735 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
2736 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
2738 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2739 guint id3v1_genre_id;
2740 const gchar *genre_str;
2742 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2743 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2744 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2745 g_free (value_utf8);
2746 value_utf8 = g_strdup (genre_str);
2751 /* convert tag from string to other type if required */
2752 tag_type = gst_tag_get_type (gst_tag_name);
2753 g_value_init (&tag_value, tag_type);
2754 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2755 GValue from_val = { 0, };
2757 g_value_init (&from_val, G_TYPE_STRING);
2758 g_value_set_string (&from_val, value_utf8);
2759 if (!g_value_transform (&from_val, &tag_value)) {
2760 GST_WARNING_OBJECT (demux,
2761 "Could not transform string tag to " "%s tag type %s",
2762 gst_tag_name, g_type_name (tag_type));
2763 g_value_unset (&tag_value);
2765 g_value_unset (&from_val);
2770 GST_DEBUG ("Setting metadata");
2771 g_value_init (&tag_value, G_TYPE_STRING);
2772 g_value_set_string (&tag_value, value_utf8);
2774 } else if (value_utf8 == NULL) {
2775 GST_WARNING ("Failed to convert string value to UTF8, skipping");
2777 GST_DEBUG ("Skipping empty string value for %s",
2778 GST_STR_NULL (gst_tag_name));
2780 g_free (value_utf8);
2783 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2785 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2786 GST_FIXME ("Unhandled byte array tag %s",
2787 GST_STR_NULL (gst_tag_name));
2790 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2796 case ASF_DEMUX_DATA_TYPE_DWORD:{
2797 guint uint_val = GST_READ_UINT32_LE (value);
2799 /* this is the track number */
2800 g_value_init (&tag_value, G_TYPE_UINT);
2802 /* WM/Track counts from 0 */
2803 if (!strcmp (name_utf8, "WM/Track"))
2806 g_value_set_uint (&tag_value, uint_val);
2810 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2815 if (G_IS_VALUE (&tag_value)) {
2817 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2819 /* WM/TrackNumber is more reliable than WM/Track, since the latter
2820 * is supposed to have a 0 base but is often wrongly written to start
2821 * from 1 as well, so prefer WM/TrackNumber when we have it: either
2822 * replace the value added earlier from WM/Track or put it first in
2823 * the list, so that it will get picked up by _get_uint() */
2824 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2825 merge_mode = GST_TAG_MERGE_REPLACE;
2827 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2830 GST_DEBUG ("Setting global metadata %s", name_utf8);
2831 gst_structure_set_value (demux->global_metadata, name_utf8,
2835 g_value_unset (&tag_value);
2844 gst_asf_demux_add_global_tags (demux, taglist);
2851 GST_WARNING ("Unexpected end of data parsing ext content desc object");
2852 gst_tag_list_free (taglist);
2853 return GST_FLOW_OK; /* not really fatal */
2857 static GstStructure *
2858 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2863 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2865 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2868 s = gst_caps_get_structure (demux->metadata, i);
2869 if (gst_structure_has_name (s, sname))
2873 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
2875 /* try lookup again; demux->metadata took ownership of the structure, so we
2876 * can't really make any assumptions about what happened to it, so we can't
2877 * just return it directly after appending it */
2878 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2881 static GstFlowReturn
2882 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2885 guint16 blockcount, i;
2887 GST_INFO_OBJECT (demux, "object is a metadata object");
2889 /* Content Descriptor Count */
2891 goto not_enough_data;
2893 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2895 for (i = 0; i < blockcount; ++i) {
2897 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
2898 guint32 data_len, ival;
2901 if (size < (2 + 2 + 2 + 2 + 4))
2902 goto not_enough_data;
2904 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2905 stream_num = gst_asf_demux_get_uint16 (&data, &size);
2906 name_len = gst_asf_demux_get_uint16 (&data, &size);
2907 data_type = gst_asf_demux_get_uint16 (&data, &size);
2908 data_len = gst_asf_demux_get_uint32 (&data, &size);
2910 if (size < name_len + data_len)
2911 goto not_enough_data;
2913 /* convert name to UTF-8 */
2914 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2916 gst_asf_demux_skip_bytes (name_len, &data, &size);
2918 if (name_utf8 == NULL) {
2919 GST_WARNING ("Failed to convert value name to UTF8, skipping");
2920 gst_asf_demux_skip_bytes (data_len, &data, &size);
2924 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2925 gst_asf_demux_skip_bytes (data_len, &data, &size);
2933 goto not_enough_data;
2936 ival = gst_asf_demux_get_uint32 (&data, &size);
2938 /* skip anything else there may be, just in case */
2939 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2941 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2942 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2946 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2952 GST_WARNING ("Unexpected end of data parsing metadata object");
2953 return GST_FLOW_OK; /* not really fatal */
2957 static GstFlowReturn
2958 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2960 GstFlowReturn ret = GST_FLOW_OK;
2961 guint32 i, num_objects;
2962 guint8 unknown G_GNUC_UNUSED;
2964 /* Get the rest of the header's header */
2965 if (size < (4 + 1 + 1))
2966 goto not_enough_data;
2968 num_objects = gst_asf_demux_get_uint32 (&data, &size);
2969 unknown = gst_asf_demux_get_uint8 (&data, &size);
2970 unknown = gst_asf_demux_get_uint8 (&data, &size);
2972 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2974 /* Loop through the header's objects, processing those */
2975 for (i = 0; i < num_objects; ++i) {
2976 GST_INFO_OBJECT (demux, "reading header part %u", i);
2977 ret = gst_asf_demux_process_object (demux, &data, &size);
2978 if (ret != GST_FLOW_OK) {
2979 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2988 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2989 ("short read parsing HEADER object"));
2990 return GST_FLOW_ERROR;
2994 static GstFlowReturn
2995 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2997 guint64 creation_time G_GNUC_UNUSED;
2998 guint64 file_size G_GNUC_UNUSED;
2999 guint64 send_time G_GNUC_UNUSED;
3000 guint64 packets_count, play_time, preroll;
3001 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3003 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3004 goto not_enough_data;
3006 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3007 file_size = gst_asf_demux_get_uint64 (&data, &size);
3008 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3009 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3010 play_time = gst_asf_demux_get_uint64 (&data, &size);
3011 send_time = gst_asf_demux_get_uint64 (&data, &size);
3012 preroll = gst_asf_demux_get_uint64 (&data, &size);
3013 flags = gst_asf_demux_get_uint32 (&data, &size);
3014 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3015 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3016 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3018 demux->broadcast = ! !(flags & 0x01);
3019 demux->seekable = ! !(flags & 0x02);
3021 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3022 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3023 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3025 if (demux->broadcast) {
3026 /* these fields are invalid if the broadcast flag is set */
3031 if (min_pktsize != max_pktsize)
3032 goto non_fixed_packet_size;
3034 demux->packet_size = max_pktsize;
3036 /* FIXME: do we need send_time as well? what is it? */
3037 if ((play_time * 100) >= (preroll * GST_MSECOND))
3038 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3040 demux->play_time = 0;
3042 demux->preroll = preroll * GST_MSECOND;
3044 /* initial latency */
3045 demux->latency = demux->preroll;
3047 if (demux->play_time == 0)
3048 demux->seekable = FALSE;
3050 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3051 GST_TIME_ARGS (demux->play_time));
3052 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3053 GST_TIME_ARGS (demux->preroll));
3055 if (demux->play_time > 0) {
3056 demux->segment.duration = demux->play_time;
3059 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3061 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3066 non_fixed_packet_size:
3068 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3069 ("packet size must be fixed"));
3070 return GST_FLOW_ERROR;
3074 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3075 ("short read parsing FILE object"));
3076 return GST_FLOW_ERROR;
3080 /* Content Description Object */
3081 static GstFlowReturn
3082 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3086 const gchar *gst_tag;
3091 GST_TAG_TITLE, 0, NULL}, {
3092 GST_TAG_ARTIST, 0, NULL}, {
3093 GST_TAG_COPYRIGHT, 0, NULL}, {
3094 GST_TAG_DESCRIPTION, 0, NULL}, {
3095 GST_TAG_COMMENT, 0, NULL}
3097 GstTagList *taglist;
3098 GValue value = { 0 };
3102 GST_INFO_OBJECT (demux, "object is a comment");
3104 if (size < (2 + 2 + 2 + 2 + 2))
3105 goto not_enough_data;
3107 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3108 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3109 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3110 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3111 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3113 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3114 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3115 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3117 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3118 if (size < tags[i].val_length)
3119 goto not_enough_data;
3121 /* might be just '/0', '/0'... */
3122 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3123 /* convert to UTF-8 */
3124 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3125 "UTF-8", "UTF-16LE", &in, &out, NULL);
3127 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3130 /* parse metadata into taglist */
3131 taglist = gst_tag_list_new_empty ();
3132 g_value_init (&value, G_TYPE_STRING);
3133 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3134 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3135 g_value_set_string (&value, tags[i].val_utf8);
3136 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3137 tags[i].gst_tag, &value, NULL);
3140 g_value_unset (&value);
3142 gst_asf_demux_add_global_tags (demux, taglist);
3144 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3145 g_free (tags[i].val_utf8);
3151 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3152 "comment tag section %d, skipping comment object", i);
3153 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3154 g_free (tags[i].val_utf8);
3155 return GST_FLOW_OK; /* not really fatal */
3159 static GstFlowReturn
3160 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3163 guint16 num_streams, i;
3167 goto not_enough_data;
3169 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3171 GST_INFO ("object is a bitrate properties object with %u streams",
3174 if (size < (num_streams * (2 + 4)))
3175 goto not_enough_data;
3177 for (i = 0; i < num_streams; ++i) {
3181 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3182 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3184 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3185 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3186 stream = gst_asf_demux_get_stream (demux, stream_id);
3188 if (stream->pending_tags == NULL) {
3189 stream->pending_tags =
3190 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3193 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3196 GST_WARNING ("stream id %u is too large", stream_id);
3204 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3205 return GST_FLOW_OK; /* not really fatal */
3209 static GstFlowReturn
3210 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3213 GstFlowReturn ret = GST_FLOW_OK;
3216 /* Get the rest of the header's header */
3217 if (size < (16 + 2 + 4))
3218 goto not_enough_data;
3220 /* skip GUID and two other bytes */
3221 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3222 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3224 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3226 /* FIXME: does data_size include the rest of the header that we have read? */
3227 if (hdr_size > size)
3228 goto not_enough_data;
3230 while (hdr_size > 0) {
3231 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3232 if (ret != GST_FLOW_OK)
3240 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3241 ("short read parsing extended header object"));
3242 return GST_FLOW_ERROR;
3246 static GstFlowReturn
3247 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3253 goto not_enough_data;
3255 if (demux->languages) {
3256 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3257 g_strfreev (demux->languages);
3258 demux->languages = NULL;
3259 demux->num_languages = 0;
3262 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3263 GST_LOG ("%u languages:", demux->num_languages);
3265 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3266 for (i = 0; i < demux->num_languages; ++i) {
3267 guint8 len, *lang_data = NULL;
3270 goto not_enough_data;
3271 len = gst_asf_demux_get_uint8 (&data, &size);
3272 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3275 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3278 /* truncate "en-us" etc. to just "en" */
3279 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3282 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3283 demux->languages[i] = utf8;
3286 goto not_enough_data;
3294 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3295 g_free (demux->languages);
3296 demux->languages = NULL;
3297 return GST_FLOW_OK; /* not fatal */
3301 static GstFlowReturn
3302 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3305 GstClockTime interval;
3308 if (size < (16 + 8 + 4 + 4))
3309 goto not_enough_data;
3312 gst_asf_demux_skip_bytes (16, &data, &size);
3313 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3314 gst_asf_demux_skip_bytes (4, &data, &size);
3315 count = gst_asf_demux_get_uint32 (&data, &size);
3317 demux->sidx_interval = interval;
3318 demux->sidx_num_entries = count;
3319 g_free (demux->sidx_entries);
3320 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3322 for (i = 0; i < count; ++i) {
3323 if (G_UNLIKELY (size <= 6))
3325 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3326 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3327 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3328 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3329 demux->sidx_entries[i].count);
3332 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3339 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3340 return GST_FLOW_OK; /* not fatal */
3344 static GstFlowReturn
3345 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3346 guint8 * data, guint64 size)
3352 if (size < 16 + 2 + (2 * 2))
3353 goto not_enough_data;
3355 gst_asf_demux_get_guid (&guid, &data, &size);
3356 num = gst_asf_demux_get_uint16 (&data, &size);
3359 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3363 if (size < (num * sizeof (guint16)))
3364 goto not_enough_data;
3366 /* read mutually exclusive stream numbers */
3367 mes = g_new (guint8, num + 1);
3368 for (i = 0; i < num; ++i) {
3369 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3370 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3373 /* add terminator so we can easily get the count or know when to stop */
3374 mes[i] = (guint8) - 1;
3376 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3383 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3384 return GST_FLOW_OK; /* not absolutely fatal */
3388 static GstFlowReturn
3389 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3392 AsfStreamExtProps esp;
3393 AsfStream *stream = NULL;
3394 AsfObject stream_obj;
3395 guint16 stream_name_count;
3396 guint16 num_payload_ext;
3398 guint8 *stream_obj_data = NULL;
3401 guint i, stream_num;
3404 obj_size = (guint) size;
3407 goto not_enough_data;
3410 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3411 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3412 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3413 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3414 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3415 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3416 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3417 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3418 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3419 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3420 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3421 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3422 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3423 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3424 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3426 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3427 GST_TIME_ARGS (esp.start_time));
3428 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3429 GST_TIME_ARGS (esp.end_time));
3430 GST_INFO ("flags = %08x", esp.flags);
3431 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3432 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3433 GST_INFO ("stream number = %u", stream_num);
3434 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3435 (esp.lang_idx < demux->num_languages) ?
3436 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3437 GST_INFO ("stream name count = %u", stream_name_count);
3439 /* read stream names */
3440 for (i = 0; i < stream_name_count; ++i) {
3441 guint16 stream_lang_idx G_GNUC_UNUSED;
3442 gchar *stream_name = NULL;
3445 goto not_enough_data;
3446 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3447 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3448 goto not_enough_data;
3449 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3450 g_free (stream_name); /* TODO: store names in struct */
3453 /* read payload extension systems stuff */
3454 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3456 if (num_payload_ext > 0)
3457 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3459 esp.payload_extensions = NULL;
3461 for (i = 0; i < num_payload_ext; ++i) {
3462 AsfPayloadExtension ext;
3464 guint32 sys_info_len;
3466 if (size < 16 + 2 + 4)
3467 goto not_enough_data;
3469 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3470 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3471 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3473 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3474 GST_LOG ("payload systems info len = %u", sys_info_len);
3475 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3476 goto not_enough_data;
3478 esp.payload_extensions[i] = ext;
3481 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3483 /* there might be an optional STREAM_INFO object here now; if not, we
3484 * should have parsed the corresponding stream info object already (since
3485 * we are parsing the extended stream properties objects delayed) */
3487 stream = gst_asf_demux_get_stream (demux, stream_num);
3491 /* get size of the stream object */
3492 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3493 goto not_enough_data;
3495 if (stream_obj.id != ASF_OBJ_STREAM)
3496 goto expected_stream_object;
3498 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3499 stream_obj.size > (10 * 1024 * 1024))
3500 goto not_enough_data;
3502 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3504 /* process this stream object later after all the other 'normal' ones
3505 * have been processed (since the others are more important/non-hidden) */
3506 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3507 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3508 goto not_enough_data;
3510 /* parse stream object */
3511 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3512 g_free (stream_obj_data);
3517 stream->ext_props = esp;
3519 /* try to set the framerate */
3520 if (stream->is_video && stream->caps) {
3521 GValue framerate = { 0 };
3525 g_value_init (&framerate, GST_TYPE_FRACTION);
3527 num = GST_SECOND / 100;
3528 denom = esp.avg_time_per_frame;
3530 /* avoid division by 0, assume 25/1 framerate */
3531 denom = GST_SECOND / 2500;
3534 gst_value_set_fraction (&framerate, num, denom);
3536 stream->caps = gst_caps_make_writable (stream->caps);
3537 s = gst_caps_get_structure (stream->caps, 0);
3538 gst_structure_set_value (s, "framerate", &framerate);
3539 g_value_unset (&framerate);
3540 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3541 num, denom, ((gdouble) num) / denom);
3544 /* add language info now if we have it */
3545 if (stream->ext_props.lang_idx < demux->num_languages) {
3546 if (stream->pending_tags == NULL)
3547 stream->pending_tags = gst_tag_list_new_empty ();
3548 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3549 demux->languages[stream->ext_props.lang_idx]);
3550 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3551 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3555 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3563 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3564 return GST_FLOW_OK; /* not absolutely fatal */
3566 expected_stream_object:
3568 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3569 "object: expected embedded stream object, but got %s object instead!",
3570 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3571 return GST_FLOW_OK; /* not absolutely fatal */
3575 static const gchar *
3576 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3580 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3581 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3582 nick += strlen ("ASF_OBJ_");
3584 if (demux->objpath == NULL) {
3585 demux->objpath = g_strdup (nick);
3589 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3590 g_free (demux->objpath);
3591 demux->objpath = newpath;
3594 return (const gchar *) demux->objpath;
3598 gst_asf_demux_pop_obj (GstASFDemux * demux)
3602 if ((s = g_strrstr (demux->objpath, "/"))) {
3605 g_free (demux->objpath);
3606 demux->objpath = NULL;
3611 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3616 /* Parse the queued extended stream property objects and add the info
3617 * to the existing streams or add the new embedded streams, but without
3618 * activating them yet */
3619 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3620 g_slist_length (demux->ext_stream_props));
3622 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3623 GstBuffer *buf = GST_BUFFER (l->data);
3626 gst_buffer_map (buf, &map, GST_MAP_READ);
3628 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3629 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
3630 gst_buffer_unmap (buf, &map);
3631 gst_buffer_unref (buf);
3633 g_slist_free (demux->ext_stream_props);
3634 demux->ext_stream_props = NULL;
3639 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3643 for (i = 0; i < demux->num_streams; ++i) {
3648 stream = &demux->stream[i];
3650 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3652 if (stream->active) {
3653 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3658 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3661 /* check for each mutual exclusion whether it affects this stream */
3662 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3663 if (*mes == stream->id) {
3664 /* if yes, check if we've already added streams that are mutually
3665 * exclusive with the stream we're about to add */
3666 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3667 for (j = 0; j < demux->num_streams; ++j) {
3668 /* if the broadcast flag is set, assume the hidden streams aren't
3669 * actually streamed and hide them (or playbin won't work right),
3670 * otherwise assume their data is available */
3671 if (demux->stream[j].id == *mes && demux->broadcast) {
3673 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3674 "mutually exclusive with already existing stream ID %d, "
3675 "hiding stream", stream->id, demux->stream[j].id);
3687 /* FIXME: we should do stream activation based on preroll data in
3688 * streaming mode too */
3689 if (demux->streaming && !is_hidden)
3690 gst_asf_demux_activate_stream (demux, stream);
3695 static GstFlowReturn
3696 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3699 GstFlowReturn ret = GST_FLOW_OK;
3701 guint64 obj_data_size;
3703 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3704 return ASF_FLOW_NEED_MORE_DATA;
3706 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3707 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3709 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3711 if (*p_size < obj_data_size)
3712 return ASF_FLOW_NEED_MORE_DATA;
3714 gst_asf_demux_push_obj (demux, obj.id);
3716 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3719 case ASF_OBJ_STREAM:
3720 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3724 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3726 case ASF_OBJ_HEADER:
3727 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3729 case ASF_OBJ_COMMENT:
3730 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3733 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3735 case ASF_OBJ_BITRATE_PROPS:
3737 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3740 case ASF_OBJ_EXT_CONTENT_DESC:
3742 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3745 case ASF_OBJ_METADATA_OBJECT:
3746 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3748 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3751 /* process these later, we might not have parsed the corresponding
3752 * stream object yet */
3753 GST_LOG ("%s: queued for later parsing", demux->objpath);
3754 buf = gst_buffer_new_and_alloc (obj_data_size);
3755 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
3756 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3760 case ASF_OBJ_LANGUAGE_LIST:
3761 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3763 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3764 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3767 case ASF_OBJ_SIMPLE_INDEX:
3768 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3770 case ASF_OBJ_CONTENT_ENCRYPTION:
3771 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3772 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3773 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
3774 goto error_encrypted;
3775 case ASF_OBJ_CONCEAL_NONE:
3777 case ASF_OBJ_UNDEFINED:
3778 case ASF_OBJ_CODEC_COMMENT:
3780 case ASF_OBJ_PADDING:
3781 case ASF_OBJ_BITRATE_MUTEX:
3782 case ASF_OBJ_COMPATIBILITY:
3783 case ASF_OBJ_INDEX_PLACEHOLDER:
3784 case ASF_OBJ_INDEX_PARAMETERS:
3785 case ASF_OBJ_STREAM_PRIORITIZATION:
3786 case ASF_OBJ_SCRIPT_COMMAND:
3788 /* Unknown/unhandled object, skip it and hope for the best */
3789 GST_INFO ("%s: skipping object", demux->objpath);
3794 /* this can't fail, we checked the number of bytes available before */
3795 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3797 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3799 gst_asf_demux_pop_obj (demux);
3806 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3807 return GST_FLOW_ERROR;
3812 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3813 GstBuffer ** p_buffer)
3815 GstBuffer *descrambled_buffer;
3816 GstBuffer *scrambled_buffer;
3817 GstBuffer *sub_buffer;
3824 /* descrambled_buffer is initialised in the first iteration */
3825 descrambled_buffer = NULL;
3826 scrambled_buffer = *p_buffer;
3828 if (gst_buffer_get_size (scrambled_buffer) <
3829 demux->ds_packet_size * demux->span)
3832 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
3833 offset += demux->ds_chunk_size) {
3834 off = offset / demux->ds_chunk_size;
3835 row = off / demux->span;
3836 col = off % demux->span;
3837 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3838 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3839 col, off, demux->ds_chunk_size);
3840 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
3841 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
3842 demux->span, demux->ds_packet_size);
3843 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
3844 gst_buffer_get_size (scrambled_buffer));
3846 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_NONE,
3847 idx * demux->ds_chunk_size, demux->ds_chunk_size);
3849 descrambled_buffer = sub_buffer;
3851 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
3855 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
3856 GST_BUFFER_TIMESTAMP (scrambled_buffer);
3857 GST_BUFFER_DURATION (descrambled_buffer) =
3858 GST_BUFFER_DURATION (scrambled_buffer);
3859 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
3860 GST_BUFFER_OFFSET_END (descrambled_buffer) =
3861 GST_BUFFER_OFFSET_END (scrambled_buffer);
3863 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3865 gst_buffer_unref (scrambled_buffer);
3866 *p_buffer = descrambled_buffer;
3870 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3872 GstASFDemux *demux = GST_ASF_DEMUX (element);
3875 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3877 for (i = 0; i < demux->num_streams; ++i) {
3878 gst_event_ref (event);
3879 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
3880 GST_OBJECT_CAST (element), event)) {
3881 gst_event_unref (event);
3886 gst_event_unref (event);
3890 /* takes ownership of the passed event */
3892 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3894 gboolean ret = TRUE;
3897 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3898 GST_EVENT_TYPE_NAME (event));
3900 for (i = 0; i < demux->num_streams; ++i) {
3901 gst_event_ref (event);
3902 ret &= gst_pad_push_event (demux->stream[i].pad, event);
3904 gst_event_unref (event);
3909 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
3913 gboolean res = FALSE;
3915 demux = GST_ASF_DEMUX (parent);
3917 GST_DEBUG ("handling %s query",
3918 gst_query_type_get_name (GST_QUERY_TYPE (query)));
3920 switch (GST_QUERY_TYPE (query)) {
3921 case GST_QUERY_DURATION:
3925 gst_query_parse_duration (query, &format, NULL);
3927 if (format != GST_FORMAT_TIME) {
3928 GST_LOG ("only support duration queries in TIME format");
3932 GST_OBJECT_LOCK (demux);
3934 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3935 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3936 GST_TIME_ARGS (demux->segment.duration));
3938 gst_query_set_duration (query, GST_FORMAT_TIME,
3939 demux->segment.duration);
3943 GST_LOG ("duration not known yet");
3946 GST_OBJECT_UNLOCK (demux);
3950 case GST_QUERY_POSITION:{
3953 gst_query_parse_position (query, &format, NULL);
3955 if (format != GST_FORMAT_TIME) {
3956 GST_LOG ("only support position queries in TIME format");
3960 GST_OBJECT_LOCK (demux);
3962 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
3963 GST_LOG ("returning position: %" GST_TIME_FORMAT,
3964 GST_TIME_ARGS (demux->segment.position));
3966 gst_query_set_position (query, GST_FORMAT_TIME,
3967 demux->segment.position);
3971 GST_LOG ("position not known yet");
3974 GST_OBJECT_UNLOCK (demux);
3978 case GST_QUERY_SEEKING:{
3981 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3982 if (format == GST_FORMAT_TIME) {
3985 GST_OBJECT_LOCK (demux);
3986 duration = demux->segment.duration;
3987 GST_OBJECT_UNLOCK (demux);
3989 if (!demux->streaming || !demux->seekable) {
3990 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3997 /* try downstream first in TIME */
3998 res = gst_pad_query_default (pad, parent, query);
4000 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4001 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4002 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4003 /* if no luck, maybe in BYTES */
4004 if (!seekable || fmt != GST_FORMAT_TIME) {
4007 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4008 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4009 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4010 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4011 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4012 if (fmt != GST_FORMAT_BYTES)
4015 gst_query_unref (q);
4016 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4022 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4026 case GST_QUERY_LATENCY:
4029 GstClockTime min, max;
4031 /* preroll delay does not matter in non-live pipeline,
4032 * but we might end up in a live (rtsp) one ... */
4035 res = gst_pad_query_default (pad, parent, query);
4039 gst_query_parse_latency (query, &live, &min, &max);
4041 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4042 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4043 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4045 GST_OBJECT_LOCK (demux);
4047 min += demux->latency;
4049 max += demux->latency;
4050 GST_OBJECT_UNLOCK (demux);
4052 gst_query_set_latency (query, live, min, max);
4056 res = gst_pad_query_default (pad, parent, query);
4063 static GstStateChangeReturn
4064 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4066 GstASFDemux *demux = GST_ASF_DEMUX (element);
4067 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4069 switch (transition) {
4070 case GST_STATE_CHANGE_NULL_TO_READY:{
4071 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4072 demux->need_newsegment = TRUE;
4073 demux->segment_running = FALSE;
4074 demux->accurate = FALSE;
4075 demux->adapter = gst_adapter_new ();
4076 demux->metadata = gst_caps_new_empty ();
4077 demux->global_metadata = gst_structure_new_empty ("metadata");
4078 demux->data_size = 0;
4079 demux->data_offset = 0;
4080 demux->index_offset = 0;
4081 demux->base_offset = 0;
4088 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4089 if (ret == GST_STATE_CHANGE_FAILURE)
4092 switch (transition) {
4093 case GST_STATE_CHANGE_PAUSED_TO_READY:
4094 case GST_STATE_CHANGE_READY_TO_NULL:
4095 gst_asf_demux_reset (demux, FALSE);