1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
45 #include "gstasfdemux.h"
46 #include "asfheaders.h"
47 #include "asfpacket.h"
49 static GstStaticPadTemplate gst_asf_demux_sink_template =
50 GST_STATIC_PAD_TEMPLATE ("sink",
53 GST_STATIC_CAPS ("video/x-ms-asf")
56 static GstStaticPadTemplate audio_src_template =
57 GST_STATIC_PAD_TEMPLATE ("audio_%u",
62 static GstStaticPadTemplate video_src_template =
63 GST_STATIC_PAD_TEMPLATE ("video_%u",
68 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
69 #define ASF_OBJECT_HEADER_SIZE (16+8)
71 /* FIXME: get rid of this */
72 /* abuse this GstFlowReturn enum for internal usage */
73 #define ASF_FLOW_NEED_MORE_DATA 99
75 #define gst_asf_get_flow_name(flow) \
76 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
77 "need-more-data" : gst_flow_get_name (flow)
79 GST_DEBUG_CATEGORY (asfdemux_dbg);
81 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
82 GstStateChange transition);
83 static gboolean gst_asf_demux_element_send_event (GstElement * element,
85 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
87 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
88 GstObject * parent, GstQuery * query);
89 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
91 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
93 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
94 guint8 ** p_data, guint64 * p_size);
95 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
96 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
97 GstObject * parent, GstPadMode mode, gboolean active);
98 static void gst_asf_demux_loop (GstASFDemux * demux);
100 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
101 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
102 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
103 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
105 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
106 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
107 AsfStream * stream, GstBuffer ** p_buffer);
108 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
110 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
112 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
115 #define gst_asf_demux_parent_class parent_class
116 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
119 gst_asf_demux_class_init (GstASFDemuxClass * klass)
121 GstElementClass *gstelement_class;
123 gstelement_class = (GstElementClass *) klass;
125 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
127 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
129 gst_element_class_add_pad_template (gstelement_class,
130 gst_static_pad_template_get (&audio_src_template));
131 gst_element_class_add_pad_template (gstelement_class,
132 gst_static_pad_template_get (&video_src_template));
133 gst_element_class_add_pad_template (gstelement_class,
134 gst_static_pad_template_get (&gst_asf_demux_sink_template));
136 gstelement_class->change_state =
137 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
138 gstelement_class->send_event =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
143 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
145 gst_caps_replace (&stream->caps, NULL);
146 if (stream->pending_tags) {
147 gst_tag_list_unref (stream->pending_tags);
148 stream->pending_tags = NULL;
150 if (stream->streamheader) {
151 gst_buffer_unref (stream->streamheader);
152 stream->streamheader = NULL;
155 if (stream->active) {
156 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
157 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
159 gst_object_unref (stream->pad);
163 if (stream->payloads) {
164 while (stream->payloads->len > 0) {
168 last = stream->payloads->len - 1;
169 payload = &g_array_index (stream->payloads, AsfPayload, last);
170 gst_buffer_replace (&payload->buf, NULL);
171 g_array_remove_index (stream->payloads, last);
173 g_array_free (stream->payloads, TRUE);
174 stream->payloads = NULL;
176 if (stream->ext_props.valid) {
177 g_free (stream->ext_props.payload_extensions);
178 stream->ext_props.payload_extensions = NULL;
183 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
185 GST_LOG_OBJECT (demux, "resetting");
187 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
188 demux->segment_running = FALSE;
189 if (demux->adapter && !chain_reset) {
190 gst_adapter_clear (demux->adapter);
191 g_object_unref (demux->adapter);
192 demux->adapter = NULL;
194 if (demux->taglist) {
195 gst_tag_list_unref (demux->taglist);
196 demux->taglist = NULL;
198 if (demux->metadata) {
199 gst_caps_unref (demux->metadata);
200 demux->metadata = NULL;
202 if (demux->global_metadata) {
203 gst_structure_free (demux->global_metadata);
204 demux->global_metadata = NULL;
207 demux->state = GST_ASF_DEMUX_STATE_HEADER;
208 g_free (demux->objpath);
209 demux->objpath = NULL;
210 g_strfreev (demux->languages);
211 demux->languages = NULL;
212 demux->num_languages = 0;
213 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
215 g_slist_free (demux->ext_stream_props);
216 demux->ext_stream_props = NULL;
218 while (demux->old_num_streams > 0) {
219 gst_asf_demux_free_stream (demux,
220 &demux->old_stream[demux->old_num_streams - 1]);
221 --demux->old_num_streams;
223 memset (demux->old_stream, 0, sizeof (demux->old_stream));
224 demux->old_num_streams = 0;
226 /* when resetting for a new chained asf, we don't want to remove the pads
227 * before adding the new ones */
229 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
230 demux->old_num_streams = demux->num_streams;
231 demux->num_streams = 0;
234 while (demux->num_streams > 0) {
235 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
236 --demux->num_streams;
238 memset (demux->stream, 0, sizeof (demux->stream));
240 /* do not remove those for not adding pads with same name */
241 demux->num_audio_streams = 0;
242 demux->num_video_streams = 0;
243 demux->have_group_id = FALSE;
244 demux->group_id = G_MAXUINT;
246 demux->num_streams = 0;
247 demux->activated_streams = FALSE;
248 demux->first_ts = GST_CLOCK_TIME_NONE;
249 demux->segment_ts = GST_CLOCK_TIME_NONE;
252 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
253 demux->state = GST_ASF_DEMUX_STATE_HEADER;
254 demux->seekable = FALSE;
255 demux->broadcast = FALSE;
256 demux->sidx_interval = 0;
257 demux->sidx_num_entries = 0;
258 g_free (demux->sidx_entries);
259 demux->sidx_entries = NULL;
261 demux->speed_packets = 1;
264 GST_LOG_OBJECT (demux, "Restarting");
265 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
266 demux->need_newsegment = TRUE;
267 demux->segment_seqnum = 0;
268 demux->segment_running = FALSE;
269 demux->accurate = FALSE;
270 demux->metadata = gst_caps_new_empty ();
271 demux->global_metadata = gst_structure_new_empty ("metadata");
272 demux->data_size = 0;
273 demux->data_offset = 0;
274 demux->index_offset = 0;
276 demux->base_offset = 0;
279 g_slist_free (demux->other_streams);
280 demux->other_streams = NULL;
284 gst_asf_demux_init (GstASFDemux * demux)
287 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
288 gst_pad_set_chain_function (demux->sinkpad,
289 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
290 gst_pad_set_event_function (demux->sinkpad,
291 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
292 gst_pad_set_activate_function (demux->sinkpad,
293 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
294 gst_pad_set_activatemode_function (demux->sinkpad,
295 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
296 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
298 /* set initial state */
299 gst_asf_demux_reset (demux, FALSE);
303 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
308 query = gst_query_new_scheduling ();
310 if (!gst_pad_peer_query (sinkpad, query)) {
311 gst_query_unref (query);
315 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
316 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
317 gst_query_unref (query);
322 GST_DEBUG_OBJECT (sinkpad, "activating pull");
323 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
327 GST_DEBUG_OBJECT (sinkpad, "activating push");
328 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
333 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
334 GstPadMode mode, gboolean active)
339 demux = GST_ASF_DEMUX (parent);
342 case GST_PAD_MODE_PUSH:
343 demux->state = GST_ASF_DEMUX_STATE_HEADER;
344 demux->streaming = TRUE;
347 case GST_PAD_MODE_PULL:
349 demux->state = GST_ASF_DEMUX_STATE_HEADER;
350 demux->streaming = FALSE;
352 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
355 res = gst_pad_stop_task (sinkpad);
366 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
371 demux = GST_ASF_DEMUX (parent);
373 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
374 switch (GST_EVENT_TYPE (event)) {
375 case GST_EVENT_SEGMENT:{
376 const GstSegment *segment;
378 gst_event_parse_segment (event, &segment);
380 if (segment->format == GST_FORMAT_BYTES) {
381 if (demux->packet_size && segment->start > demux->data_offset)
382 demux->packet = (segment->start - demux->data_offset) /
386 } else if (segment->format == GST_FORMAT_TIME) {
387 /* do not know packet position, not really a problem */
390 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
391 gst_event_unref (event);
395 /* record upstream segment for interpolation */
396 if (segment->format != demux->in_segment.format)
397 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
398 gst_segment_copy_into (segment, &demux->in_segment);
400 /* in either case, clear some state and generate newsegment later on */
401 GST_OBJECT_LOCK (demux);
402 demux->segment_ts = GST_CLOCK_TIME_NONE;
403 demux->in_gap = GST_CLOCK_TIME_NONE;
404 demux->need_newsegment = TRUE;
405 demux->segment_seqnum = gst_event_get_seqnum (event);
406 gst_asf_demux_reset_stream_state_after_discont (demux);
407 GST_OBJECT_UNLOCK (demux);
409 gst_event_unref (event);
415 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
416 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
417 (_("This stream contains no data.")),
418 ("got eos and didn't receive a complete header object"));
421 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
422 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
423 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
424 (_("Internal data stream error.")),
425 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
429 GST_OBJECT_LOCK (demux);
430 gst_adapter_clear (demux->adapter);
431 GST_OBJECT_UNLOCK (demux);
432 gst_asf_demux_send_event_unlocked (demux, event);
436 case GST_EVENT_FLUSH_STOP:
437 GST_OBJECT_LOCK (demux);
438 gst_asf_demux_reset_stream_state_after_discont (demux);
439 GST_OBJECT_UNLOCK (demux);
440 gst_asf_demux_send_event_unlocked (demux, event);
441 /* upon activation, latency is no longer introduced, e.g. after seek */
442 if (demux->activated_streams)
447 ret = gst_pad_event_default (pad, parent, event);
455 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
456 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
457 gboolean next, gboolean * eos)
459 GstClockTime idx_time;
465 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
468 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
471 /* if we want the next keyframe, we have to go forward till we find
472 a different packet number */
474 if (idx >= demux->sidx_num_entries - 1) {
475 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
480 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
481 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
488 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
494 *packet = demux->sidx_entries[idx].packet;
496 *speed = demux->sidx_entries[idx].count;
498 /* so we get closer to the actual time of the packet ... actually, let's not
499 * do this, since we throw away superfluous payloads before the seek position
500 * anyway; this way, our key unit seek 'snap resolution' is a bit better
501 * (ie. same as index resolution) */
503 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
507 idx_time = demux->sidx_interval * idx;
508 if (G_LIKELY (idx_time >= demux->preroll))
509 idx_time -= demux->preroll;
511 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
512 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
513 GST_TIME_ARGS (idx_time));
515 if (G_LIKELY (p_idx_time))
516 *p_idx_time = idx_time;
522 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
526 gst_adapter_clear (demux->adapter);
528 GST_DEBUG_OBJECT (demux, "reset stream state");
530 for (n = 0; n < demux->num_streams; n++) {
531 demux->stream[n].discont = TRUE;
532 demux->stream[n].first_buffer = TRUE;
534 while (demux->stream[n].payloads->len > 0) {
538 last = demux->stream[n].payloads->len - 1;
539 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
540 gst_buffer_replace (&payload->buf, NULL);
541 g_array_remove_index (demux->stream[n].payloads, last);
547 gst_asf_demux_mark_discont (GstASFDemux * demux)
551 GST_DEBUG_OBJECT (demux, "Mark stream discont");
553 for (n = 0; n < demux->num_streams; n++)
554 demux->stream[n].discont = TRUE;
557 /* do a seek in push based mode */
559 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
564 GstSeekType cur_type, stop_type;
568 GstEvent *byte_event;
570 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
573 stop_type = GST_SEEK_TYPE_NONE;
576 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
578 /* determine packet, by index or by estimation */
579 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
582 (guint) gst_util_uint64_scale (demux->num_packets, cur,
586 if (packet > demux->num_packets) {
587 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
592 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
594 cur = demux->data_offset + (packet * demux->packet_size);
596 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
597 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
598 /* BYTE seek event */
599 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
600 cur, stop_type, stop);
601 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
602 res = gst_pad_push_event (demux->sinkpad, byte_event);
608 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
610 GstClockTime idx_time;
613 GstSeekType cur_type, stop_type;
615 gboolean only_need_update;
616 gboolean keyunit_sync, after, before, next;
621 guint packet, speed_count = 1;
626 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
627 demux->num_packets == 0 || demux->play_time == 0)) {
628 GST_LOG_OBJECT (demux, "stream is not seekable");
632 if (G_UNLIKELY (!demux->activated_streams)) {
633 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
637 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
639 seqnum = gst_event_get_seqnum (event);
641 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
642 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
646 if (G_UNLIKELY (rate <= 0.0)) {
647 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
651 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
653 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
654 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
655 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
656 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
657 next = after && !before;
659 if (G_UNLIKELY (demux->streaming)) {
660 /* support it safely needs more segment handling, e.g. closing etc */
662 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
665 /* we can (re)construct the start later on, but not the end */
666 if (stop_type != GST_SEEK_TYPE_NONE &&
667 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
668 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
671 gst_event_ref (event);
672 /* upstream might handle TIME seek, e.g. mms or rtsp,
673 * or not, e.g. http, then we give it a hand */
674 if (!gst_pad_push_event (demux->sinkpad, event))
675 return gst_asf_demux_handle_seek_push (demux, event);
680 /* unlock the streaming thread */
681 if (G_LIKELY (flush)) {
682 fevent = gst_event_new_flush_start ();
684 gst_event_set_seqnum (fevent, seqnum);
685 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
686 gst_asf_demux_send_event_unlocked (demux, fevent);
688 gst_pad_pause_task (demux->sinkpad);
691 /* grab the stream lock so that streaming cannot continue, for
692 * non flushing seeks when the element is in PAUSED this could block
694 GST_PAD_STREAM_LOCK (demux->sinkpad);
696 /* we now can stop flushing, since we have the stream lock now */
697 fevent = gst_event_new_flush_stop (TRUE);
698 gst_event_set_seqnum (fevent, seqnum);
699 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
701 if (G_LIKELY (flush))
702 gst_asf_demux_send_event_unlocked (demux, fevent);
704 gst_event_unref (fevent);
706 /* operating on copy of segment until we know the seek worked */
707 segment = demux->segment;
709 if (G_UNLIKELY (demux->segment_running && !flush)) {
710 GstSegment newsegment;
713 /* create the segment event to close the current segment */
714 gst_segment_copy_into (&segment, &newsegment);
715 newseg = gst_event_new_segment (&newsegment);
716 gst_event_set_seqnum (newseg, seqnum);
718 gst_asf_demux_send_event_unlocked (demux, newseg);
721 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
722 cur, stop_type, stop, &only_need_update);
724 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
725 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
727 if (cur_type != GST_SEEK_TYPE_SET)
728 seek_time = segment.start;
732 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
733 * real start of data and segment_start to indexed time for key unit seek*/
734 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
735 &idx_time, &speed_count, next, &eos))) {
739 demux->packet = demux->num_packets;
743 /* First try to query our source to see if it can convert for us. This is
744 the case when our source is an mms stream, notice that in this case
745 gstmms will do a time based seek to get the byte offset, this is not a
746 problem as the seek to this offset needs to happen anway. */
747 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
748 GST_FORMAT_BYTES, &offset)) {
749 packet = (offset - demux->data_offset) / demux->packet_size;
750 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
751 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
752 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
753 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
754 demux->packet_size, packet);
756 /* FIXME: For streams containing video, seek to an earlier position in
757 * the hope of hitting a keyframe and let the sinks throw away the stuff
758 * before the segment start. For audio-only this is unnecessary as every
760 if (flush && (demux->accurate || (keyunit_sync && !next))
761 && demux->num_video_streams > 0) {
762 seek_time -= 5 * GST_SECOND;
767 packet = (guint) gst_util_uint64_scale (demux->num_packets,
768 seek_time, demux->play_time);
770 if (packet > demux->num_packets)
771 packet = demux->num_packets;
774 if (G_LIKELY (keyunit_sync)) {
775 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
776 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
777 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
778 segment.start = idx_time;
779 segment.position = idx_time;
780 segment.time = idx_time;
784 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
786 GST_OBJECT_LOCK (demux);
787 demux->segment = segment;
788 demux->packet = packet;
789 demux->need_newsegment = TRUE;
790 demux->segment_seqnum = seqnum;
791 demux->speed_packets = speed_count;
792 gst_asf_demux_reset_stream_state_after_discont (demux);
793 GST_OBJECT_UNLOCK (demux);
796 /* restart our task since it might have been stopped when we did the flush */
797 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
800 /* streaming can continue now */
801 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
807 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
813 demux = GST_ASF_DEMUX (parent);
815 switch (GST_EVENT_TYPE (event)) {
817 GST_LOG_OBJECT (pad, "seek event");
818 ret = gst_asf_demux_handle_seek_event (demux, event);
819 gst_event_unref (event);
822 case GST_EVENT_NAVIGATION:
823 /* just drop these two silently */
824 gst_event_unref (event);
828 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
829 ret = gst_pad_event_default (pad, parent, event);
836 static inline guint32
837 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
841 ret = gst_asf_identify_guid (guids, guid);
843 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
844 gst_asf_get_guid_nick (guids, ret),
845 guid->v1, guid->v2, guid->v3, guid->v4);
857 /* expect is true when the user is expeting an object,
858 * when false, it will give no warnings if the object
862 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
863 guint data_len, AsfObject * object, gboolean expect)
867 if (data_len < ASF_OBJECT_HEADER_SIZE)
870 guid.v1 = GST_READ_UINT32_LE (data + 0);
871 guid.v2 = GST_READ_UINT32_LE (data + 4);
872 guid.v3 = GST_READ_UINT32_LE (data + 8);
873 guid.v4 = GST_READ_UINT32_LE (data + 12);
875 object->size = GST_READ_UINT64_LE (data + 16);
877 /* FIXME: make asf_demux_identify_object_guid() */
878 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
879 if (object->id == ASF_OBJ_UNDEFINED && expect) {
880 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
881 guid.v1, guid.v2, guid.v3, guid.v4);
888 gst_asf_demux_release_old_pads (GstASFDemux * demux)
890 GST_DEBUG_OBJECT (demux, "Releasing old pads");
892 while (demux->old_num_streams > 0) {
893 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
894 gst_event_new_eos ());
895 gst_asf_demux_free_stream (demux,
896 &demux->old_stream[demux->old_num_streams - 1]);
897 --demux->old_num_streams;
899 memset (demux->old_stream, 0, sizeof (demux->old_stream));
900 demux->old_num_streams = 0;
904 gst_asf_demux_chain_headers (GstASFDemux * demux)
908 guint8 *header_data, *data = NULL;
909 const guint8 *cdata = NULL;
912 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
916 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
917 if (obj.id != ASF_OBJ_HEADER)
920 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
922 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
923 if (gst_adapter_available (demux->adapter) < obj.size + 50)
926 data = gst_adapter_take (demux->adapter, obj.size + 50);
929 header_size = obj.size;
930 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
931 if (flow != GST_FLOW_OK)
934 /* calculate where the packet data starts */
935 demux->data_offset = obj.size + 50;
937 /* now parse the beginning of the ASF_OBJ_DATA object */
938 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
941 if (demux->num_streams == 0)
950 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
957 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
958 ("This doesn't seem to be an ASF file"));
960 return GST_FLOW_ERROR;
965 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
966 ("header parsing failed, or no streams found, flow = %s",
967 gst_flow_get_name (flow)));
969 return GST_FLOW_ERROR;
974 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
975 GstBuffer ** p_buf, GstFlowReturn * p_flow)
980 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
983 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
985 if (G_LIKELY (p_flow))
988 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
989 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
990 "+%u", gst_flow_get_name (flow), offset, size);
995 g_assert (*p_buf != NULL);
997 buffer_size = gst_buffer_get_size (*p_buf);
998 if (G_UNLIKELY (buffer_size < size)) {
999 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1000 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1001 gst_buffer_unref (*p_buf);
1002 if (G_LIKELY (p_flow))
1003 *p_flow = GST_FLOW_EOS;
1012 gst_asf_demux_pull_indices (GstASFDemux * demux)
1014 GstBuffer *buf = NULL;
1018 offset = demux->index_offset;
1020 if (G_UNLIKELY (offset == 0)) {
1021 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1025 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1031 gst_buffer_map (buf, &map, GST_MAP_READ);
1032 g_assert (map.size >= 16 + 8);
1033 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1034 gst_buffer_unmap (buf, &map);
1035 gst_buffer_replace (&buf, NULL);
1037 /* check for sanity */
1038 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1039 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1043 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1047 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1048 ", size %u", offset, (guint) obj.size);
1050 offset += obj.size; /* increase before _process_object changes it */
1052 gst_buffer_map (buf, &map, GST_MAP_READ);
1053 g_assert (map.size >= obj.size);
1054 bufdata = (guint8 *) map.data;
1055 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1056 gst_buffer_unmap (buf, &map);
1057 gst_buffer_replace (&buf, NULL);
1059 if (G_UNLIKELY (flow != GST_FLOW_OK))
1064 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1068 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1072 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1073 if (obj.id != ASF_OBJ_DATA) {
1074 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1078 demux->state = GST_ASF_DEMUX_STATE_DATA;
1080 if (!demux->broadcast && obj.size > 50) {
1081 demux->data_size = obj.size - 50;
1082 /* CHECKME: for at least one file this is off by +158 bytes?! */
1083 demux->index_offset = demux->data_offset + demux->data_size;
1085 demux->data_size = 0;
1086 demux->index_offset = 0;
1091 if (!demux->broadcast) {
1092 /* skip object header (24 bytes) and file GUID (16 bytes) */
1093 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1095 demux->num_packets = 0;
1098 if (demux->num_packets == 0)
1099 demux->seekable = FALSE;
1101 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1102 if (demux->data_size == 0 && demux->num_packets > 0) {
1103 demux->data_size = demux->num_packets * demux->packet_size;
1104 demux->index_offset = demux->data_offset + demux->data_size;
1107 /* process pending stream objects and create pads for those */
1108 gst_asf_demux_process_queued_extended_stream_objects (demux);
1110 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1111 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1112 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1113 demux->data_offset, demux->data_size, demux->index_offset);
1119 gst_asf_demux_pull_headers (GstASFDemux * demux)
1123 GstBuffer *buf = NULL;
1128 GST_LOG_OBJECT (demux, "reading headers");
1130 /* pull HEADER object header, so we know its size */
1131 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1134 gst_buffer_map (buf, &map, GST_MAP_READ);
1135 g_assert (map.size >= 16 + 8);
1136 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1137 gst_buffer_unmap (buf, &map);
1138 gst_buffer_replace (&buf, NULL);
1140 if (obj.id != ASF_OBJ_HEADER)
1143 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1145 /* pull HEADER object */
1146 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1150 size = obj.size; /* don't want obj.size changed */
1151 gst_buffer_map (buf, &map, GST_MAP_READ);
1152 g_assert (map.size >= size);
1153 bufdata = (guint8 *) map.data;
1154 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1155 gst_buffer_unmap (buf, &map);
1156 gst_buffer_replace (&buf, NULL);
1158 if (flow != GST_FLOW_OK) {
1159 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1163 /* calculate where the packet data starts */
1164 demux->data_offset = demux->base_offset + obj.size + 50;
1166 /* now pull beginning of DATA object before packet data */
1167 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1171 gst_buffer_map (buf, &map, GST_MAP_READ);
1172 g_assert (map.size >= size);
1173 bufdata = (guint8 *) map.data;
1174 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1177 if (demux->num_streams == 0)
1180 gst_buffer_unmap (buf, &map);
1181 gst_buffer_replace (&buf, NULL);
1189 gst_buffer_unmap (buf, &map);
1190 gst_buffer_replace (&buf, NULL);
1192 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1193 ("This doesn't seem to be an ASF file"));
1202 gst_buffer_unmap (buf, &map);
1203 gst_buffer_replace (&buf, NULL);
1204 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1210 all_streams_prerolled (GstASFDemux * demux)
1212 GstClockTime preroll_time;
1213 guint i, num_no_data = 0;
1215 /* Allow at least 500ms of preroll_time */
1216 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1218 /* returns TRUE as long as there isn't a stream which (a) has data queued
1219 * and (b) the timestamp of last piece of data queued is < demux->preroll
1220 * AND there is at least one other stream with data queued */
1221 for (i = 0; i < demux->num_streams; ++i) {
1222 AsfPayload *last_payload = NULL;
1226 stream = &demux->stream[i];
1227 if (G_UNLIKELY (stream->payloads->len == 0)) {
1229 GST_LOG_OBJECT (stream->pad, "no data queued");
1233 /* find last payload with timestamp */
1234 for (last_idx = stream->payloads->len - 1;
1235 last_idx >= 0 && (last_payload == NULL
1236 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1237 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1240 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1241 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1242 GST_TIME_ARGS (preroll_time));
1243 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1244 || last_payload->ts <= preroll_time)) {
1245 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1250 if (G_UNLIKELY (num_no_data > 0))
1258 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1263 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1266 /* check for each mutual exclusion group whether it affects this stream */
1267 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1268 if (*mes == stream->id) {
1269 /* we are in this group; let's check if we've already activated streams
1270 * that are in the same group (and hence mutually exclusive to this
1272 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1275 for (i = 0; i < demux->num_streams; ++i) {
1276 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1277 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1278 "to already active stream with ID %d", stream->id,
1279 demux->stream[i].id);
1284 /* we can only be in this group once, let's break out and move on to
1285 * the next mutual exclusion group */
1296 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1298 /* remember the first queued timestamp for the segment */
1299 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1300 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1301 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1302 GST_TIME_ARGS (demux->first_ts));
1303 demux->segment_ts = payload_ts;
1304 /* always note, but only determines segment when streaming */
1305 if (demux->streaming)
1306 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1307 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1308 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1313 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1315 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1316 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1319 /* go trhough each stream, find smallest timestamp */
1320 for (i = 0; i < demux->num_streams; ++i) {
1323 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1324 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1325 stream = &demux->stream[i];
1327 for (j = 0; j < stream->payloads->len; ++j) {
1328 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1329 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1330 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1331 || stream_min_ts > payload->ts)) {
1332 stream_min_ts = payload->ts;
1334 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1335 payload->ts > stream_min_ts &&
1336 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1337 || stream_min_ts2 > payload->ts)) {
1338 stream_min_ts2 = payload->ts;
1342 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1343 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1344 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1345 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1346 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1348 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1351 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1352 stream_min_ts = stream_min_ts2;
1354 /* if we don't have timestamp for this stream, wait for more data */
1355 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1358 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1359 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1360 first_ts = stream_min_ts;
1363 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1366 demux->first_ts = first_ts;
1368 /* update packets queued before we knew first timestamp */
1369 for (i = 0; i < demux->num_streams; ++i) {
1372 stream = &demux->stream[i];
1374 for (j = 0; j < stream->payloads->len; ++j) {
1375 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1376 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1377 if (payload->ts > first_ts)
1378 payload->ts -= first_ts;
1386 gst_asf_demux_check_segment_ts (demux, 0);
1392 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1394 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1395 and often set wrong, inspecting the data is the only way that seem to be working */
1396 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1397 GstCaps *caps = NULL;
1399 GstAdapter *adapter = gst_adapter_new ();
1401 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1403 AsfPayload *payload;
1406 payload = &g_array_index (stream->payloads, AsfPayload, i);
1407 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1408 len = gst_adapter_available (adapter);
1409 data = gst_adapter_map (adapter, len);
1413 #define MIN_LENGTH 128
1415 /* look for the sync points */
1417 if (len < MIN_LENGTH || /* give typefind something to work on */
1418 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1419 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1425 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1428 if (prob < GST_TYPE_FIND_LIKELY) {
1431 if (len > MIN_LENGTH)
1432 /* this wasn't it, look for another sync point */
1436 gst_adapter_unmap (adapter);
1439 gst_object_unref (adapter);
1442 gst_caps_take (&stream->caps, caps);
1450 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1454 if (demux->activated_streams)
1457 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1460 if (!all_streams_prerolled (demux) && !force) {
1461 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1465 for (i = 0; i < demux->num_streams; ++i) {
1466 AsfStream *stream = &demux->stream[i];
1468 if (stream->payloads->len > 0) {
1470 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1471 !stream->active && /* do not inspect active streams (caps were already set) */
1472 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1473 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1474 /* try to gather some more data */
1477 /* we don't check mutual exclusion stuff here; either we have data for
1478 * a stream, then we active it, or we don't, then we'll ignore it */
1479 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1480 gst_asf_demux_activate_stream (demux, stream);
1482 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1486 gst_asf_demux_release_old_pads (demux);
1488 demux->activated_streams = TRUE;
1489 GST_LOG_OBJECT (demux, "signalling no more pads");
1490 gst_element_no_more_pads (GST_ELEMENT (demux));
1494 /* returns the stream that has a complete payload with the lowest timestamp
1495 * queued, or NULL (we push things by timestamp because during the internal
1496 * prerolling we might accumulate more data then the external queues can take,
1497 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1499 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1501 AsfPayload *best_payload = NULL;
1502 AsfStream *best_stream = NULL;
1505 for (i = 0; i < demux->num_streams; ++i) {
1509 stream = &demux->stream[i];
1511 /* Don't push any data until we have at least one payload that falls within
1512 * the current segment. This way we can remove out-of-segment payloads that
1513 * don't need to be decoded after a seek, sending only data from the
1514 * keyframe directly before our segment start */
1515 if (stream->payloads->len > 0) {
1516 AsfPayload *payload = NULL;
1519 /* find last payload with timestamp */
1520 for (last_idx = stream->payloads->len - 1;
1521 last_idx >= 0 && (payload == NULL
1522 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1523 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1526 /* if this is first payload after seek we might need to update the segment */
1527 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1528 gst_asf_demux_check_segment_ts (demux, payload->ts);
1530 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1531 (payload->ts < demux->segment.start))) {
1532 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1533 GST_DEBUG_OBJECT (stream->pad,
1534 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1535 GST_TIME_ARGS (payload->ts));
1536 demux->segment.start = payload->ts;
1537 demux->segment.time = payload->ts;
1539 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1540 GST_TIME_FORMAT " which is before our segment start %"
1541 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1542 GST_TIME_ARGS (demux->segment.start));
1547 /* Now see if there's a complete payload queued for this stream */
1550 /* find first complete payload with timestamp */
1552 j < stream->payloads->len && (payload == NULL
1553 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1554 payload = &g_array_index (stream->payloads, AsfPayload, j);
1557 if (!gst_asf_payload_is_complete (payload))
1560 /* ... and whether its timestamp is lower than the current best */
1561 if (best_stream == NULL || best_payload->ts > payload->ts) {
1562 best_stream = stream;
1563 best_payload = payload;
1571 static GstFlowReturn
1572 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1575 GstFlowReturn ret = GST_FLOW_OK;
1577 if (G_UNLIKELY (!demux->activated_streams)) {
1578 if (!gst_asf_demux_check_activate_streams (demux, force))
1580 /* streams are now activated */
1583 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1584 AsfPayload *payload;
1586 /* wait until we had a chance to "lock on" some payload's timestamp */
1587 if (G_UNLIKELY (demux->need_newsegment
1588 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1591 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1593 /* do we need to send a newsegment event */
1594 if ((G_UNLIKELY (demux->need_newsegment))) {
1595 GstEvent *segment_event;
1597 /* safe default if insufficient upstream info */
1598 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1601 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1602 demux->segment.duration > 0) {
1603 /* slight HACK; prevent clipping of last bit */
1604 demux->segment.stop = demux->segment.duration + demux->in_gap;
1607 /* FIXME : only if ACCURATE ! */
1608 if (G_LIKELY (!demux->accurate
1609 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1610 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1611 GST_TIME_ARGS (payload->ts));
1612 demux->segment.start = payload->ts;
1613 demux->segment.time = payload->ts;
1616 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1619 /* note: we fix up all timestamps to start from 0, so this should be ok */
1620 segment_event = gst_event_new_segment (&demux->segment);
1621 if (demux->segment_seqnum)
1622 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1623 gst_asf_demux_send_event_unlocked (demux, segment_event);
1625 /* now post any global tags we may have found */
1626 if (demux->taglist == NULL) {
1627 demux->taglist = gst_tag_list_new_empty ();
1628 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1631 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1632 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1634 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1635 gst_asf_demux_send_event_unlocked (demux,
1636 gst_event_new_tag (demux->taglist));
1637 demux->taglist = NULL;
1639 demux->need_newsegment = FALSE;
1640 demux->segment_seqnum = 0;
1641 demux->segment_running = TRUE;
1644 /* Do we have tags pending for this stream? */
1645 if (G_UNLIKELY (stream->pending_tags)) {
1646 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1647 gst_pad_push_event (stream->pad,
1648 gst_event_new_tag (stream->pending_tags));
1649 stream->pending_tags = NULL;
1652 /* We have the whole packet now so we should push the packet to
1653 * the src pad now. First though we should check if we need to do
1655 if (G_UNLIKELY (stream->span > 1)) {
1656 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1659 payload->buf = gst_buffer_make_writable (payload->buf);
1661 if (G_LIKELY (!payload->keyframe)) {
1662 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1665 if (G_UNLIKELY (stream->discont)) {
1666 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1667 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1668 stream->discont = FALSE;
1671 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1672 (payload->par_x != stream->par_x) &&
1673 (payload->par_y != stream->par_y))) {
1674 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1675 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1676 stream->par_x = payload->par_x;
1677 stream->par_y = payload->par_y;
1678 stream->caps = gst_caps_make_writable (stream->caps);
1679 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1680 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1681 gst_pad_set_caps (stream->pad, stream->caps);
1684 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1685 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1686 payload->interlaced);
1687 stream->interlaced = payload->interlaced;
1688 stream->caps = gst_caps_make_writable (stream->caps);
1689 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1690 (stream->interlaced ? "mixed" : "progressive"), NULL);
1691 gst_pad_set_caps (stream->pad, stream->caps);
1694 /* (sort of) interpolate timestamps using upstream "frame of reference",
1695 * typically useful for live src, but might (unavoidably) mess with
1696 * position reporting if a live src is playing not so live content
1697 * (e.g. rtspsrc taking some time to fall back to tcp) */
1698 GST_BUFFER_PTS (payload->buf) = payload->ts;
1699 if (GST_BUFFER_PTS_IS_VALID (payload->buf)) {
1700 GST_BUFFER_PTS (payload->buf) += demux->in_gap;
1702 if (payload->duration == GST_CLOCK_TIME_NONE
1703 && stream->ext_props.avg_time_per_frame != 0)
1704 GST_BUFFER_DURATION (payload->buf) =
1705 stream->ext_props.avg_time_per_frame * 100;
1707 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1709 /* FIXME: we should really set durations on buffers if we can */
1711 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1714 if (stream->active) {
1715 if (G_UNLIKELY (stream->first_buffer)) {
1716 if (stream->streamheader != NULL) {
1717 GST_DEBUG_OBJECT (stream->pad,
1718 "Pushing streamheader before first buffer");
1719 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1721 stream->first_buffer = FALSE;
1724 ret = gst_pad_push (stream->pad, payload->buf);
1725 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
1727 gst_buffer_unref (payload->buf);
1730 payload->buf = NULL;
1731 g_array_remove_index (stream->payloads, 0);
1733 /* Break out as soon as we have an issue */
1734 if (G_UNLIKELY (ret != GST_FLOW_OK))
1742 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1746 g_assert (buf != NULL);
1748 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1750 gst_buffer_map (buf, &map, GST_MAP_READ);
1752 /* we return false on buffer too small */
1753 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1754 gst_buffer_unmap (buf, &map);
1758 /* check if it is a header */
1759 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1760 gst_buffer_unmap (buf, &map);
1761 if (obj.id == ASF_OBJ_HEADER) {
1768 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1770 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1771 GstFlowReturn ret = GST_FLOW_OK;
1772 GstBuffer *buf = NULL;
1773 gboolean header = FALSE;
1775 /* TODO maybe we should skip index objects after the data and look
1776 * further for a new header */
1777 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1778 g_assert (buf != NULL);
1779 /* check if it is a header */
1780 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1781 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1782 demux->base_offset = off;
1786 gst_buffer_unref (buf);
1793 gst_asf_demux_loop (GstASFDemux * demux)
1795 GstFlowReturn flow = GST_FLOW_OK;
1796 GstBuffer *buf = NULL;
1798 gboolean sent_eos = FALSE;
1800 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1801 if (!gst_asf_demux_pull_headers (demux)) {
1802 flow = GST_FLOW_ERROR;
1806 gst_asf_demux_pull_indices (demux);
1809 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1811 if (G_UNLIKELY (demux->num_packets != 0
1812 && demux->packet >= demux->num_packets))
1815 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1816 (guint) demux->num_packets);
1818 off = demux->data_offset + (demux->packet * demux->packet_size);
1820 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1821 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1822 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1823 if (flow == GST_FLOW_EOS)
1825 else if (flow == GST_FLOW_FLUSHING) {
1826 GST_DEBUG_OBJECT (demux, "Not fatal");
1832 if (G_LIKELY (demux->speed_packets == 1)) {
1833 GstAsfDemuxParsePacketError err;
1834 err = gst_asf_demux_parse_packet (demux, buf);
1835 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1836 /* when we don't know when the data object ends, we should check
1837 * for a chained asf */
1838 if (demux->num_packets == 0) {
1839 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1840 GST_INFO_OBJECT (demux, "Chained asf found");
1841 demux->base_offset = off;
1842 gst_asf_demux_reset (demux, TRUE);
1843 gst_buffer_unref (buf);
1847 /* FIXME: We should tally up fatal errors and error out only
1848 * after a few broken packets in a row? */
1850 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1851 gst_buffer_unref (buf);
1856 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1862 for (n = 0; n < demux->speed_packets; n++) {
1864 GstAsfDemuxParsePacketError err;
1867 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1868 n * demux->packet_size, demux->packet_size);
1869 err = gst_asf_demux_parse_packet (demux, sub);
1870 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1871 /* when we don't know when the data object ends, we should check
1872 * for a chained asf */
1873 if (demux->num_packets == 0) {
1874 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1875 GST_INFO_OBJECT (demux, "Chained asf found");
1876 demux->base_offset = off + n * demux->packet_size;
1877 gst_asf_demux_reset (demux, TRUE);
1878 gst_buffer_unref (sub);
1879 gst_buffer_unref (buf);
1883 /* FIXME: We should tally up fatal errors and error out only
1884 * after a few broken packets in a row? */
1886 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1890 gst_buffer_unref (sub);
1892 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1893 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1899 /* reset speed pull */
1900 demux->speed_packets = 1;
1903 gst_buffer_unref (buf);
1905 if (G_UNLIKELY (demux->num_packets > 0
1906 && demux->packet >= demux->num_packets)) {
1907 GST_LOG_OBJECT (demux, "reached EOS");
1911 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1912 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1916 /* check if we're at the end of the configured segment */
1917 /* FIXME: check if segment end reached etc. */
1923 /* if we haven't activated our streams yet, this might be because we have
1924 * less data queued than required for preroll; force stream activation and
1925 * send any pending payloads before sending EOS */
1926 if (!demux->activated_streams)
1927 gst_asf_demux_push_complete_payloads (demux, TRUE);
1929 /* we want to push an eos or post a segment-done in any case */
1930 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1933 /* for segment playback we need to post when (in stream time)
1934 * we stopped, this is either stop (when set) or the duration. */
1935 if ((stop = demux->segment.stop) == -1)
1936 stop = demux->segment.duration;
1938 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1939 gst_element_post_message (GST_ELEMENT_CAST (demux),
1940 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1942 gst_asf_demux_send_event_unlocked (demux,
1943 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1944 } else if (flow != GST_FLOW_EOS) {
1945 /* check if we have a chained asf, in case, we don't eos yet */
1946 if (gst_asf_demux_check_chained_asf (demux)) {
1947 GST_INFO_OBJECT (demux, "Chained ASF starting");
1948 gst_asf_demux_reset (demux, TRUE);
1952 /* normal playback, send EOS to all linked pads */
1953 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1954 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1956 /* ... and fall through to pause */
1960 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1961 gst_flow_get_name (flow));
1962 demux->segment_running = FALSE;
1963 gst_pad_pause_task (demux->sinkpad);
1965 /* For the error cases (not EOS) */
1967 if (flow == GST_FLOW_EOS)
1968 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1969 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1970 /* Post an error. Hopefully something else already has, but if not... */
1971 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1972 (_("Internal data stream error.")),
1973 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1982 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1983 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1984 flow = GST_FLOW_EOS;
1988 /* See FIXMEs above */
1991 gst_buffer_unref (buf);
1992 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1993 ("Error parsing ASF packet %u", (guint) demux->packet));
1994 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1995 flow = GST_FLOW_ERROR;
2001 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2002 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2003 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2006 gst_asf_demux_check_header (GstASFDemux * demux)
2009 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2010 ASF_OBJECT_HEADER_SIZE);
2011 if (cdata == NULL) /* need more data */
2012 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2014 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2015 if (obj.id != ASF_OBJ_HEADER) {
2016 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2018 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2022 static GstFlowReturn
2023 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2025 GstFlowReturn ret = GST_FLOW_OK;
2028 demux = GST_ASF_DEMUX (parent);
2030 GST_LOG_OBJECT (demux,
2031 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2032 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2033 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2035 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2036 GST_DEBUG_OBJECT (demux, "received DISCONT");
2037 gst_asf_demux_mark_discont (demux);
2040 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2041 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2042 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2043 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2044 ", interpolation gap: %" GST_TIME_FORMAT,
2045 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2048 gst_adapter_push (demux->adapter, buf);
2050 switch (demux->state) {
2051 case GST_ASF_DEMUX_STATE_INDEX:{
2052 gint result = gst_asf_demux_check_header (demux);
2053 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2056 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2057 /* we don't care about this, probably an index */
2058 /* TODO maybe would be smarter to skip all the indices
2059 * until we got a new header or EOS to decide */
2060 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2063 GST_INFO_OBJECT (demux, "Chained asf starting");
2064 /* cleanup and get ready for a chained asf */
2065 gst_asf_demux_reset (demux, TRUE);
2069 case GST_ASF_DEMUX_STATE_HEADER:{
2070 ret = gst_asf_demux_chain_headers (demux);
2071 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2073 /* otherwise fall through */
2075 case GST_ASF_DEMUX_STATE_DATA:
2079 data_size = demux->packet_size;
2081 while (gst_adapter_available (demux->adapter) >= data_size) {
2083 GstAsfDemuxParsePacketError err;
2085 /* we don't know the length of the stream
2086 * check for a chained asf everytime */
2087 if (demux->num_packets == 0) {
2088 gint result = gst_asf_demux_check_header (demux);
2090 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2091 GST_INFO_OBJECT (demux, "Chained asf starting");
2092 /* cleanup and get ready for a chained asf */
2093 gst_asf_demux_reset (demux, TRUE);
2096 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2097 && demux->packet >= demux->num_packets)) {
2098 /* do not overshoot data section when streaming */
2102 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2104 /* FIXME: We should tally up fatal errors and error out only
2105 * after a few broken packets in a row? */
2106 err = gst_asf_demux_parse_packet (demux, buf);
2108 gst_buffer_unref (buf);
2110 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2111 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2113 GST_WARNING_OBJECT (demux, "Parse error");
2115 if (demux->packet >= 0)
2118 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2119 && demux->packet >= demux->num_packets)) {
2120 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2125 g_assert_not_reached ();
2129 if (ret != GST_FLOW_OK)
2130 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2136 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2142 static inline gboolean
2143 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2145 if (*p_size < num_bytes)
2148 *p_data += num_bytes;
2149 *p_size -= num_bytes;
2153 static inline guint8
2154 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2158 g_assert (*p_size >= 1);
2159 ret = GST_READ_UINT8 (*p_data);
2160 *p_data += sizeof (guint8);
2161 *p_size -= sizeof (guint8);
2165 static inline guint16
2166 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2170 g_assert (*p_size >= 2);
2171 ret = GST_READ_UINT16_LE (*p_data);
2172 *p_data += sizeof (guint16);
2173 *p_size -= sizeof (guint16);
2177 static inline guint32
2178 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2182 g_assert (*p_size >= 4);
2183 ret = GST_READ_UINT32_LE (*p_data);
2184 *p_data += sizeof (guint32);
2185 *p_size -= sizeof (guint32);
2189 static inline guint64
2190 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2194 g_assert (*p_size >= 8);
2195 ret = GST_READ_UINT64_LE (*p_data);
2196 *p_data += sizeof (guint64);
2197 *p_size -= sizeof (guint64);
2202 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2203 guint8 ** p_data, guint64 * p_size)
2207 if (*p_size < num_bytes_to_read)
2210 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2211 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2213 *p_data += num_bytes_to_read;
2214 *p_size -= num_bytes_to_read;
2220 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2221 guint8 ** p_data, guint64 * p_size)
2225 if (*p_size < num_bytes_to_read)
2228 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2229 *p_data += num_bytes_to_read;
2230 *p_size -= num_bytes_to_read;
2235 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2236 guint8 ** p_data, guint64 * p_size)
2246 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2249 *p_strlen = s_length;
2251 if (s_length == 0) {
2252 GST_WARNING ("zero-length string");
2253 *p_str = g_strdup ("");
2257 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2260 g_assert (s != NULL);
2262 /* just because They don't exist doesn't
2263 * mean They are not out to get you ... */
2264 if (s[s_length - 1] != '\0') {
2265 s = g_realloc (s, s_length + 1);
2269 *p_str = (gchar *) s;
2275 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2277 g_assert (*p_size >= 4 * sizeof (guint32));
2279 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2280 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2281 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2282 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2286 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2289 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2292 /* WAVEFORMATEX Structure */
2293 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2294 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2295 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2296 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2297 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2298 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2299 /* Codec specific data size */
2300 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2305 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2308 if (*p_size < (4 + 4 + 1 + 2))
2311 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2312 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2313 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2314 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2319 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2320 guint8 ** p_data, guint64 * p_size)
2322 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2325 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2326 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2327 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2328 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2329 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2330 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2331 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2332 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2333 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2334 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2335 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2340 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2344 for (i = 0; i < demux->num_streams; i++) {
2345 if (demux->stream[i].id == id)
2346 return &demux->stream[i];
2349 if (gst_asf_demux_is_unknown_stream (demux, id))
2350 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2355 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2356 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2361 gst_pad_use_fixed_caps (src_pad);
2362 gst_pad_set_caps (src_pad, caps);
2364 gst_pad_set_event_function (src_pad,
2365 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2366 gst_pad_set_query_function (src_pad,
2367 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2369 stream = &demux->stream[demux->num_streams];
2370 stream->caps = caps;
2371 stream->pad = src_pad;
2373 stream->fps_known = !is_video; /* bit hacky for audio */
2374 stream->is_video = is_video;
2375 stream->pending_tags = tags;
2376 stream->discont = TRUE;
2377 stream->first_buffer = TRUE;
2378 stream->streamheader = streamheader;
2379 if (stream->streamheader) {
2380 stream->streamheader = gst_buffer_make_writable (streamheader);
2381 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2386 st = gst_caps_get_structure (caps, 0);
2387 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2388 par_x > 0 && par_y > 0) {
2389 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2390 stream->par_x = par_x;
2391 stream->par_y = par_y;
2395 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2397 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2398 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2400 ++demux->num_streams;
2402 stream->active = FALSE;
2408 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2409 GstBuffer * buffer, GstStructure * structure)
2411 GValue arr_val = G_VALUE_INIT;
2412 GValue buf_val = G_VALUE_INIT;
2414 g_value_init (&arr_val, GST_TYPE_ARRAY);
2415 g_value_init (&buf_val, GST_TYPE_BUFFER);
2417 gst_value_set_buffer (&buf_val, buffer);
2418 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2420 gst_structure_take_value (structure, "streamheader", &arr_val);
2424 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2425 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2427 GstTagList *tags = NULL;
2428 GstBuffer *extradata = NULL;
2431 guint16 size_left = 0;
2432 gchar *codec_name = NULL;
2435 size_left = audio->size;
2437 /* Create the audio pad */
2438 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2440 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2443 /* Swallow up any left over data and set up the
2444 * standard properties from the header info */
2446 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2447 "codec specific data", size_left);
2449 g_assert (size_left <= *p_size);
2450 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2453 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2454 * additional two bytes indicating extradata. */
2455 /* FIXME: Handle the channel reorder map here */
2456 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2457 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2460 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2461 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2464 /* Informing about that audio format we just added */
2466 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2467 g_free (codec_name);
2471 gst_buffer_unref (extradata);
2473 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2474 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2475 audio->codec_tag, tags);
2477 ++demux->num_audio_streams;
2479 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2483 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2484 asf_stream_video_format * video, guint16 id,
2485 guint8 ** p_data, guint64 * p_size)
2487 GstTagList *tags = NULL;
2488 GstStructure *caps_s;
2489 GstBuffer *extradata = NULL;
2494 gchar *codec_name = NULL;
2495 gint size_left = video->size - 40;
2496 GstBuffer *streamheader = NULL;
2498 /* Create the video pad */
2499 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2500 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2503 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2505 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2506 g_assert (size_left <= *p_size);
2507 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2510 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2512 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2513 caps = gst_riff_create_video_caps (video->tag, NULL,
2514 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2517 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2518 G_TYPE_UINT, video->tag, NULL);
2523 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2524 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2525 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2526 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2531 /* retry with the global metadata */
2532 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2533 demux->global_metadata);
2534 s = demux->global_metadata;
2535 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2536 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2537 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2538 if (ax > 0 && ay > 0)
2539 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2543 s = gst_caps_get_structure (caps, 0);
2544 gst_structure_remove_field (s, "framerate");
2547 caps_s = gst_caps_get_structure (caps, 0);
2549 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2550 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2551 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2552 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2555 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2556 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2557 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2558 GstBuffer *buf = gst_value_get_buffer (value);
2561 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2562 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2563 /* this looks like a bytestream start */
2564 streamheader = gst_buffer_ref (buf);
2565 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2566 gst_structure_remove_field (caps_s, "codec_data");
2569 gst_buffer_unmap (buf, &mapinfo);
2574 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2575 g_free (codec_name);
2579 gst_buffer_unref (extradata);
2581 GST_INFO ("Adding video stream #%u, id %u, codec %"
2582 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2583 GST_FOURCC_ARGS (video->tag), video->tag);
2585 ++demux->num_video_streams;
2587 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2588 streamheader, tags);
2592 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2594 if (!stream->active) {
2598 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2599 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2600 gst_pad_set_active (stream->pad, TRUE);
2603 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2604 "%03u", stream->id);
2607 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2609 if (gst_event_parse_group_id (event, &demux->group_id))
2610 demux->have_group_id = TRUE;
2612 demux->have_group_id = FALSE;
2613 gst_event_unref (event);
2614 } else if (!demux->have_group_id) {
2615 demux->have_group_id = TRUE;
2616 demux->group_id = gst_util_group_id_next ();
2619 event = gst_event_new_stream_start (stream_id);
2620 if (demux->have_group_id)
2621 gst_event_set_group_id (event, demux->group_id);
2623 gst_pad_push_event (stream->pad, event);
2625 gst_pad_set_caps (stream->pad, stream->caps);
2627 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2628 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2629 stream->active = TRUE;
2634 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2637 AsfCorrectionType correction_type;
2638 AsfStreamType stream_type;
2639 GstClockTime time_offset;
2640 gboolean is_encrypted G_GNUC_UNUSED;
2644 guint stream_specific_size;
2645 guint type_specific_size G_GNUC_UNUSED;
2646 guint unknown G_GNUC_UNUSED;
2647 gboolean inspect_payload = FALSE;
2648 AsfStream *stream = NULL;
2650 /* Get the rest of the header's header */
2651 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2652 goto not_enough_data;
2654 gst_asf_demux_get_guid (&guid, &data, &size);
2655 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2657 gst_asf_demux_get_guid (&guid, &data, &size);
2658 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2660 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2662 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2663 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2665 flags = gst_asf_demux_get_uint16 (&data, &size);
2666 stream_id = flags & 0x7f;
2667 is_encrypted = ! !((flags & 0x8000) << 15);
2668 unknown = gst_asf_demux_get_uint32 (&data, &size);
2670 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2671 stream_id, GST_TIME_ARGS (time_offset));
2673 /* dvr-ms has audio stream declared in stream specific data */
2674 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2675 AsfExtStreamType ext_stream_type;
2676 gst_asf_demux_get_guid (&guid, &data, &size);
2677 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2679 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2680 inspect_payload = TRUE;
2682 gst_asf_demux_get_guid (&guid, &data, &size);
2683 gst_asf_demux_get_uint32 (&data, &size);
2684 gst_asf_demux_get_uint32 (&data, &size);
2685 gst_asf_demux_get_uint32 (&data, &size);
2686 gst_asf_demux_get_guid (&guid, &data, &size);
2687 gst_asf_demux_get_uint32 (&data, &size);
2688 stream_type = ASF_STREAM_AUDIO;
2692 switch (stream_type) {
2693 case ASF_STREAM_AUDIO:{
2694 asf_stream_audio audio_object;
2696 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2697 goto not_enough_data;
2699 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2702 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2705 switch (correction_type) {
2706 case ASF_CORRECTION_ON:{
2707 guint span, packet_size, chunk_size, data_size, silence_data;
2709 GST_INFO ("Using error correction");
2711 if (size < (1 + 2 + 2 + 2 + 1))
2712 goto not_enough_data;
2714 span = gst_asf_demux_get_uint8 (&data, &size);
2715 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2716 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2717 data_size = gst_asf_demux_get_uint16 (&data, &size);
2718 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2720 stream->span = span;
2722 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2723 packet_size, chunk_size, data_size, span, silence_data);
2725 if (stream->span > 1) {
2726 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2727 /* Disable descrambling */
2730 /* FIXME: this else branch was added for
2731 * weird_al_yankovic - the saga begins.asf */
2732 stream->ds_packet_size = packet_size;
2733 stream->ds_chunk_size = chunk_size;
2736 /* Descambling is enabled */
2737 stream->ds_packet_size = packet_size;
2738 stream->ds_chunk_size = chunk_size;
2741 /* Now skip the rest of the silence data */
2743 gst_bytestream_flush (demux->bs, data_size - 1);
2745 /* FIXME: CHECKME. And why -1? */
2746 if (data_size > 1) {
2747 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2748 goto not_enough_data;
2754 case ASF_CORRECTION_OFF:{
2755 GST_INFO ("Error correction off");
2756 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2757 goto not_enough_data;
2761 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2762 ("Audio stream using unknown error correction"));
2769 case ASF_STREAM_VIDEO:{
2770 asf_stream_video_format video_format_object;
2771 asf_stream_video video_object;
2774 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2775 goto not_enough_data;
2777 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2779 GST_INFO ("object is a video stream with %u bytes of "
2780 "additional data", vsize);
2782 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2784 goto not_enough_data;
2787 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
2788 stream_id, &data, &size);
2794 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2796 demux->other_streams =
2797 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
2802 stream->inspect_payload = inspect_payload;
2807 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2808 /* we'll error out later if we found no streams */
2813 static const gchar *
2814 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2818 const gchar *asf_name;
2819 const gchar *gst_name;
2822 "WM/Genre", GST_TAG_GENRE}, {
2823 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2824 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2825 "WM/Picture", GST_TAG_IMAGE}, {
2826 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2827 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2828 "WM/Year", GST_TAG_DATE_TIME}
2829 /* { "WM/Composer", GST_TAG_COMPOSER } */
2834 if (name_utf8 == NULL) {
2835 GST_WARNING ("Failed to convert name to UTF8, skipping");
2839 out = strlen (name_utf8);
2841 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2842 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2843 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2844 return tags[i].gst_name;
2851 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2853 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2857 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2859 if (taglist == NULL)
2862 if (gst_tag_list_is_empty (taglist)) {
2863 gst_tag_list_unref (taglist);
2867 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2868 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
2870 gst_tag_list_unref (demux->taglist);
2871 gst_tag_list_unref (taglist);
2873 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2876 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2877 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2878 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2881 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2885 const guint8 *img_data = NULL;
2886 guint32 img_data_len = 0;
2887 guint8 pic_type = 0;
2889 gst_byte_reader_init (&r, tag_data, tag_data_len);
2891 /* skip mime type string (we don't trust it and do our own typefinding),
2892 * and also skip the description string, since we don't use it */
2893 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2894 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2895 !gst_byte_reader_skip_string_utf16 (&r) ||
2896 !gst_byte_reader_skip_string_utf16 (&r) ||
2897 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2898 goto not_enough_data;
2902 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2903 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2909 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2910 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2915 /* Extended Content Description Object */
2916 static GstFlowReturn
2917 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2920 /* Other known (and unused) 'text/unicode' metadata available :
2923 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2924 * WMFSDKVersion = 9.00.00.2980
2925 * WMFSDKNeeded = 0.0.0.0000
2926 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2927 * WM/Publisher = 4AD
2929 * WM/ProviderRating = 8
2930 * WM/ProviderStyle = Rock (similar to WM/Genre)
2931 * WM/GenreID (similar to WM/Genre)
2932 * WM/TrackNumber (same as WM/Track but as a string)
2934 * Other known (and unused) 'non-text' metadata available :
2940 * We might want to read WM/TrackNumber and use atoi() if we don't have
2944 GstTagList *taglist;
2945 guint16 blockcount, i;
2947 GST_INFO_OBJECT (demux, "object is an extended content description");
2949 taglist = gst_tag_list_new_empty ();
2951 /* Content Descriptor Count */
2953 goto not_enough_data;
2955 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2957 for (i = 1; i <= blockcount; ++i) {
2958 const gchar *gst_tag_name;
2962 GValue tag_value = { 0, };
2965 gchar *name_utf8 = NULL;
2969 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2970 goto not_enough_data;
2974 goto not_enough_data;
2976 /* Descriptor Value Data Type */
2977 datatype = gst_asf_demux_get_uint16 (&data, &size);
2979 /* Descriptor Value (not really a string, but same thing reading-wise) */
2980 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2982 goto not_enough_data;
2986 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2988 if (name_utf8 != NULL) {
2989 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2991 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2992 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2995 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2998 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3001 /* get rid of tags with empty value */
3002 if (value_utf8 != NULL && *value_utf8 != '\0') {
3003 GST_DEBUG ("string value %s", value_utf8);
3005 value_utf8[out] = '\0';
3007 if (gst_tag_name != NULL) {
3008 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3009 guint year = atoi (value_utf8);
3012 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3013 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3015 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3016 guint id3v1_genre_id;
3017 const gchar *genre_str;
3019 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3020 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3021 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3022 g_free (value_utf8);
3023 value_utf8 = g_strdup (genre_str);
3028 /* convert tag from string to other type if required */
3029 tag_type = gst_tag_get_type (gst_tag_name);
3030 g_value_init (&tag_value, tag_type);
3031 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3032 GValue from_val = { 0, };
3034 g_value_init (&from_val, G_TYPE_STRING);
3035 g_value_set_string (&from_val, value_utf8);
3036 if (!g_value_transform (&from_val, &tag_value)) {
3037 GST_WARNING_OBJECT (demux,
3038 "Could not transform string tag to " "%s tag type %s",
3039 gst_tag_name, g_type_name (tag_type));
3040 g_value_unset (&tag_value);
3042 g_value_unset (&from_val);
3047 GST_DEBUG ("Setting metadata");
3048 g_value_init (&tag_value, G_TYPE_STRING);
3049 g_value_set_string (&tag_value, value_utf8);
3051 } else if (value_utf8 == NULL) {
3052 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3054 GST_DEBUG ("Skipping empty string value for %s",
3055 GST_STR_NULL (gst_tag_name));
3057 g_free (value_utf8);
3060 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3062 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3063 GST_FIXME ("Unhandled byte array tag %s",
3064 GST_STR_NULL (gst_tag_name));
3067 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3073 case ASF_DEMUX_DATA_TYPE_DWORD:{
3074 guint uint_val = GST_READ_UINT32_LE (value);
3076 /* this is the track number */
3077 g_value_init (&tag_value, G_TYPE_UINT);
3079 /* WM/Track counts from 0 */
3080 if (!strcmp (name_utf8, "WM/Track"))
3083 g_value_set_uint (&tag_value, uint_val);
3087 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3092 if (G_IS_VALUE (&tag_value)) {
3094 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3096 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3097 * is supposed to have a 0 base but is often wrongly written to start
3098 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3099 * replace the value added earlier from WM/Track or put it first in
3100 * the list, so that it will get picked up by _get_uint() */
3101 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3102 merge_mode = GST_TAG_MERGE_REPLACE;
3104 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3107 GST_DEBUG ("Setting global metadata %s", name_utf8);
3108 gst_structure_set_value (demux->global_metadata, name_utf8,
3112 g_value_unset (&tag_value);
3121 gst_asf_demux_add_global_tags (demux, taglist);
3128 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3129 gst_tag_list_unref (taglist);
3130 return GST_FLOW_OK; /* not really fatal */
3134 static GstStructure *
3135 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3140 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3142 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3145 s = gst_caps_get_structure (demux->metadata, i);
3146 if (gst_structure_has_name (s, sname))
3150 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3152 /* try lookup again; demux->metadata took ownership of the structure, so we
3153 * can't really make any assumptions about what happened to it, so we can't
3154 * just return it directly after appending it */
3155 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3158 static GstFlowReturn
3159 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3162 guint16 blockcount, i;
3164 GST_INFO_OBJECT (demux, "object is a metadata object");
3166 /* Content Descriptor Count */
3168 goto not_enough_data;
3170 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3172 for (i = 0; i < blockcount; ++i) {
3174 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3175 guint32 data_len, ival;
3178 if (size < (2 + 2 + 2 + 2 + 4))
3179 goto not_enough_data;
3181 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3182 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3183 name_len = gst_asf_demux_get_uint16 (&data, &size);
3184 data_type = gst_asf_demux_get_uint16 (&data, &size);
3185 data_len = gst_asf_demux_get_uint32 (&data, &size);
3187 if (size < name_len + data_len)
3188 goto not_enough_data;
3190 /* convert name to UTF-8 */
3191 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3193 gst_asf_demux_skip_bytes (name_len, &data, &size);
3195 if (name_utf8 == NULL) {
3196 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3197 gst_asf_demux_skip_bytes (data_len, &data, &size);
3201 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3202 gst_asf_demux_skip_bytes (data_len, &data, &size);
3210 goto not_enough_data;
3213 ival = gst_asf_demux_get_uint32 (&data, &size);
3215 /* skip anything else there may be, just in case */
3216 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3218 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3219 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3223 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3229 GST_WARNING ("Unexpected end of data parsing metadata object");
3230 return GST_FLOW_OK; /* not really fatal */
3234 static GstFlowReturn
3235 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3237 GstFlowReturn ret = GST_FLOW_OK;
3238 guint32 i, num_objects;
3239 guint8 unknown G_GNUC_UNUSED;
3241 /* Get the rest of the header's header */
3242 if (size < (4 + 1 + 1))
3243 goto not_enough_data;
3245 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3246 unknown = gst_asf_demux_get_uint8 (&data, &size);
3247 unknown = gst_asf_demux_get_uint8 (&data, &size);
3249 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3251 /* Loop through the header's objects, processing those */
3252 for (i = 0; i < num_objects; ++i) {
3253 GST_INFO_OBJECT (demux, "reading header part %u", i);
3254 ret = gst_asf_demux_process_object (demux, &data, &size);
3255 if (ret != GST_FLOW_OK) {
3256 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3265 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3266 ("short read parsing HEADER object"));
3267 return GST_FLOW_ERROR;
3271 static GstFlowReturn
3272 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3274 guint64 creation_time G_GNUC_UNUSED;
3275 guint64 file_size G_GNUC_UNUSED;
3276 guint64 send_time G_GNUC_UNUSED;
3277 guint64 packets_count, play_time, preroll;
3278 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3280 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3281 goto not_enough_data;
3283 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3284 file_size = gst_asf_demux_get_uint64 (&data, &size);
3285 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3286 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3287 play_time = gst_asf_demux_get_uint64 (&data, &size);
3288 send_time = gst_asf_demux_get_uint64 (&data, &size);
3289 preroll = gst_asf_demux_get_uint64 (&data, &size);
3290 flags = gst_asf_demux_get_uint32 (&data, &size);
3291 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3292 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3293 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3295 demux->broadcast = ! !(flags & 0x01);
3296 demux->seekable = ! !(flags & 0x02);
3298 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3299 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3300 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3302 if (demux->broadcast) {
3303 /* these fields are invalid if the broadcast flag is set */
3308 if (min_pktsize != max_pktsize)
3309 goto non_fixed_packet_size;
3311 demux->packet_size = max_pktsize;
3313 /* FIXME: do we need send_time as well? what is it? */
3314 if ((play_time * 100) >= (preroll * GST_MSECOND))
3315 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3317 demux->play_time = 0;
3319 demux->preroll = preroll * GST_MSECOND;
3321 /* initial latency */
3322 demux->latency = demux->preroll;
3324 if (demux->play_time == 0)
3325 demux->seekable = FALSE;
3327 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3328 GST_TIME_ARGS (demux->play_time));
3329 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3330 GST_TIME_ARGS (demux->preroll));
3332 if (demux->play_time > 0) {
3333 demux->segment.duration = demux->play_time;
3336 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3338 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3343 non_fixed_packet_size:
3345 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3346 ("packet size must be fixed"));
3347 return GST_FLOW_ERROR;
3351 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3352 ("short read parsing FILE object"));
3353 return GST_FLOW_ERROR;
3357 /* Content Description Object */
3358 static GstFlowReturn
3359 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3363 const gchar *gst_tag;
3368 GST_TAG_TITLE, 0, NULL}, {
3369 GST_TAG_ARTIST, 0, NULL}, {
3370 GST_TAG_COPYRIGHT, 0, NULL}, {
3371 GST_TAG_DESCRIPTION, 0, NULL}, {
3372 GST_TAG_COMMENT, 0, NULL}
3374 GstTagList *taglist;
3375 GValue value = { 0 };
3379 GST_INFO_OBJECT (demux, "object is a comment");
3381 if (size < (2 + 2 + 2 + 2 + 2))
3382 goto not_enough_data;
3384 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3385 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3386 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3387 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3388 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3390 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3391 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3392 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3394 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3395 if (size < tags[i].val_length)
3396 goto not_enough_data;
3398 /* might be just '/0', '/0'... */
3399 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3400 /* convert to UTF-8 */
3401 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3402 "UTF-8", "UTF-16LE", &in, &out, NULL);
3404 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3407 /* parse metadata into taglist */
3408 taglist = gst_tag_list_new_empty ();
3409 g_value_init (&value, G_TYPE_STRING);
3410 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3411 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3412 g_value_set_string (&value, tags[i].val_utf8);
3413 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3414 tags[i].gst_tag, &value, NULL);
3417 g_value_unset (&value);
3419 gst_asf_demux_add_global_tags (demux, taglist);
3421 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3422 g_free (tags[i].val_utf8);
3428 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3429 "comment tag section %d, skipping comment object", i);
3430 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3431 g_free (tags[i].val_utf8);
3432 return GST_FLOW_OK; /* not really fatal */
3436 static GstFlowReturn
3437 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3440 guint16 num_streams, i;
3444 goto not_enough_data;
3446 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3448 GST_INFO ("object is a bitrate properties object with %u streams",
3451 if (size < (num_streams * (2 + 4)))
3452 goto not_enough_data;
3454 for (i = 0; i < num_streams; ++i) {
3458 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3459 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3461 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3462 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3463 stream = gst_asf_demux_get_stream (demux, stream_id);
3465 if (stream->pending_tags == NULL) {
3466 stream->pending_tags =
3467 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3470 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3473 GST_WARNING ("stream id %u is too large", stream_id);
3481 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3482 return GST_FLOW_OK; /* not really fatal */
3486 static GstFlowReturn
3487 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3490 GstFlowReturn ret = GST_FLOW_OK;
3493 /* Get the rest of the header's header */
3494 if (size < (16 + 2 + 4))
3495 goto not_enough_data;
3497 /* skip GUID and two other bytes */
3498 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3499 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3501 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3503 /* FIXME: does data_size include the rest of the header that we have read? */
3504 if (hdr_size > size)
3505 goto not_enough_data;
3507 while (hdr_size > 0) {
3508 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3509 if (ret != GST_FLOW_OK)
3517 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3518 ("short read parsing extended header object"));
3519 return GST_FLOW_ERROR;
3523 static GstFlowReturn
3524 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3530 goto not_enough_data;
3532 if (demux->languages) {
3533 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3534 g_strfreev (demux->languages);
3535 demux->languages = NULL;
3536 demux->num_languages = 0;
3539 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3540 GST_LOG ("%u languages:", demux->num_languages);
3542 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3543 for (i = 0; i < demux->num_languages; ++i) {
3544 guint8 len, *lang_data = NULL;
3547 goto not_enough_data;
3548 len = gst_asf_demux_get_uint8 (&data, &size);
3549 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3552 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3555 /* truncate "en-us" etc. to just "en" */
3556 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3559 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3560 demux->languages[i] = utf8;
3563 goto not_enough_data;
3571 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3572 g_free (demux->languages);
3573 demux->languages = NULL;
3574 return GST_FLOW_OK; /* not fatal */
3578 static GstFlowReturn
3579 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3582 GstClockTime interval;
3585 if (size < (16 + 8 + 4 + 4))
3586 goto not_enough_data;
3589 gst_asf_demux_skip_bytes (16, &data, &size);
3590 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3591 gst_asf_demux_skip_bytes (4, &data, &size);
3592 count = gst_asf_demux_get_uint32 (&data, &size);
3594 demux->sidx_interval = interval;
3595 demux->sidx_num_entries = count;
3596 g_free (demux->sidx_entries);
3597 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3599 for (i = 0; i < count; ++i) {
3600 if (G_UNLIKELY (size < 6)) {
3601 /* adjust for broken files, to avoid having entries at the end
3602 * of the parsed index that point to time=0. Resulting in seeking to
3603 * the end of the file leading back to the beginning */
3604 demux->sidx_num_entries -= (count - i);
3607 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3608 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3609 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3610 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3611 demux->sidx_entries[i].count);
3614 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3621 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3622 return GST_FLOW_OK; /* not fatal */
3626 static GstFlowReturn
3627 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3628 guint8 * data, guint64 size)
3634 if (size < 16 + 2 + (2 * 2))
3635 goto not_enough_data;
3637 gst_asf_demux_get_guid (&guid, &data, &size);
3638 num = gst_asf_demux_get_uint16 (&data, &size);
3641 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3645 if (size < (num * sizeof (guint16)))
3646 goto not_enough_data;
3648 /* read mutually exclusive stream numbers */
3649 mes = g_new (guint8, num + 1);
3650 for (i = 0; i < num; ++i) {
3651 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3652 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3655 /* add terminator so we can easily get the count or know when to stop */
3656 mes[i] = (guint8) - 1;
3658 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3665 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3666 return GST_FLOW_OK; /* not absolutely fatal */
3671 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3673 return g_slist_find (demux->other_streams,
3674 GINT_TO_POINTER (stream_num)) == NULL;
3677 static GstFlowReturn
3678 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3681 AsfStreamExtProps esp;
3682 AsfStream *stream = NULL;
3683 AsfObject stream_obj;
3684 guint16 stream_name_count;
3685 guint16 num_payload_ext;
3687 guint8 *stream_obj_data = NULL;
3690 guint i, stream_num;
3693 obj_size = (guint) size;
3696 goto not_enough_data;
3699 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3700 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3701 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3702 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3703 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3704 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3705 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3706 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3707 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3708 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3709 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3710 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3711 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3712 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3713 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3715 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3716 GST_TIME_ARGS (esp.start_time));
3717 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3718 GST_TIME_ARGS (esp.end_time));
3719 GST_INFO ("flags = %08x", esp.flags);
3720 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3721 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3722 GST_INFO ("stream number = %u", stream_num);
3723 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3724 (esp.lang_idx < demux->num_languages) ?
3725 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3726 GST_INFO ("stream name count = %u", stream_name_count);
3728 /* read stream names */
3729 for (i = 0; i < stream_name_count; ++i) {
3730 guint16 stream_lang_idx G_GNUC_UNUSED;
3731 gchar *stream_name = NULL;
3734 goto not_enough_data;
3735 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3736 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3737 goto not_enough_data;
3738 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3739 g_free (stream_name); /* TODO: store names in struct */
3742 /* read payload extension systems stuff */
3743 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3745 if (num_payload_ext > 0)
3746 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3748 esp.payload_extensions = NULL;
3750 for (i = 0; i < num_payload_ext; ++i) {
3751 AsfPayloadExtension ext;
3753 guint32 sys_info_len;
3755 if (size < 16 + 2 + 4)
3756 goto not_enough_data;
3758 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3759 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3760 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3762 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3763 GST_LOG ("payload systems info len = %u", sys_info_len);
3764 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3765 goto not_enough_data;
3767 esp.payload_extensions[i] = ext;
3770 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3772 /* there might be an optional STREAM_INFO object here now; if not, we
3773 * should have parsed the corresponding stream info object already (since
3774 * we are parsing the extended stream properties objects delayed) */
3776 stream = gst_asf_demux_get_stream (demux, stream_num);
3780 /* get size of the stream object */
3781 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3782 goto not_enough_data;
3784 if (stream_obj.id != ASF_OBJ_STREAM)
3785 goto expected_stream_object;
3787 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3788 stream_obj.size > (10 * 1024 * 1024))
3789 goto not_enough_data;
3791 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3793 /* process this stream object later after all the other 'normal' ones
3794 * have been processed (since the others are more important/non-hidden) */
3795 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3796 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3797 goto not_enough_data;
3799 /* parse stream object */
3800 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3801 g_free (stream_obj_data);
3806 stream->ext_props = esp;
3808 /* try to set the framerate */
3809 if (stream->is_video && stream->caps) {
3810 GValue framerate = { 0 };
3814 g_value_init (&framerate, GST_TYPE_FRACTION);
3816 num = GST_SECOND / 100;
3817 denom = esp.avg_time_per_frame;
3819 /* avoid division by 0, assume 25/1 framerate */
3820 denom = GST_SECOND / 2500;
3823 gst_value_set_fraction (&framerate, num, denom);
3825 stream->caps = gst_caps_make_writable (stream->caps);
3826 s = gst_caps_get_structure (stream->caps, 0);
3827 gst_structure_set_value (s, "framerate", &framerate);
3828 g_value_unset (&framerate);
3829 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3830 num, denom, ((gdouble) num) / denom);
3833 /* add language info now if we have it */
3834 if (stream->ext_props.lang_idx < demux->num_languages) {
3835 if (stream->pending_tags == NULL)
3836 stream->pending_tags = gst_tag_list_new_empty ();
3837 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3838 demux->languages[stream->ext_props.lang_idx]);
3839 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3840 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3843 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
3844 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3852 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3853 return GST_FLOW_OK; /* not absolutely fatal */
3855 expected_stream_object:
3857 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3858 "object: expected embedded stream object, but got %s object instead!",
3859 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3860 return GST_FLOW_OK; /* not absolutely fatal */
3864 static const gchar *
3865 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3869 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3870 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3871 nick += strlen ("ASF_OBJ_");
3873 if (demux->objpath == NULL) {
3874 demux->objpath = g_strdup (nick);
3878 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3879 g_free (demux->objpath);
3880 demux->objpath = newpath;
3883 return (const gchar *) demux->objpath;
3887 gst_asf_demux_pop_obj (GstASFDemux * demux)
3891 if ((s = g_strrstr (demux->objpath, "/"))) {
3894 g_free (demux->objpath);
3895 demux->objpath = NULL;
3900 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3905 /* Parse the queued extended stream property objects and add the info
3906 * to the existing streams or add the new embedded streams, but without
3907 * activating them yet */
3908 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3909 g_slist_length (demux->ext_stream_props));
3911 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3912 GstBuffer *buf = GST_BUFFER (l->data);
3915 gst_buffer_map (buf, &map, GST_MAP_READ);
3917 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3918 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
3919 gst_buffer_unmap (buf, &map);
3920 gst_buffer_unref (buf);
3922 g_slist_free (demux->ext_stream_props);
3923 demux->ext_stream_props = NULL;
3928 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3932 for (i = 0; i < demux->num_streams; ++i) {
3937 stream = &demux->stream[i];
3939 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3941 if (stream->active) {
3942 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3947 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3950 /* check for each mutual exclusion whether it affects this stream */
3951 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3952 if (*mes == stream->id) {
3953 /* if yes, check if we've already added streams that are mutually
3954 * exclusive with the stream we're about to add */
3955 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3956 for (j = 0; j < demux->num_streams; ++j) {
3957 /* if the broadcast flag is set, assume the hidden streams aren't
3958 * actually streamed and hide them (or playbin won't work right),
3959 * otherwise assume their data is available */
3960 if (demux->stream[j].id == *mes && demux->broadcast) {
3962 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3963 "mutually exclusive with already existing stream ID %d, "
3964 "hiding stream", stream->id, demux->stream[j].id);
3976 /* FIXME: we should do stream activation based on preroll data in
3977 * streaming mode too */
3978 if (demux->streaming && !is_hidden)
3979 gst_asf_demux_activate_stream (demux, stream);
3984 static GstFlowReturn
3985 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3988 GstFlowReturn ret = GST_FLOW_OK;
3990 guint64 obj_data_size;
3992 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3993 return ASF_FLOW_NEED_MORE_DATA;
3995 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3996 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3998 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4000 if (*p_size < obj_data_size)
4001 return ASF_FLOW_NEED_MORE_DATA;
4003 gst_asf_demux_push_obj (demux, obj.id);
4005 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4008 case ASF_OBJ_STREAM:
4009 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4013 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4015 case ASF_OBJ_HEADER:
4016 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4018 case ASF_OBJ_COMMENT:
4019 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4022 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4024 case ASF_OBJ_BITRATE_PROPS:
4026 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4029 case ASF_OBJ_EXT_CONTENT_DESC:
4031 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4034 case ASF_OBJ_METADATA_OBJECT:
4035 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4037 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4040 /* process these later, we might not have parsed the corresponding
4041 * stream object yet */
4042 GST_LOG ("%s: queued for later parsing", demux->objpath);
4043 buf = gst_buffer_new_and_alloc (obj_data_size);
4044 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4045 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4049 case ASF_OBJ_LANGUAGE_LIST:
4050 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4052 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4053 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4056 case ASF_OBJ_SIMPLE_INDEX:
4057 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4059 case ASF_OBJ_CONTENT_ENCRYPTION:
4060 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4061 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4062 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4063 goto error_encrypted;
4064 case ASF_OBJ_CONCEAL_NONE:
4066 case ASF_OBJ_UNDEFINED:
4067 case ASF_OBJ_CODEC_COMMENT:
4069 case ASF_OBJ_PADDING:
4070 case ASF_OBJ_BITRATE_MUTEX:
4071 case ASF_OBJ_COMPATIBILITY:
4072 case ASF_OBJ_INDEX_PLACEHOLDER:
4073 case ASF_OBJ_INDEX_PARAMETERS:
4074 case ASF_OBJ_STREAM_PRIORITIZATION:
4075 case ASF_OBJ_SCRIPT_COMMAND:
4077 /* Unknown/unhandled object, skip it and hope for the best */
4078 GST_INFO ("%s: skipping object", demux->objpath);
4083 /* this can't fail, we checked the number of bytes available before */
4084 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4086 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4088 gst_asf_demux_pop_obj (demux);
4095 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4096 return GST_FLOW_ERROR;
4101 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4102 GstBuffer ** p_buffer)
4104 GstBuffer *descrambled_buffer;
4105 GstBuffer *scrambled_buffer;
4106 GstBuffer *sub_buffer;
4113 /* descrambled_buffer is initialised in the first iteration */
4114 descrambled_buffer = NULL;
4115 scrambled_buffer = *p_buffer;
4117 if (gst_buffer_get_size (scrambled_buffer) <
4118 stream->ds_packet_size * stream->span)
4121 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4122 offset += stream->ds_chunk_size) {
4123 off = offset / stream->ds_chunk_size;
4124 row = off / stream->span;
4125 col = off % stream->span;
4126 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4127 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4128 col, off, stream->ds_chunk_size);
4129 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4130 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4131 stream->span, stream->ds_packet_size);
4132 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4133 gst_buffer_get_size (scrambled_buffer));
4135 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4136 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4138 descrambled_buffer = sub_buffer;
4140 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4144 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4145 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4146 GST_BUFFER_DURATION (descrambled_buffer) =
4147 GST_BUFFER_DURATION (scrambled_buffer);
4148 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4149 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4150 GST_BUFFER_OFFSET_END (scrambled_buffer);
4152 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4154 gst_buffer_unref (scrambled_buffer);
4155 *p_buffer = descrambled_buffer;
4159 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4161 GstASFDemux *demux = GST_ASF_DEMUX (element);
4164 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4166 for (i = 0; i < demux->num_streams; ++i) {
4167 gst_event_ref (event);
4168 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4169 GST_OBJECT_CAST (element), event)) {
4170 gst_event_unref (event);
4175 gst_event_unref (event);
4179 /* takes ownership of the passed event */
4181 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4183 gboolean ret = TRUE;
4186 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4187 GST_EVENT_TYPE_NAME (event));
4189 for (i = 0; i < demux->num_streams; ++i) {
4190 gst_event_ref (event);
4191 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4193 gst_event_unref (event);
4198 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4202 gboolean res = FALSE;
4204 demux = GST_ASF_DEMUX (parent);
4206 GST_DEBUG ("handling %s query",
4207 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4209 switch (GST_QUERY_TYPE (query)) {
4210 case GST_QUERY_DURATION:
4214 gst_query_parse_duration (query, &format, NULL);
4216 if (format != GST_FORMAT_TIME) {
4217 GST_LOG ("only support duration queries in TIME format");
4221 GST_OBJECT_LOCK (demux);
4223 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4224 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4225 GST_TIME_ARGS (demux->segment.duration));
4227 gst_query_set_duration (query, GST_FORMAT_TIME,
4228 demux->segment.duration);
4232 GST_LOG ("duration not known yet");
4235 GST_OBJECT_UNLOCK (demux);
4239 case GST_QUERY_POSITION:{
4242 gst_query_parse_position (query, &format, NULL);
4244 if (format != GST_FORMAT_TIME) {
4245 GST_LOG ("only support position queries in TIME format");
4249 GST_OBJECT_LOCK (demux);
4251 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4252 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4253 GST_TIME_ARGS (demux->segment.position));
4255 gst_query_set_position (query, GST_FORMAT_TIME,
4256 demux->segment.position);
4260 GST_LOG ("position not known yet");
4263 GST_OBJECT_UNLOCK (demux);
4267 case GST_QUERY_SEEKING:{
4270 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4271 if (format == GST_FORMAT_TIME) {
4274 GST_OBJECT_LOCK (demux);
4275 duration = demux->segment.duration;
4276 GST_OBJECT_UNLOCK (demux);
4278 if (!demux->streaming || !demux->seekable) {
4279 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4286 /* try downstream first in TIME */
4287 res = gst_pad_query_default (pad, parent, query);
4289 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4290 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4291 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4292 /* if no luck, maybe in BYTES */
4293 if (!seekable || fmt != GST_FORMAT_TIME) {
4296 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4297 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4298 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4299 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4300 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4301 if (fmt != GST_FORMAT_BYTES)
4304 gst_query_unref (q);
4305 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4311 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4315 case GST_QUERY_LATENCY:
4318 GstClockTime min, max;
4320 /* preroll delay does not matter in non-live pipeline,
4321 * but we might end up in a live (rtsp) one ... */
4324 res = gst_pad_query_default (pad, parent, query);
4328 gst_query_parse_latency (query, &live, &min, &max);
4330 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4331 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4332 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4334 GST_OBJECT_LOCK (demux);
4336 min += demux->latency;
4338 max += demux->latency;
4339 GST_OBJECT_UNLOCK (demux);
4341 gst_query_set_latency (query, live, min, max);
4344 case GST_QUERY_SEGMENT:
4349 format = demux->segment.format;
4352 gst_segment_to_stream_time (&demux->segment, format,
4353 demux->segment.start);
4354 if ((stop = demux->segment.stop) == -1)
4355 stop = demux->segment.duration;
4357 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4359 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4364 res = gst_pad_query_default (pad, parent, query);
4371 static GstStateChangeReturn
4372 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4374 GstASFDemux *demux = GST_ASF_DEMUX (element);
4375 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4377 switch (transition) {
4378 case GST_STATE_CHANGE_NULL_TO_READY:{
4379 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4380 demux->need_newsegment = TRUE;
4381 demux->segment_running = FALSE;
4382 demux->accurate = FALSE;
4383 demux->adapter = gst_adapter_new ();
4384 demux->metadata = gst_caps_new_empty ();
4385 demux->global_metadata = gst_structure_new_empty ("metadata");
4386 demux->data_size = 0;
4387 demux->data_offset = 0;
4388 demux->index_offset = 0;
4389 demux->base_offset = 0;
4390 demux->flowcombiner = gst_flow_combiner_new ();
4397 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4398 if (ret == GST_STATE_CHANGE_FAILURE)
4401 switch (transition) {
4402 case GST_STATE_CHANGE_PAUSED_TO_READY:
4403 gst_asf_demux_reset (demux, FALSE);
4406 case GST_STATE_CHANGE_READY_TO_NULL:
4407 gst_asf_demux_reset (demux, FALSE);
4408 gst_flow_combiner_free (demux->flowcombiner);
4409 demux->flowcombiner = NULL;