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>
41 #include <gst/video/video.h>
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS ("video/x-ms-asf")
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE (16+8)
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA 99
76 #define gst_asf_get_flow_name(flow) \
77 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
78 "need-more-data" : gst_flow_get_name (flow)
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83 GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89 GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98 GstObject * parent, GstPadMode mode, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
103 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
104 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
106 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
107 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
108 AsfStream * stream, GstBuffer ** p_buffer);
109 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
111 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
113 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
116 #define gst_asf_demux_parent_class parent_class
117 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
120 gst_asf_demux_class_init (GstASFDemuxClass * klass)
122 GstElementClass *gstelement_class;
124 gstelement_class = (GstElementClass *) klass;
126 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
128 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
130 gst_element_class_add_pad_template (gstelement_class,
131 gst_static_pad_template_get (&audio_src_template));
132 gst_element_class_add_pad_template (gstelement_class,
133 gst_static_pad_template_get (&video_src_template));
134 gst_element_class_add_pad_template (gstelement_class,
135 gst_static_pad_template_get (&gst_asf_demux_sink_template));
137 gstelement_class->change_state =
138 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
139 gstelement_class->send_event =
140 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
144 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
146 gst_caps_replace (&stream->caps, NULL);
147 if (stream->pending_tags) {
148 gst_tag_list_unref (stream->pending_tags);
149 stream->pending_tags = NULL;
151 if (stream->streamheader) {
152 gst_buffer_unref (stream->streamheader);
153 stream->streamheader = NULL;
156 if (stream->active) {
157 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
158 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
160 gst_object_unref (stream->pad);
164 if (stream->payloads) {
165 while (stream->payloads->len > 0) {
169 last = stream->payloads->len - 1;
170 payload = &g_array_index (stream->payloads, AsfPayload, last);
171 gst_buffer_replace (&payload->buf, NULL);
172 g_array_remove_index (stream->payloads, last);
174 g_array_free (stream->payloads, TRUE);
175 stream->payloads = NULL;
177 if (stream->ext_props.valid) {
178 g_free (stream->ext_props.payload_extensions);
179 stream->ext_props.payload_extensions = NULL;
184 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
186 GST_LOG_OBJECT (demux, "resetting");
188 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
189 demux->segment_running = FALSE;
190 if (demux->adapter && !chain_reset) {
191 gst_adapter_clear (demux->adapter);
192 g_object_unref (demux->adapter);
193 demux->adapter = NULL;
195 if (demux->taglist) {
196 gst_tag_list_unref (demux->taglist);
197 demux->taglist = NULL;
199 if (demux->metadata) {
200 gst_caps_unref (demux->metadata);
201 demux->metadata = NULL;
203 if (demux->global_metadata) {
204 gst_structure_free (demux->global_metadata);
205 demux->global_metadata = NULL;
207 if (demux->mut_ex_streams) {
208 g_slist_free (demux->mut_ex_streams);
209 demux->mut_ex_streams = NULL;
212 demux->state = GST_ASF_DEMUX_STATE_HEADER;
213 g_free (demux->objpath);
214 demux->objpath = NULL;
215 g_strfreev (demux->languages);
216 demux->languages = NULL;
217 demux->num_languages = 0;
218 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
220 g_slist_free (demux->ext_stream_props);
221 demux->ext_stream_props = NULL;
223 while (demux->old_num_streams > 0) {
224 gst_asf_demux_free_stream (demux,
225 &demux->old_stream[demux->old_num_streams - 1]);
226 --demux->old_num_streams;
228 memset (demux->old_stream, 0, sizeof (demux->old_stream));
229 demux->old_num_streams = 0;
231 /* when resetting for a new chained asf, we don't want to remove the pads
232 * before adding the new ones */
234 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
235 demux->old_num_streams = demux->num_streams;
236 demux->num_streams = 0;
239 while (demux->num_streams > 0) {
240 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
241 --demux->num_streams;
243 memset (demux->stream, 0, sizeof (demux->stream));
245 /* do not remove those for not adding pads with same name */
246 demux->num_audio_streams = 0;
247 demux->num_video_streams = 0;
248 demux->have_group_id = FALSE;
249 demux->group_id = G_MAXUINT;
251 demux->num_streams = 0;
252 demux->activated_streams = FALSE;
253 demux->first_ts = GST_CLOCK_TIME_NONE;
254 demux->segment_ts = GST_CLOCK_TIME_NONE;
257 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
258 demux->state = GST_ASF_DEMUX_STATE_HEADER;
259 demux->seekable = FALSE;
260 demux->broadcast = FALSE;
261 demux->sidx_interval = 0;
262 demux->sidx_num_entries = 0;
263 g_free (demux->sidx_entries);
264 demux->sidx_entries = NULL;
266 demux->speed_packets = 1;
268 demux->asf_3D_mode = GST_ASF_3D_NONE;
271 GST_LOG_OBJECT (demux, "Restarting");
272 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
273 demux->need_newsegment = TRUE;
274 demux->segment_seqnum = 0;
275 demux->segment_running = FALSE;
276 demux->accurate = FALSE;
277 demux->metadata = gst_caps_new_empty ();
278 demux->global_metadata = gst_structure_new_empty ("metadata");
279 demux->data_size = 0;
280 demux->data_offset = 0;
281 demux->index_offset = 0;
283 demux->base_offset = 0;
286 g_slist_free (demux->other_streams);
287 demux->other_streams = NULL;
291 gst_asf_demux_init (GstASFDemux * demux)
294 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
295 gst_pad_set_chain_function (demux->sinkpad,
296 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
297 gst_pad_set_event_function (demux->sinkpad,
298 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
299 gst_pad_set_activate_function (demux->sinkpad,
300 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
301 gst_pad_set_activatemode_function (demux->sinkpad,
302 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
303 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
305 /* set initial state */
306 gst_asf_demux_reset (demux, FALSE);
310 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
315 query = gst_query_new_scheduling ();
317 if (!gst_pad_peer_query (sinkpad, query)) {
318 gst_query_unref (query);
322 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
323 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
324 gst_query_unref (query);
329 GST_DEBUG_OBJECT (sinkpad, "activating pull");
330 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
334 GST_DEBUG_OBJECT (sinkpad, "activating push");
335 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
340 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
341 GstPadMode mode, gboolean active)
346 demux = GST_ASF_DEMUX (parent);
349 case GST_PAD_MODE_PUSH:
350 demux->state = GST_ASF_DEMUX_STATE_HEADER;
351 demux->streaming = TRUE;
354 case GST_PAD_MODE_PULL:
356 demux->state = GST_ASF_DEMUX_STATE_HEADER;
357 demux->streaming = FALSE;
359 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
362 res = gst_pad_stop_task (sinkpad);
373 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
378 demux = GST_ASF_DEMUX (parent);
380 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
381 switch (GST_EVENT_TYPE (event)) {
382 case GST_EVENT_SEGMENT:{
383 const GstSegment *segment;
385 gst_event_parse_segment (event, &segment);
387 if (segment->format == GST_FORMAT_BYTES) {
388 if (demux->packet_size && segment->start > demux->data_offset)
389 demux->packet = (segment->start - demux->data_offset) /
393 } else if (segment->format == GST_FORMAT_TIME) {
394 /* do not know packet position, not really a problem */
397 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
398 gst_event_unref (event);
402 /* record upstream segment for interpolation */
403 if (segment->format != demux->in_segment.format)
404 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
405 gst_segment_copy_into (segment, &demux->in_segment);
407 /* in either case, clear some state and generate newsegment later on */
408 GST_OBJECT_LOCK (demux);
409 demux->segment_ts = GST_CLOCK_TIME_NONE;
410 demux->in_gap = GST_CLOCK_TIME_NONE;
411 demux->need_newsegment = TRUE;
412 demux->segment_seqnum = gst_event_get_seqnum (event);
413 gst_asf_demux_reset_stream_state_after_discont (demux);
414 GST_OBJECT_UNLOCK (demux);
416 gst_event_unref (event);
422 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
423 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
424 (_("This stream contains no data.")),
425 ("got eos and didn't receive a complete header object"));
428 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
429 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
430 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
431 (_("Internal data stream error.")),
432 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
436 GST_OBJECT_LOCK (demux);
437 gst_adapter_clear (demux->adapter);
438 GST_OBJECT_UNLOCK (demux);
439 gst_asf_demux_send_event_unlocked (demux, event);
443 case GST_EVENT_FLUSH_STOP:
444 GST_OBJECT_LOCK (demux);
445 gst_asf_demux_reset_stream_state_after_discont (demux);
446 GST_OBJECT_UNLOCK (demux);
447 gst_asf_demux_send_event_unlocked (demux, event);
448 /* upon activation, latency is no longer introduced, e.g. after seek */
449 if (demux->activated_streams)
454 ret = gst_pad_event_default (pad, parent, event);
462 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
463 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
464 gboolean next, gboolean * eos)
466 GstClockTime idx_time;
472 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
475 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
478 /* if we want the next keyframe, we have to go forward till we find
479 a different packet number */
481 if (idx >= demux->sidx_num_entries - 1) {
482 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
487 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
488 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
495 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
501 *packet = demux->sidx_entries[idx].packet;
503 *speed = demux->sidx_entries[idx].count;
505 /* so we get closer to the actual time of the packet ... actually, let's not
506 * do this, since we throw away superfluous payloads before the seek position
507 * anyway; this way, our key unit seek 'snap resolution' is a bit better
508 * (ie. same as index resolution) */
510 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
514 idx_time = demux->sidx_interval * idx;
515 if (G_LIKELY (idx_time >= demux->preroll))
516 idx_time -= demux->preroll;
518 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
519 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
520 GST_TIME_ARGS (idx_time));
522 if (G_LIKELY (p_idx_time))
523 *p_idx_time = idx_time;
529 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
533 gst_adapter_clear (demux->adapter);
535 GST_DEBUG_OBJECT (demux, "reset stream state");
537 gst_flow_combiner_reset (demux->flowcombiner);
538 for (n = 0; n < demux->num_streams; n++) {
539 demux->stream[n].discont = TRUE;
540 demux->stream[n].first_buffer = TRUE;
542 while (demux->stream[n].payloads->len > 0) {
546 last = demux->stream[n].payloads->len - 1;
547 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
548 gst_buffer_replace (&payload->buf, NULL);
549 g_array_remove_index (demux->stream[n].payloads, last);
555 gst_asf_demux_mark_discont (GstASFDemux * demux)
559 GST_DEBUG_OBJECT (demux, "Mark stream discont");
561 for (n = 0; n < demux->num_streams; n++)
562 demux->stream[n].discont = TRUE;
565 /* do a seek in push based mode */
567 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
572 GstSeekType cur_type, stop_type;
576 GstEvent *byte_event;
578 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
581 stop_type = GST_SEEK_TYPE_NONE;
584 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
586 /* determine packet, by index or by estimation */
587 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
590 (guint) gst_util_uint64_scale (demux->num_packets, cur,
594 if (packet > demux->num_packets) {
595 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
600 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
602 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
604 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
605 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
606 /* BYTE seek event */
607 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
608 cur, stop_type, stop);
609 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
610 res = gst_pad_push_event (demux->sinkpad, byte_event);
616 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
618 GstClockTime idx_time;
621 GstSeekType cur_type, stop_type;
623 gboolean only_need_update;
624 gboolean keyunit_sync, after, before, next;
629 guint packet, speed_count = 1;
634 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
637 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
638 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
642 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
643 * so first try to let it handle the seek event. */
644 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
647 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
648 demux->num_packets == 0 || demux->play_time == 0)) {
649 GST_LOG_OBJECT (demux, "stream is not seekable");
653 if (G_UNLIKELY (!demux->activated_streams)) {
654 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
658 if (G_UNLIKELY (rate <= 0.0)) {
659 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
663 seqnum = gst_event_get_seqnum (event);
664 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
666 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
667 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
668 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
669 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
670 next = after && !before;
672 if (G_UNLIKELY (demux->streaming)) {
673 /* support it safely needs more segment handling, e.g. closing etc */
675 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
678 /* we can (re)construct the start later on, but not the end */
679 if (stop_type != GST_SEEK_TYPE_NONE &&
680 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
681 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
684 return gst_asf_demux_handle_seek_push (demux, event);
687 /* unlock the streaming thread */
688 if (G_LIKELY (flush)) {
689 fevent = gst_event_new_flush_start ();
691 gst_event_set_seqnum (fevent, seqnum);
692 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
693 gst_asf_demux_send_event_unlocked (demux, fevent);
695 gst_pad_pause_task (demux->sinkpad);
698 /* grab the stream lock so that streaming cannot continue, for
699 * non flushing seeks when the element is in PAUSED this could block
701 GST_PAD_STREAM_LOCK (demux->sinkpad);
703 /* we now can stop flushing, since we have the stream lock now */
704 fevent = gst_event_new_flush_stop (TRUE);
705 gst_event_set_seqnum (fevent, seqnum);
706 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
708 if (G_LIKELY (flush))
709 gst_asf_demux_send_event_unlocked (demux, fevent);
711 gst_event_unref (fevent);
713 /* operating on copy of segment until we know the seek worked */
714 segment = demux->segment;
716 if (G_UNLIKELY (demux->segment_running && !flush)) {
717 GstSegment newsegment;
720 /* create the segment event to close the current segment */
721 gst_segment_copy_into (&segment, &newsegment);
722 newseg = gst_event_new_segment (&newsegment);
723 gst_event_set_seqnum (newseg, seqnum);
725 gst_asf_demux_send_event_unlocked (demux, newseg);
728 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
729 cur, stop_type, stop, &only_need_update);
731 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
732 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
734 if (cur_type != GST_SEEK_TYPE_SET)
735 seek_time = segment.start;
739 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
740 * real start of data and segment_start to indexed time for key unit seek*/
741 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
742 &idx_time, &speed_count, next, &eos))) {
746 demux->packet = demux->num_packets;
750 /* First try to query our source to see if it can convert for us. This is
751 the case when our source is an mms stream, notice that in this case
752 gstmms will do a time based seek to get the byte offset, this is not a
753 problem as the seek to this offset needs to happen anway. */
754 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
755 GST_FORMAT_BYTES, &offset)) {
756 packet = (offset - demux->data_offset) / demux->packet_size;
757 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
758 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
759 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
760 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
761 demux->packet_size, packet);
763 /* FIXME: For streams containing video, seek to an earlier position in
764 * the hope of hitting a keyframe and let the sinks throw away the stuff
765 * before the segment start. For audio-only this is unnecessary as every
767 if (flush && (demux->accurate || (keyunit_sync && !next))
768 && demux->num_video_streams > 0) {
769 seek_time -= 5 * GST_SECOND;
774 packet = (guint) gst_util_uint64_scale (demux->num_packets,
775 seek_time, demux->play_time);
777 if (packet > demux->num_packets)
778 packet = demux->num_packets;
781 if (G_LIKELY (keyunit_sync)) {
782 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
783 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
784 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
785 segment.start = idx_time;
786 segment.position = idx_time;
787 segment.time = idx_time;
791 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
793 GST_OBJECT_LOCK (demux);
794 demux->segment = segment;
795 demux->packet = packet;
796 demux->need_newsegment = TRUE;
797 demux->segment_seqnum = seqnum;
798 demux->speed_packets = speed_count;
799 gst_asf_demux_reset_stream_state_after_discont (demux);
800 GST_OBJECT_UNLOCK (demux);
803 /* restart our task since it might have been stopped when we did the flush */
804 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
807 /* streaming can continue now */
808 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
814 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
820 demux = GST_ASF_DEMUX (parent);
822 switch (GST_EVENT_TYPE (event)) {
824 GST_LOG_OBJECT (pad, "seek event");
825 ret = gst_asf_demux_handle_seek_event (demux, event);
826 gst_event_unref (event);
829 case GST_EVENT_NAVIGATION:
830 /* just drop these two silently */
831 gst_event_unref (event);
835 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
836 ret = gst_pad_event_default (pad, parent, event);
843 static inline guint32
844 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
848 ret = gst_asf_identify_guid (guids, guid);
850 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
851 gst_asf_get_guid_nick (guids, ret),
852 guid->v1, guid->v2, guid->v3, guid->v4);
864 /* expect is true when the user is expeting an object,
865 * when false, it will give no warnings if the object
869 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
870 guint data_len, AsfObject * object, gboolean expect)
874 if (data_len < ASF_OBJECT_HEADER_SIZE)
877 guid.v1 = GST_READ_UINT32_LE (data + 0);
878 guid.v2 = GST_READ_UINT32_LE (data + 4);
879 guid.v3 = GST_READ_UINT32_LE (data + 8);
880 guid.v4 = GST_READ_UINT32_LE (data + 12);
882 object->size = GST_READ_UINT64_LE (data + 16);
884 /* FIXME: make asf_demux_identify_object_guid() */
885 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
886 if (object->id == ASF_OBJ_UNDEFINED && expect) {
887 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
888 guid.v1, guid.v2, guid.v3, guid.v4);
895 gst_asf_demux_release_old_pads (GstASFDemux * demux)
897 GST_DEBUG_OBJECT (demux, "Releasing old pads");
899 while (demux->old_num_streams > 0) {
900 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
901 gst_event_new_eos ());
902 gst_asf_demux_free_stream (demux,
903 &demux->old_stream[demux->old_num_streams - 1]);
904 --demux->old_num_streams;
906 memset (demux->old_stream, 0, sizeof (demux->old_stream));
907 demux->old_num_streams = 0;
911 gst_asf_demux_chain_headers (GstASFDemux * demux)
915 guint8 *header_data, *data = NULL;
916 const guint8 *cdata = NULL;
919 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
923 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
924 if (obj.id != ASF_OBJ_HEADER)
927 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
929 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
930 if (gst_adapter_available (demux->adapter) < obj.size + 50)
933 data = gst_adapter_take (demux->adapter, obj.size + 50);
936 header_size = obj.size;
937 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
938 if (flow != GST_FLOW_OK)
941 /* calculate where the packet data starts */
942 demux->data_offset = obj.size + 50;
944 /* now parse the beginning of the ASF_OBJ_DATA object */
945 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
948 if (demux->num_streams == 0)
957 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
964 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
965 ("This doesn't seem to be an ASF file"));
967 return GST_FLOW_ERROR;
972 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
973 ("header parsing failed, or no streams found, flow = %s",
974 gst_flow_get_name (flow)));
976 return GST_FLOW_ERROR;
981 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
982 GstBuffer ** p_buf, GstFlowReturn * p_flow)
987 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
990 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
992 if (G_LIKELY (p_flow))
995 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
996 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
997 "+%u", gst_flow_get_name (flow), offset, size);
1002 g_assert (*p_buf != NULL);
1004 buffer_size = gst_buffer_get_size (*p_buf);
1005 if (G_UNLIKELY (buffer_size < size)) {
1006 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1007 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1008 gst_buffer_unref (*p_buf);
1009 if (G_LIKELY (p_flow))
1010 *p_flow = GST_FLOW_EOS;
1019 gst_asf_demux_pull_indices (GstASFDemux * demux)
1021 GstBuffer *buf = NULL;
1025 offset = demux->index_offset;
1027 if (G_UNLIKELY (offset == 0)) {
1028 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1032 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1038 gst_buffer_map (buf, &map, GST_MAP_READ);
1039 g_assert (map.size >= 16 + 8);
1040 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1041 gst_buffer_unmap (buf, &map);
1042 gst_buffer_replace (&buf, NULL);
1044 /* check for sanity */
1045 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1046 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1050 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1054 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1055 ", size %u", offset, (guint) obj.size);
1057 offset += obj.size; /* increase before _process_object changes it */
1059 gst_buffer_map (buf, &map, GST_MAP_READ);
1060 g_assert (map.size >= obj.size);
1061 bufdata = (guint8 *) map.data;
1062 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1063 gst_buffer_unmap (buf, &map);
1064 gst_buffer_replace (&buf, NULL);
1066 if (G_UNLIKELY (flow != GST_FLOW_OK))
1071 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1075 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1079 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1080 if (obj.id != ASF_OBJ_DATA) {
1081 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1085 demux->state = GST_ASF_DEMUX_STATE_DATA;
1087 if (!demux->broadcast && obj.size > 50) {
1088 demux->data_size = obj.size - 50;
1089 /* CHECKME: for at least one file this is off by +158 bytes?! */
1090 demux->index_offset = demux->data_offset + demux->data_size;
1092 demux->data_size = 0;
1093 demux->index_offset = 0;
1098 if (!demux->broadcast) {
1099 /* skip object header (24 bytes) and file GUID (16 bytes) */
1100 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1102 demux->num_packets = 0;
1105 if (demux->num_packets == 0)
1106 demux->seekable = FALSE;
1108 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1109 if (demux->data_size == 0 && demux->num_packets > 0) {
1110 demux->data_size = demux->num_packets * demux->packet_size;
1111 demux->index_offset = demux->data_offset + demux->data_size;
1114 /* process pending stream objects and create pads for those */
1115 gst_asf_demux_process_queued_extended_stream_objects (demux);
1117 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1118 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1119 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1120 demux->data_offset, demux->data_size, demux->index_offset);
1126 gst_asf_demux_pull_headers (GstASFDemux * demux)
1130 GstBuffer *buf = NULL;
1135 GST_LOG_OBJECT (demux, "reading headers");
1137 /* pull HEADER object header, so we know its size */
1138 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1141 gst_buffer_map (buf, &map, GST_MAP_READ);
1142 g_assert (map.size >= 16 + 8);
1143 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1144 gst_buffer_unmap (buf, &map);
1145 gst_buffer_replace (&buf, NULL);
1147 if (obj.id != ASF_OBJ_HEADER)
1150 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1152 /* pull HEADER object */
1153 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1157 size = obj.size; /* don't want obj.size changed */
1158 gst_buffer_map (buf, &map, GST_MAP_READ);
1159 g_assert (map.size >= size);
1160 bufdata = (guint8 *) map.data;
1161 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1162 gst_buffer_unmap (buf, &map);
1163 gst_buffer_replace (&buf, NULL);
1165 if (flow != GST_FLOW_OK) {
1166 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1170 /* calculate where the packet data starts */
1171 demux->data_offset = demux->base_offset + obj.size + 50;
1173 /* now pull beginning of DATA object before packet data */
1174 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1178 gst_buffer_map (buf, &map, GST_MAP_READ);
1179 g_assert (map.size >= size);
1180 bufdata = (guint8 *) map.data;
1181 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1184 if (demux->num_streams == 0)
1187 gst_buffer_unmap (buf, &map);
1188 gst_buffer_replace (&buf, NULL);
1196 gst_buffer_unmap (buf, &map);
1197 gst_buffer_replace (&buf, NULL);
1199 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1200 ("This doesn't seem to be an ASF file"));
1209 gst_buffer_unmap (buf, &map);
1210 gst_buffer_replace (&buf, NULL);
1211 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1217 all_streams_prerolled (GstASFDemux * demux)
1219 GstClockTime preroll_time;
1220 guint i, num_no_data = 0;
1222 /* Allow at least 500ms of preroll_time */
1223 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1225 /* returns TRUE as long as there isn't a stream which (a) has data queued
1226 * and (b) the timestamp of last piece of data queued is < demux->preroll
1227 * AND there is at least one other stream with data queued */
1228 for (i = 0; i < demux->num_streams; ++i) {
1229 AsfPayload *last_payload = NULL;
1233 stream = &demux->stream[i];
1234 if (G_UNLIKELY (stream->payloads->len == 0)) {
1236 GST_LOG_OBJECT (stream->pad, "no data queued");
1240 /* find last payload with timestamp */
1241 for (last_idx = stream->payloads->len - 1;
1242 last_idx >= 0 && (last_payload == NULL
1243 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1244 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1247 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1248 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1249 GST_TIME_ARGS (preroll_time));
1250 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1251 || last_payload->ts <= preroll_time)) {
1252 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1257 if (G_UNLIKELY (num_no_data > 0))
1265 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1270 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1273 /* check for each mutual exclusion group whether it affects this stream */
1274 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1275 if (*mes == stream->id) {
1276 /* we are in this group; let's check if we've already activated streams
1277 * that are in the same group (and hence mutually exclusive to this
1279 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1282 for (i = 0; i < demux->num_streams; ++i) {
1283 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1284 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1285 "to already active stream with ID %d", stream->id,
1286 demux->stream[i].id);
1291 /* we can only be in this group once, let's break out and move on to
1292 * the next mutual exclusion group */
1303 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1305 /* remember the first queued timestamp for the segment */
1306 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1307 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1308 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1309 GST_TIME_ARGS (demux->first_ts));
1310 demux->segment_ts = payload_ts;
1311 /* always note, but only determines segment when streaming */
1312 if (demux->streaming)
1313 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1314 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1315 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1320 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1322 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1323 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1326 /* go trhough each stream, find smallest timestamp */
1327 for (i = 0; i < demux->num_streams; ++i) {
1330 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1331 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1332 stream = &demux->stream[i];
1334 for (j = 0; j < stream->payloads->len; ++j) {
1335 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1336 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1337 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1338 || stream_min_ts > payload->ts)) {
1339 stream_min_ts = payload->ts;
1341 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1342 payload->ts > stream_min_ts &&
1343 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1344 || stream_min_ts2 > payload->ts)) {
1345 stream_min_ts2 = payload->ts;
1349 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1350 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1351 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1352 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1353 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1355 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1358 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1359 stream_min_ts = stream_min_ts2;
1361 /* if we don't have timestamp for this stream, wait for more data */
1362 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1365 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1366 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1367 first_ts = stream_min_ts;
1370 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1373 demux->first_ts = first_ts;
1375 /* update packets queued before we knew first timestamp */
1376 for (i = 0; i < demux->num_streams; ++i) {
1379 stream = &demux->stream[i];
1381 for (j = 0; j < stream->payloads->len; ++j) {
1382 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1383 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1384 if (payload->ts > first_ts)
1385 payload->ts -= first_ts;
1393 gst_asf_demux_check_segment_ts (demux, 0);
1399 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1401 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1402 and often set wrong, inspecting the data is the only way that seem to be working */
1403 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1404 GstCaps *caps = NULL;
1406 GstAdapter *adapter = gst_adapter_new ();
1408 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1410 AsfPayload *payload;
1413 payload = &g_array_index (stream->payloads, AsfPayload, i);
1414 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1415 len = gst_adapter_available (adapter);
1416 data = gst_adapter_map (adapter, len);
1420 #define MIN_LENGTH 128
1422 /* look for the sync points */
1424 if (len < MIN_LENGTH || /* give typefind something to work on */
1425 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1426 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1432 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1435 if (prob < GST_TYPE_FIND_LIKELY) {
1438 if (len > MIN_LENGTH)
1439 /* this wasn't it, look for another sync point */
1443 gst_adapter_unmap (adapter);
1446 gst_object_unref (adapter);
1449 gst_caps_take (&stream->caps, caps);
1457 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1461 if (demux->activated_streams)
1464 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1467 if (!all_streams_prerolled (demux) && !force) {
1468 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1472 for (i = 0; i < demux->num_streams; ++i) {
1473 AsfStream *stream = &demux->stream[i];
1475 if (stream->payloads->len > 0) {
1477 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1478 !stream->active && /* do not inspect active streams (caps were already set) */
1479 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1480 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1481 /* try to gather some more data */
1484 /* we don't check mutual exclusion stuff here; either we have data for
1485 * a stream, then we active it, or we don't, then we'll ignore it */
1486 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1487 gst_asf_demux_activate_stream (demux, stream);
1489 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1493 gst_asf_demux_release_old_pads (demux);
1495 demux->activated_streams = TRUE;
1496 GST_LOG_OBJECT (demux, "signalling no more pads");
1497 gst_element_no_more_pads (GST_ELEMENT (demux));
1501 /* returns the stream that has a complete payload with the lowest timestamp
1502 * queued, or NULL (we push things by timestamp because during the internal
1503 * prerolling we might accumulate more data then the external queues can take,
1504 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1506 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1508 AsfPayload *best_payload = NULL;
1509 AsfStream *best_stream = NULL;
1512 for (i = 0; i < demux->num_streams; ++i) {
1516 stream = &demux->stream[i];
1518 /* Don't push any data until we have at least one payload that falls within
1519 * the current segment. This way we can remove out-of-segment payloads that
1520 * don't need to be decoded after a seek, sending only data from the
1521 * keyframe directly before our segment start */
1522 if (stream->payloads->len > 0) {
1523 AsfPayload *payload = NULL;
1526 /* find last payload with timestamp */
1527 for (last_idx = stream->payloads->len - 1;
1528 last_idx >= 0 && (payload == NULL
1529 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1530 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1533 /* if this is first payload after seek we might need to update the segment */
1534 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1535 gst_asf_demux_check_segment_ts (demux, payload->ts);
1537 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1538 (payload->ts < demux->segment.start))) {
1539 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1540 GST_DEBUG_OBJECT (stream->pad,
1541 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1542 GST_TIME_ARGS (payload->ts));
1543 demux->segment.start = payload->ts;
1544 demux->segment.time = payload->ts;
1546 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1547 GST_TIME_FORMAT " which is before our segment start %"
1548 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1549 GST_TIME_ARGS (demux->segment.start));
1554 /* Now see if there's a complete payload queued for this stream */
1557 /* find first complete payload with timestamp */
1559 j < stream->payloads->len && (payload == NULL
1560 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1561 payload = &g_array_index (stream->payloads, AsfPayload, j);
1564 if (!gst_asf_payload_is_complete (payload))
1567 /* ... and whether its timestamp is lower than the current best */
1568 if (best_stream == NULL || best_payload->ts > payload->ts) {
1569 best_stream = stream;
1570 best_payload = payload;
1578 static GstFlowReturn
1579 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1582 GstFlowReturn ret = GST_FLOW_OK;
1584 if (G_UNLIKELY (!demux->activated_streams)) {
1585 if (!gst_asf_demux_check_activate_streams (demux, force))
1587 /* streams are now activated */
1590 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1591 AsfPayload *payload;
1593 /* wait until we had a chance to "lock on" some payload's timestamp */
1594 if (G_UNLIKELY (demux->need_newsegment
1595 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1598 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1600 /* do we need to send a newsegment event */
1601 if ((G_UNLIKELY (demux->need_newsegment))) {
1602 GstEvent *segment_event;
1604 /* safe default if insufficient upstream info */
1605 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1608 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1609 demux->segment.duration > 0) {
1610 /* slight HACK; prevent clipping of last bit */
1611 demux->segment.stop = demux->segment.duration + demux->in_gap;
1614 /* FIXME : only if ACCURATE ! */
1615 if (G_LIKELY (!demux->accurate
1616 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1617 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1618 GST_TIME_ARGS (payload->ts));
1619 demux->segment.start = payload->ts;
1620 demux->segment.time = payload->ts;
1623 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1626 /* note: we fix up all timestamps to start from 0, so this should be ok */
1627 segment_event = gst_event_new_segment (&demux->segment);
1628 if (demux->segment_seqnum)
1629 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1630 gst_asf_demux_send_event_unlocked (demux, segment_event);
1632 /* now post any global tags we may have found */
1633 if (demux->taglist == NULL) {
1634 demux->taglist = gst_tag_list_new_empty ();
1635 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1638 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1639 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1641 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1642 gst_asf_demux_send_event_unlocked (demux,
1643 gst_event_new_tag (demux->taglist));
1644 demux->taglist = NULL;
1646 demux->need_newsegment = FALSE;
1647 demux->segment_seqnum = 0;
1648 demux->segment_running = TRUE;
1651 /* Do we have tags pending for this stream? */
1652 if (G_UNLIKELY (stream->pending_tags)) {
1653 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1654 gst_pad_push_event (stream->pad,
1655 gst_event_new_tag (stream->pending_tags));
1656 stream->pending_tags = NULL;
1659 /* We have the whole packet now so we should push the packet to
1660 * the src pad now. First though we should check if we need to do
1662 if (G_UNLIKELY (stream->span > 1)) {
1663 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1666 payload->buf = gst_buffer_make_writable (payload->buf);
1668 if (G_LIKELY (!payload->keyframe)) {
1669 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1672 if (G_UNLIKELY (stream->discont)) {
1673 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1674 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1675 stream->discont = FALSE;
1678 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1679 (payload->par_x != stream->par_x) &&
1680 (payload->par_y != stream->par_y))) {
1681 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1682 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1683 stream->par_x = payload->par_x;
1684 stream->par_y = payload->par_y;
1685 stream->caps = gst_caps_make_writable (stream->caps);
1686 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1687 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1688 gst_pad_set_caps (stream->pad, stream->caps);
1691 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1692 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1693 payload->interlaced);
1694 stream->interlaced = payload->interlaced;
1695 stream->caps = gst_caps_make_writable (stream->caps);
1696 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1697 (stream->interlaced ? "mixed" : "progressive"), NULL);
1698 gst_pad_set_caps (stream->pad, stream->caps);
1701 /* (sort of) interpolate timestamps using upstream "frame of reference",
1702 * typically useful for live src, but might (unavoidably) mess with
1703 * position reporting if a live src is playing not so live content
1704 * (e.g. rtspsrc taking some time to fall back to tcp) */
1705 GST_BUFFER_PTS (payload->buf) = payload->ts;
1706 if (GST_BUFFER_PTS_IS_VALID (payload->buf)) {
1707 GST_BUFFER_PTS (payload->buf) += demux->in_gap;
1709 if (payload->duration == GST_CLOCK_TIME_NONE
1710 && stream->ext_props.avg_time_per_frame != 0)
1711 GST_BUFFER_DURATION (payload->buf) =
1712 stream->ext_props.avg_time_per_frame * 100;
1714 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1716 /* FIXME: we should really set durations on buffers if we can */
1718 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1721 if (stream->active) {
1722 if (G_UNLIKELY (stream->first_buffer)) {
1723 if (stream->streamheader != NULL) {
1724 GST_DEBUG_OBJECT (stream->pad,
1725 "Pushing streamheader before first buffer");
1726 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1728 stream->first_buffer = FALSE;
1731 ret = gst_pad_push (stream->pad, payload->buf);
1732 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
1734 gst_buffer_unref (payload->buf);
1737 payload->buf = NULL;
1738 g_array_remove_index (stream->payloads, 0);
1740 /* Break out as soon as we have an issue */
1741 if (G_UNLIKELY (ret != GST_FLOW_OK))
1749 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1753 g_assert (buf != NULL);
1755 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1757 gst_buffer_map (buf, &map, GST_MAP_READ);
1759 /* we return false on buffer too small */
1760 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1761 gst_buffer_unmap (buf, &map);
1765 /* check if it is a header */
1766 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1767 gst_buffer_unmap (buf, &map);
1768 if (obj.id == ASF_OBJ_HEADER) {
1775 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1777 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1778 GstFlowReturn ret = GST_FLOW_OK;
1779 GstBuffer *buf = NULL;
1780 gboolean header = FALSE;
1782 /* TODO maybe we should skip index objects after the data and look
1783 * further for a new header */
1784 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1785 g_assert (buf != NULL);
1786 /* check if it is a header */
1787 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1788 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1789 demux->base_offset = off;
1793 gst_buffer_unref (buf);
1800 gst_asf_demux_loop (GstASFDemux * demux)
1802 GstFlowReturn flow = GST_FLOW_OK;
1803 GstBuffer *buf = NULL;
1805 gboolean sent_eos = FALSE;
1807 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1808 if (!gst_asf_demux_pull_headers (demux)) {
1809 flow = GST_FLOW_ERROR;
1813 gst_asf_demux_pull_indices (demux);
1816 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1818 if (G_UNLIKELY (demux->num_packets != 0
1819 && demux->packet >= demux->num_packets))
1822 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1823 (guint) demux->num_packets);
1825 off = demux->data_offset + (demux->packet * demux->packet_size);
1827 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1828 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1829 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1830 if (flow == GST_FLOW_EOS)
1832 else if (flow == GST_FLOW_FLUSHING) {
1833 GST_DEBUG_OBJECT (demux, "Not fatal");
1839 if (G_LIKELY (demux->speed_packets == 1)) {
1840 GstAsfDemuxParsePacketError err;
1841 err = gst_asf_demux_parse_packet (demux, buf);
1842 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1843 /* when we don't know when the data object ends, we should check
1844 * for a chained asf */
1845 if (demux->num_packets == 0) {
1846 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1847 GST_INFO_OBJECT (demux, "Chained asf found");
1848 demux->base_offset = off;
1849 gst_asf_demux_reset (demux, TRUE);
1850 gst_buffer_unref (buf);
1854 /* FIXME: We should tally up fatal errors and error out only
1855 * after a few broken packets in a row? */
1857 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1858 gst_buffer_unref (buf);
1863 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1869 for (n = 0; n < demux->speed_packets; n++) {
1871 GstAsfDemuxParsePacketError err;
1874 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1875 n * demux->packet_size, demux->packet_size);
1876 err = gst_asf_demux_parse_packet (demux, sub);
1877 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1878 /* when we don't know when the data object ends, we should check
1879 * for a chained asf */
1880 if (demux->num_packets == 0) {
1881 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1882 GST_INFO_OBJECT (demux, "Chained asf found");
1883 demux->base_offset = off + n * demux->packet_size;
1884 gst_asf_demux_reset (demux, TRUE);
1885 gst_buffer_unref (sub);
1886 gst_buffer_unref (buf);
1890 /* FIXME: We should tally up fatal errors and error out only
1891 * after a few broken packets in a row? */
1893 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1897 gst_buffer_unref (sub);
1899 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1900 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1906 /* reset speed pull */
1907 demux->speed_packets = 1;
1910 gst_buffer_unref (buf);
1912 if (G_UNLIKELY (demux->num_packets > 0
1913 && demux->packet >= demux->num_packets)) {
1914 GST_LOG_OBJECT (demux, "reached EOS");
1918 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1919 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1923 /* check if we're at the end of the configured segment */
1924 /* FIXME: check if segment end reached etc. */
1930 /* if we haven't activated our streams yet, this might be because we have
1931 * less data queued than required for preroll; force stream activation and
1932 * send any pending payloads before sending EOS */
1933 if (!demux->activated_streams)
1934 gst_asf_demux_push_complete_payloads (demux, TRUE);
1936 /* we want to push an eos or post a segment-done in any case */
1937 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1940 /* for segment playback we need to post when (in stream time)
1941 * we stopped, this is either stop (when set) or the duration. */
1942 if ((stop = demux->segment.stop) == -1)
1943 stop = demux->segment.duration;
1945 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1946 gst_element_post_message (GST_ELEMENT_CAST (demux),
1947 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1949 gst_asf_demux_send_event_unlocked (demux,
1950 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1951 } else if (flow != GST_FLOW_EOS) {
1952 /* check if we have a chained asf, in case, we don't eos yet */
1953 if (gst_asf_demux_check_chained_asf (demux)) {
1954 GST_INFO_OBJECT (demux, "Chained ASF starting");
1955 gst_asf_demux_reset (demux, TRUE);
1959 /* normal playback, send EOS to all linked pads */
1960 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1961 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1963 /* ... and fall through to pause */
1967 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1968 gst_flow_get_name (flow));
1969 demux->segment_running = FALSE;
1970 gst_pad_pause_task (demux->sinkpad);
1972 /* For the error cases (not EOS) */
1974 if (flow == GST_FLOW_EOS)
1975 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1976 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1977 /* Post an error. Hopefully something else already has, but if not... */
1978 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1979 (_("Internal data stream error.")),
1980 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1989 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1990 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1991 flow = GST_FLOW_EOS;
1995 /* See FIXMEs above */
1998 gst_buffer_unref (buf);
1999 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2000 ("Error parsing ASF packet %u", (guint) demux->packet));
2001 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2002 flow = GST_FLOW_ERROR;
2008 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2009 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2010 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2013 gst_asf_demux_check_header (GstASFDemux * demux)
2016 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2017 ASF_OBJECT_HEADER_SIZE);
2018 if (cdata == NULL) /* need more data */
2019 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2021 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2022 if (obj.id != ASF_OBJ_HEADER) {
2023 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2025 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2029 static GstFlowReturn
2030 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2032 GstFlowReturn ret = GST_FLOW_OK;
2035 demux = GST_ASF_DEMUX (parent);
2037 GST_LOG_OBJECT (demux,
2038 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2039 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2040 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2042 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2043 GST_DEBUG_OBJECT (demux, "received DISCONT");
2044 gst_asf_demux_mark_discont (demux);
2047 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2048 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2049 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2050 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2051 ", interpolation gap: %" GST_TIME_FORMAT,
2052 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2055 gst_adapter_push (demux->adapter, buf);
2057 switch (demux->state) {
2058 case GST_ASF_DEMUX_STATE_INDEX:{
2059 gint result = gst_asf_demux_check_header (demux);
2060 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2063 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2064 /* we don't care about this, probably an index */
2065 /* TODO maybe would be smarter to skip all the indices
2066 * until we got a new header or EOS to decide */
2067 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2070 GST_INFO_OBJECT (demux, "Chained asf starting");
2071 /* cleanup and get ready for a chained asf */
2072 gst_asf_demux_reset (demux, TRUE);
2076 case GST_ASF_DEMUX_STATE_HEADER:{
2077 ret = gst_asf_demux_chain_headers (demux);
2078 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2080 /* otherwise fall through */
2082 case GST_ASF_DEMUX_STATE_DATA:
2086 data_size = demux->packet_size;
2088 while (gst_adapter_available (demux->adapter) >= data_size) {
2090 GstAsfDemuxParsePacketError err;
2092 /* we don't know the length of the stream
2093 * check for a chained asf everytime */
2094 if (demux->num_packets == 0) {
2095 gint result = gst_asf_demux_check_header (demux);
2097 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2098 GST_INFO_OBJECT (demux, "Chained asf starting");
2099 /* cleanup and get ready for a chained asf */
2100 gst_asf_demux_reset (demux, TRUE);
2103 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2104 && demux->packet >= demux->num_packets)) {
2105 /* do not overshoot data section when streaming */
2109 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2111 /* FIXME: We should tally up fatal errors and error out only
2112 * after a few broken packets in a row? */
2113 err = gst_asf_demux_parse_packet (demux, buf);
2115 gst_buffer_unref (buf);
2117 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2118 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2120 GST_WARNING_OBJECT (demux, "Parse error");
2122 if (demux->packet >= 0)
2125 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2126 && demux->packet >= demux->num_packets)) {
2127 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2132 g_assert_not_reached ();
2136 if (ret != GST_FLOW_OK)
2137 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2143 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2149 static inline gboolean
2150 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2152 if (*p_size < num_bytes)
2155 *p_data += num_bytes;
2156 *p_size -= num_bytes;
2160 static inline guint8
2161 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2165 g_assert (*p_size >= 1);
2166 ret = GST_READ_UINT8 (*p_data);
2167 *p_data += sizeof (guint8);
2168 *p_size -= sizeof (guint8);
2172 static inline guint16
2173 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2177 g_assert (*p_size >= 2);
2178 ret = GST_READ_UINT16_LE (*p_data);
2179 *p_data += sizeof (guint16);
2180 *p_size -= sizeof (guint16);
2184 static inline guint32
2185 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2189 g_assert (*p_size >= 4);
2190 ret = GST_READ_UINT32_LE (*p_data);
2191 *p_data += sizeof (guint32);
2192 *p_size -= sizeof (guint32);
2196 static inline guint64
2197 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2201 g_assert (*p_size >= 8);
2202 ret = GST_READ_UINT64_LE (*p_data);
2203 *p_data += sizeof (guint64);
2204 *p_size -= sizeof (guint64);
2209 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2210 guint8 ** p_data, guint64 * p_size)
2214 if (*p_size < num_bytes_to_read)
2217 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2218 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2220 *p_data += num_bytes_to_read;
2221 *p_size -= num_bytes_to_read;
2227 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2228 guint8 ** p_data, guint64 * p_size)
2232 if (*p_size < num_bytes_to_read)
2235 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2236 *p_data += num_bytes_to_read;
2237 *p_size -= num_bytes_to_read;
2242 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2243 guint8 ** p_data, guint64 * p_size)
2253 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2256 *p_strlen = s_length;
2258 if (s_length == 0) {
2259 GST_WARNING ("zero-length string");
2260 *p_str = g_strdup ("");
2264 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2267 g_assert (s != NULL);
2269 /* just because They don't exist doesn't
2270 * mean They are not out to get you ... */
2271 if (s[s_length - 1] != '\0') {
2272 s = g_realloc (s, s_length + 1);
2276 *p_str = (gchar *) s;
2282 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2284 g_assert (*p_size >= 4 * sizeof (guint32));
2286 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2287 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2288 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2289 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2293 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2296 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2299 /* WAVEFORMATEX Structure */
2300 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2301 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2302 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2303 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2304 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2305 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2306 /* Codec specific data size */
2307 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2312 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2315 if (*p_size < (4 + 4 + 1 + 2))
2318 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2319 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2320 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2321 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2326 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2327 guint8 ** p_data, guint64 * p_size)
2329 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2332 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2333 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2334 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2335 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2336 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2337 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2338 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2339 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2340 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2341 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2342 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2347 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2351 for (i = 0; i < demux->num_streams; i++) {
2352 if (demux->stream[i].id == id)
2353 return &demux->stream[i];
2356 if (gst_asf_demux_is_unknown_stream (demux, id))
2357 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2362 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2363 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2368 gst_pad_use_fixed_caps (src_pad);
2369 gst_pad_set_caps (src_pad, caps);
2371 gst_pad_set_event_function (src_pad,
2372 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2373 gst_pad_set_query_function (src_pad,
2374 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2376 stream = &demux->stream[demux->num_streams];
2377 stream->caps = caps;
2378 stream->pad = src_pad;
2380 stream->fps_known = !is_video; /* bit hacky for audio */
2381 stream->is_video = is_video;
2382 stream->pending_tags = tags;
2383 stream->discont = TRUE;
2384 stream->first_buffer = TRUE;
2385 stream->streamheader = streamheader;
2386 if (stream->streamheader) {
2387 stream->streamheader = gst_buffer_make_writable (streamheader);
2388 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2393 st = gst_caps_get_structure (caps, 0);
2394 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2395 par_x > 0 && par_y > 0) {
2396 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2397 stream->par_x = par_x;
2398 stream->par_y = par_y;
2402 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2404 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2405 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2407 ++demux->num_streams;
2409 stream->active = FALSE;
2415 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2416 GstBuffer * buffer, GstStructure * structure)
2418 GValue arr_val = G_VALUE_INIT;
2419 GValue buf_val = G_VALUE_INIT;
2421 g_value_init (&arr_val, GST_TYPE_ARRAY);
2422 g_value_init (&buf_val, GST_TYPE_BUFFER);
2424 gst_value_set_buffer (&buf_val, buffer);
2425 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2427 gst_structure_take_value (structure, "streamheader", &arr_val);
2431 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2432 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2434 GstTagList *tags = NULL;
2435 GstBuffer *extradata = NULL;
2438 guint16 size_left = 0;
2439 gchar *codec_name = NULL;
2442 size_left = audio->size;
2444 /* Create the audio pad */
2445 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2447 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2450 /* Swallow up any left over data and set up the
2451 * standard properties from the header info */
2453 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2454 "codec specific data", size_left);
2456 g_assert (size_left <= *p_size);
2457 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2460 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2461 * additional two bytes indicating extradata. */
2462 /* FIXME: Handle the channel reorder map here */
2463 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2464 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2467 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2468 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2471 /* Informing about that audio format we just added */
2473 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2474 g_free (codec_name);
2478 gst_buffer_unref (extradata);
2480 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2481 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2482 audio->codec_tag, tags);
2484 ++demux->num_audio_streams;
2486 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2490 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2491 asf_stream_video_format * video, guint16 id,
2492 guint8 ** p_data, guint64 * p_size)
2494 GstTagList *tags = NULL;
2495 GstStructure *caps_s;
2496 GstBuffer *extradata = NULL;
2501 gchar *codec_name = NULL;
2502 gint size_left = video->size - 40;
2503 GstBuffer *streamheader = NULL;
2504 guint par_w = 1, par_h = 1;
2506 /* Create the video pad */
2507 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2508 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2511 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2513 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2514 g_assert (size_left <= *p_size);
2515 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2518 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2520 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2521 caps = gst_riff_create_video_caps (video->tag, NULL,
2522 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2525 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2526 G_TYPE_UINT, video->tag, NULL);
2531 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2532 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2533 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2536 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2540 /* retry with the global metadata */
2541 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2542 demux->global_metadata);
2543 s = demux->global_metadata;
2544 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2545 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2546 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2547 if (ax > 0 && ay > 0) {
2550 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2555 s = gst_caps_get_structure (caps, 0);
2556 gst_structure_remove_field (s, "framerate");
2559 caps_s = gst_caps_get_structure (caps, 0);
2561 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2562 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2563 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2564 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2567 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2568 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2569 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2570 GstBuffer *buf = gst_value_get_buffer (value);
2573 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2574 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2575 /* this looks like a bytestream start */
2576 streamheader = gst_buffer_ref (buf);
2577 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2578 gst_structure_remove_field (caps_s, "codec_data");
2581 gst_buffer_unmap (buf, &mapinfo);
2585 /* For a 3D video, set multiview information into the caps based on
2586 * what was detected during object parsing */
2587 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2588 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2589 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2590 const gchar *mview_mode_str;
2592 switch (demux->asf_3D_mode) {
2593 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2594 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2596 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2597 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2598 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2600 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2601 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2603 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2604 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2605 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2607 case GST_ASF_3D_DUAL_STREAM:{
2608 gboolean is_right_view = FALSE;
2609 /* if Advanced_Mutual_Exclusion object exists, use it
2610 * to figure out which is the left view (lower ID) */
2611 if (demux->mut_ex_streams != NULL) {
2615 length = g_slist_length (demux->mut_ex_streams);
2617 for (i = 0; i < length; i++) {
2620 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2622 GST_DEBUG_OBJECT (demux,
2623 "has Mutual_Exclusion object. stream id in object is %d",
2624 GPOINTER_TO_INT (v_s_id));
2626 if (id > GPOINTER_TO_INT (v_s_id))
2627 is_right_view = TRUE;
2630 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2631 * first video stream encountered has the lower ID */
2632 if (demux->num_video_streams > 0) {
2633 /* This is not the first video stream, assuming right eye view */
2634 is_right_view = TRUE;
2638 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2640 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2647 GST_INFO_OBJECT (demux,
2648 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2651 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2652 if (mview_mode_str != NULL) {
2653 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2654 video->height, par_w, par_h))
2655 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2657 gst_caps_set_simple (caps,
2658 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2659 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2660 GST_FLAG_SET_MASK_EXACT, NULL);
2665 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2666 g_free (codec_name);
2670 gst_buffer_unref (extradata);
2672 GST_INFO ("Adding video stream #%u, id %u, codec %"
2673 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2674 GST_FOURCC_ARGS (video->tag), video->tag);
2676 ++demux->num_video_streams;
2678 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2679 streamheader, tags);
2683 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2685 if (!stream->active) {
2689 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2690 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2691 gst_pad_set_active (stream->pad, TRUE);
2694 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2695 "%03u", stream->id);
2698 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2700 if (gst_event_parse_group_id (event, &demux->group_id))
2701 demux->have_group_id = TRUE;
2703 demux->have_group_id = FALSE;
2704 gst_event_unref (event);
2705 } else if (!demux->have_group_id) {
2706 demux->have_group_id = TRUE;
2707 demux->group_id = gst_util_group_id_next ();
2710 event = gst_event_new_stream_start (stream_id);
2711 if (demux->have_group_id)
2712 gst_event_set_group_id (event, demux->group_id);
2714 gst_pad_push_event (stream->pad, event);
2716 gst_pad_set_caps (stream->pad, stream->caps);
2718 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2719 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2720 stream->active = TRUE;
2725 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2728 AsfCorrectionType correction_type;
2729 AsfStreamType stream_type;
2730 GstClockTime time_offset;
2731 gboolean is_encrypted G_GNUC_UNUSED;
2735 guint stream_specific_size;
2736 guint type_specific_size G_GNUC_UNUSED;
2737 guint unknown G_GNUC_UNUSED;
2738 gboolean inspect_payload = FALSE;
2739 AsfStream *stream = NULL;
2741 /* Get the rest of the header's header */
2742 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2743 goto not_enough_data;
2745 gst_asf_demux_get_guid (&guid, &data, &size);
2746 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2748 gst_asf_demux_get_guid (&guid, &data, &size);
2749 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2751 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2753 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2754 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2756 flags = gst_asf_demux_get_uint16 (&data, &size);
2757 stream_id = flags & 0x7f;
2758 is_encrypted = ! !((flags & 0x8000) << 15);
2759 unknown = gst_asf_demux_get_uint32 (&data, &size);
2761 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2762 stream_id, GST_TIME_ARGS (time_offset));
2764 /* dvr-ms has audio stream declared in stream specific data */
2765 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2766 AsfExtStreamType ext_stream_type;
2767 gst_asf_demux_get_guid (&guid, &data, &size);
2768 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2770 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2771 inspect_payload = TRUE;
2773 gst_asf_demux_get_guid (&guid, &data, &size);
2774 gst_asf_demux_get_uint32 (&data, &size);
2775 gst_asf_demux_get_uint32 (&data, &size);
2776 gst_asf_demux_get_uint32 (&data, &size);
2777 gst_asf_demux_get_guid (&guid, &data, &size);
2778 gst_asf_demux_get_uint32 (&data, &size);
2779 stream_type = ASF_STREAM_AUDIO;
2783 switch (stream_type) {
2784 case ASF_STREAM_AUDIO:{
2785 asf_stream_audio audio_object;
2787 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2788 goto not_enough_data;
2790 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2793 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2796 switch (correction_type) {
2797 case ASF_CORRECTION_ON:{
2798 guint span, packet_size, chunk_size, data_size, silence_data;
2800 GST_INFO ("Using error correction");
2802 if (size < (1 + 2 + 2 + 2 + 1))
2803 goto not_enough_data;
2805 span = gst_asf_demux_get_uint8 (&data, &size);
2806 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2807 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2808 data_size = gst_asf_demux_get_uint16 (&data, &size);
2809 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2811 stream->span = span;
2813 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2814 packet_size, chunk_size, data_size, span, silence_data);
2816 if (stream->span > 1) {
2817 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2818 /* Disable descrambling */
2821 /* FIXME: this else branch was added for
2822 * weird_al_yankovic - the saga begins.asf */
2823 stream->ds_packet_size = packet_size;
2824 stream->ds_chunk_size = chunk_size;
2827 /* Descambling is enabled */
2828 stream->ds_packet_size = packet_size;
2829 stream->ds_chunk_size = chunk_size;
2832 /* Now skip the rest of the silence data */
2834 gst_bytestream_flush (demux->bs, data_size - 1);
2836 /* FIXME: CHECKME. And why -1? */
2837 if (data_size > 1) {
2838 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2839 goto not_enough_data;
2845 case ASF_CORRECTION_OFF:{
2846 GST_INFO ("Error correction off");
2847 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2848 goto not_enough_data;
2852 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2853 ("Audio stream using unknown error correction"));
2860 case ASF_STREAM_VIDEO:{
2861 asf_stream_video_format video_format_object;
2862 asf_stream_video video_object;
2865 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2866 goto not_enough_data;
2868 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2870 GST_INFO ("object is a video stream with %u bytes of "
2871 "additional data", vsize);
2873 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2875 goto not_enough_data;
2878 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
2879 stream_id, &data, &size);
2885 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2887 demux->other_streams =
2888 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
2893 stream->inspect_payload = inspect_payload;
2898 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2899 /* we'll error out later if we found no streams */
2904 static const gchar *
2905 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2909 const gchar *asf_name;
2910 const gchar *gst_name;
2913 "WM/Genre", GST_TAG_GENRE}, {
2914 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2915 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2916 "WM/Picture", GST_TAG_IMAGE}, {
2917 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2918 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2919 "WM/Year", GST_TAG_DATE_TIME}
2920 /* { "WM/Composer", GST_TAG_COMPOSER } */
2925 if (name_utf8 == NULL) {
2926 GST_WARNING ("Failed to convert name to UTF8, skipping");
2930 out = strlen (name_utf8);
2932 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2933 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2934 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2935 return tags[i].gst_name;
2942 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2944 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2948 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2950 if (taglist == NULL)
2953 if (gst_tag_list_is_empty (taglist)) {
2954 gst_tag_list_unref (taglist);
2958 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2959 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
2961 gst_tag_list_unref (demux->taglist);
2962 gst_tag_list_unref (taglist);
2964 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2967 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2968 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2969 #define ASF_DEMUX_DATA_TYPE_BOOL 2
2970 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2973 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2977 const guint8 *img_data = NULL;
2978 guint32 img_data_len = 0;
2979 guint8 pic_type = 0;
2981 gst_byte_reader_init (&r, tag_data, tag_data_len);
2983 /* skip mime type string (we don't trust it and do our own typefinding),
2984 * and also skip the description string, since we don't use it */
2985 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2986 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2987 !gst_byte_reader_skip_string_utf16 (&r) ||
2988 !gst_byte_reader_skip_string_utf16 (&r) ||
2989 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2990 goto not_enough_data;
2994 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2995 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3001 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3002 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3007 /* Extended Content Description Object */
3008 static GstFlowReturn
3009 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3012 /* Other known (and unused) 'text/unicode' metadata available :
3015 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3016 * WMFSDKVersion = 9.00.00.2980
3017 * WMFSDKNeeded = 0.0.0.0000
3018 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3019 * WM/Publisher = 4AD
3021 * WM/ProviderRating = 8
3022 * WM/ProviderStyle = Rock (similar to WM/Genre)
3023 * WM/GenreID (similar to WM/Genre)
3024 * WM/TrackNumber (same as WM/Track but as a string)
3026 * Other known (and unused) 'non-text' metadata available :
3032 * We might want to read WM/TrackNumber and use atoi() if we don't have
3036 GstTagList *taglist;
3037 guint16 blockcount, i;
3038 gboolean content3D = FALSE;
3042 const gchar *interleave_name;
3043 GstASF3DMode interleaving_type;
3044 } stereoscopic_layout_map[] = {
3046 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3047 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3048 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3049 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3050 "DualStream", GST_ASF_3D_DUAL_STREAM}
3052 GST_INFO_OBJECT (demux, "object is an extended content description");
3054 taglist = gst_tag_list_new_empty ();
3056 /* Content Descriptor Count */
3058 goto not_enough_data;
3060 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3062 for (i = 1; i <= blockcount; ++i) {
3063 const gchar *gst_tag_name;
3067 GValue tag_value = { 0, };
3070 gchar *name_utf8 = NULL;
3074 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3075 goto not_enough_data;
3079 goto not_enough_data;
3081 /* Descriptor Value Data Type */
3082 datatype = gst_asf_demux_get_uint16 (&data, &size);
3084 /* Descriptor Value (not really a string, but same thing reading-wise) */
3085 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3087 goto not_enough_data;
3091 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3093 if (name_utf8 != NULL) {
3094 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3096 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3097 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3100 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3103 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3106 /* get rid of tags with empty value */
3107 if (value_utf8 != NULL && *value_utf8 != '\0') {
3108 GST_DEBUG ("string value %s", value_utf8);
3110 value_utf8[out] = '\0';
3112 if (gst_tag_name != NULL) {
3113 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3114 guint year = atoi (value_utf8);
3117 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3118 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3120 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3121 guint id3v1_genre_id;
3122 const gchar *genre_str;
3124 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3125 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3126 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3127 g_free (value_utf8);
3128 value_utf8 = g_strdup (genre_str);
3133 /* convert tag from string to other type if required */
3134 tag_type = gst_tag_get_type (gst_tag_name);
3135 g_value_init (&tag_value, tag_type);
3136 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3137 GValue from_val = { 0, };
3139 g_value_init (&from_val, G_TYPE_STRING);
3140 g_value_set_string (&from_val, value_utf8);
3141 if (!g_value_transform (&from_val, &tag_value)) {
3142 GST_WARNING_OBJECT (demux,
3143 "Could not transform string tag to " "%s tag type %s",
3144 gst_tag_name, g_type_name (tag_type));
3145 g_value_unset (&tag_value);
3147 g_value_unset (&from_val);
3152 GST_DEBUG ("Setting metadata");
3153 g_value_init (&tag_value, G_TYPE_STRING);
3154 g_value_set_string (&tag_value, value_utf8);
3155 /* If we found a stereoscopic marker, look for StereoscopicLayout
3159 if (strncmp ("StereoscopicLayout", name_utf8,
3160 strlen (name_utf8)) == 0) {
3161 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3162 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3164 demux->asf_3D_mode =
3165 stereoscopic_layout_map[i].interleaving_type;
3166 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3170 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3172 demux->asf_3D_mode = GST_ASF_3D_NONE;
3173 GST_INFO_OBJECT (demux, "None 3d type");
3176 } else if (value_utf8 == NULL) {
3177 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3179 GST_DEBUG ("Skipping empty string value for %s",
3180 GST_STR_NULL (gst_tag_name));
3182 g_free (value_utf8);
3185 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3187 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3188 GST_FIXME ("Unhandled byte array tag %s",
3189 GST_STR_NULL (gst_tag_name));
3192 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3198 case ASF_DEMUX_DATA_TYPE_DWORD:{
3199 guint uint_val = GST_READ_UINT32_LE (value);
3201 /* this is the track number */
3202 g_value_init (&tag_value, G_TYPE_UINT);
3204 /* WM/Track counts from 0 */
3205 if (!strcmp (name_utf8, "WM/Track"))
3208 g_value_set_uint (&tag_value, uint_val);
3212 case ASF_DEMUX_DATA_TYPE_BOOL:{
3213 gboolean bool_val = GST_READ_UINT32_LE (value);
3215 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3217 GST_INFO_OBJECT (demux, "This is 3D contents");
3220 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3228 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3233 if (G_IS_VALUE (&tag_value)) {
3235 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3237 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3238 * is supposed to have a 0 base but is often wrongly written to start
3239 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3240 * replace the value added earlier from WM/Track or put it first in
3241 * the list, so that it will get picked up by _get_uint() */
3242 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3243 merge_mode = GST_TAG_MERGE_REPLACE;
3245 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3248 GST_DEBUG ("Setting global metadata %s", name_utf8);
3249 gst_structure_set_value (demux->global_metadata, name_utf8,
3253 g_value_unset (&tag_value);
3262 gst_asf_demux_add_global_tags (demux, taglist);
3269 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3270 gst_tag_list_unref (taglist);
3271 return GST_FLOW_OK; /* not really fatal */
3275 static GstStructure *
3276 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3281 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3283 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3286 s = gst_caps_get_structure (demux->metadata, i);
3287 if (gst_structure_has_name (s, sname))
3291 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3293 /* try lookup again; demux->metadata took ownership of the structure, so we
3294 * can't really make any assumptions about what happened to it, so we can't
3295 * just return it directly after appending it */
3296 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3299 static GstFlowReturn
3300 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3303 guint16 blockcount, i;
3305 GST_INFO_OBJECT (demux, "object is a metadata object");
3307 /* Content Descriptor Count */
3309 goto not_enough_data;
3311 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3313 for (i = 0; i < blockcount; ++i) {
3315 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3316 guint32 data_len, ival;
3319 if (size < (2 + 2 + 2 + 2 + 4))
3320 goto not_enough_data;
3322 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3323 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3324 name_len = gst_asf_demux_get_uint16 (&data, &size);
3325 data_type = gst_asf_demux_get_uint16 (&data, &size);
3326 data_len = gst_asf_demux_get_uint32 (&data, &size);
3328 if (size < name_len + data_len)
3329 goto not_enough_data;
3331 /* convert name to UTF-8 */
3332 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3334 gst_asf_demux_skip_bytes (name_len, &data, &size);
3336 if (name_utf8 == NULL) {
3337 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3338 gst_asf_demux_skip_bytes (data_len, &data, &size);
3342 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3343 gst_asf_demux_skip_bytes (data_len, &data, &size);
3351 goto not_enough_data;
3354 ival = gst_asf_demux_get_uint32 (&data, &size);
3356 /* skip anything else there may be, just in case */
3357 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3359 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3360 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3364 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3370 GST_WARNING ("Unexpected end of data parsing metadata object");
3371 return GST_FLOW_OK; /* not really fatal */
3375 static GstFlowReturn
3376 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3378 GstFlowReturn ret = GST_FLOW_OK;
3379 guint32 i, num_objects;
3380 guint8 unknown G_GNUC_UNUSED;
3382 /* Get the rest of the header's header */
3383 if (size < (4 + 1 + 1))
3384 goto not_enough_data;
3386 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3387 unknown = gst_asf_demux_get_uint8 (&data, &size);
3388 unknown = gst_asf_demux_get_uint8 (&data, &size);
3390 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3392 /* Loop through the header's objects, processing those */
3393 for (i = 0; i < num_objects; ++i) {
3394 GST_INFO_OBJECT (demux, "reading header part %u", i);
3395 ret = gst_asf_demux_process_object (demux, &data, &size);
3396 if (ret != GST_FLOW_OK) {
3397 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3406 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3407 ("short read parsing HEADER object"));
3408 return GST_FLOW_ERROR;
3412 static GstFlowReturn
3413 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3415 guint64 creation_time G_GNUC_UNUSED;
3416 guint64 file_size G_GNUC_UNUSED;
3417 guint64 send_time G_GNUC_UNUSED;
3418 guint64 packets_count, play_time, preroll;
3419 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3421 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3422 goto not_enough_data;
3424 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3425 file_size = gst_asf_demux_get_uint64 (&data, &size);
3426 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3427 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3428 play_time = gst_asf_demux_get_uint64 (&data, &size);
3429 send_time = gst_asf_demux_get_uint64 (&data, &size);
3430 preroll = gst_asf_demux_get_uint64 (&data, &size);
3431 flags = gst_asf_demux_get_uint32 (&data, &size);
3432 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3433 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3434 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3436 demux->broadcast = ! !(flags & 0x01);
3437 demux->seekable = ! !(flags & 0x02);
3439 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3440 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3441 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3443 if (demux->broadcast) {
3444 /* these fields are invalid if the broadcast flag is set */
3449 if (min_pktsize != max_pktsize)
3450 goto non_fixed_packet_size;
3452 demux->packet_size = max_pktsize;
3454 /* FIXME: do we need send_time as well? what is it? */
3455 if ((play_time * 100) >= (preroll * GST_MSECOND))
3456 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3458 demux->play_time = 0;
3460 demux->preroll = preroll * GST_MSECOND;
3462 /* initial latency */
3463 demux->latency = demux->preroll;
3465 if (demux->play_time == 0)
3466 demux->seekable = FALSE;
3468 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3469 GST_TIME_ARGS (demux->play_time));
3470 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3471 GST_TIME_ARGS (demux->preroll));
3473 if (demux->play_time > 0) {
3474 demux->segment.duration = demux->play_time;
3477 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3479 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3484 non_fixed_packet_size:
3486 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3487 ("packet size must be fixed"));
3488 return GST_FLOW_ERROR;
3492 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3493 ("short read parsing FILE object"));
3494 return GST_FLOW_ERROR;
3498 /* Content Description Object */
3499 static GstFlowReturn
3500 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3504 const gchar *gst_tag;
3509 GST_TAG_TITLE, 0, NULL}, {
3510 GST_TAG_ARTIST, 0, NULL}, {
3511 GST_TAG_COPYRIGHT, 0, NULL}, {
3512 GST_TAG_DESCRIPTION, 0, NULL}, {
3513 GST_TAG_COMMENT, 0, NULL}
3515 GstTagList *taglist;
3516 GValue value = { 0 };
3520 GST_INFO_OBJECT (demux, "object is a comment");
3522 if (size < (2 + 2 + 2 + 2 + 2))
3523 goto not_enough_data;
3525 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3526 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3527 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3528 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3529 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3531 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3532 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3533 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3535 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3536 if (size < tags[i].val_length)
3537 goto not_enough_data;
3539 /* might be just '/0', '/0'... */
3540 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3541 /* convert to UTF-8 */
3542 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3543 "UTF-8", "UTF-16LE", &in, &out, NULL);
3545 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3548 /* parse metadata into taglist */
3549 taglist = gst_tag_list_new_empty ();
3550 g_value_init (&value, G_TYPE_STRING);
3551 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3552 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3553 g_value_set_string (&value, tags[i].val_utf8);
3554 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3555 tags[i].gst_tag, &value, NULL);
3558 g_value_unset (&value);
3560 gst_asf_demux_add_global_tags (demux, taglist);
3562 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3563 g_free (tags[i].val_utf8);
3569 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3570 "comment tag section %d, skipping comment object", i);
3571 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3572 g_free (tags[i].val_utf8);
3573 return GST_FLOW_OK; /* not really fatal */
3577 static GstFlowReturn
3578 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3581 guint16 num_streams, i;
3585 goto not_enough_data;
3587 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3589 GST_INFO ("object is a bitrate properties object with %u streams",
3592 if (size < (num_streams * (2 + 4)))
3593 goto not_enough_data;
3595 for (i = 0; i < num_streams; ++i) {
3599 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3600 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3602 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3603 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3604 stream = gst_asf_demux_get_stream (demux, stream_id);
3606 if (stream->pending_tags == NULL) {
3607 stream->pending_tags =
3608 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3611 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3614 GST_WARNING ("stream id %u is too large", stream_id);
3622 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3623 return GST_FLOW_OK; /* not really fatal */
3627 static GstFlowReturn
3628 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3631 GstFlowReturn ret = GST_FLOW_OK;
3634 /* Get the rest of the header's header */
3635 if (size < (16 + 2 + 4))
3636 goto not_enough_data;
3638 /* skip GUID and two other bytes */
3639 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3640 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3642 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3644 /* FIXME: does data_size include the rest of the header that we have read? */
3645 if (hdr_size > size)
3646 goto not_enough_data;
3648 while (hdr_size > 0) {
3649 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3650 if (ret != GST_FLOW_OK)
3658 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3659 ("short read parsing extended header object"));
3660 return GST_FLOW_ERROR;
3664 static GstFlowReturn
3665 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3671 goto not_enough_data;
3673 if (demux->languages) {
3674 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3675 g_strfreev (demux->languages);
3676 demux->languages = NULL;
3677 demux->num_languages = 0;
3680 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3681 GST_LOG ("%u languages:", demux->num_languages);
3683 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3684 for (i = 0; i < demux->num_languages; ++i) {
3685 guint8 len, *lang_data = NULL;
3688 goto not_enough_data;
3689 len = gst_asf_demux_get_uint8 (&data, &size);
3690 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3693 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3696 /* truncate "en-us" etc. to just "en" */
3697 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3700 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3701 demux->languages[i] = utf8;
3704 goto not_enough_data;
3712 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3713 g_free (demux->languages);
3714 demux->languages = NULL;
3715 return GST_FLOW_OK; /* not fatal */
3719 static GstFlowReturn
3720 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3723 GstClockTime interval;
3726 if (size < (16 + 8 + 4 + 4))
3727 goto not_enough_data;
3730 gst_asf_demux_skip_bytes (16, &data, &size);
3731 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3732 gst_asf_demux_skip_bytes (4, &data, &size);
3733 count = gst_asf_demux_get_uint32 (&data, &size);
3735 demux->sidx_interval = interval;
3736 demux->sidx_num_entries = count;
3737 g_free (demux->sidx_entries);
3738 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3740 for (i = 0; i < count; ++i) {
3741 if (G_UNLIKELY (size < 6)) {
3742 /* adjust for broken files, to avoid having entries at the end
3743 * of the parsed index that point to time=0. Resulting in seeking to
3744 * the end of the file leading back to the beginning */
3745 demux->sidx_num_entries -= (count - i);
3748 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3749 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3750 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3751 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3752 demux->sidx_entries[i].count);
3755 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3762 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3763 return GST_FLOW_OK; /* not fatal */
3767 static GstFlowReturn
3768 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3769 guint8 * data, guint64 size)
3774 if (size < 16 + 2 + (2 * 2))
3775 goto not_enough_data;
3777 gst_asf_demux_get_guid (&guid, &data, &size);
3778 num = gst_asf_demux_get_uint16 (&data, &size);
3781 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3785 if (size < (num * sizeof (guint16)))
3786 goto not_enough_data;
3788 /* read mutually exclusive stream numbers */
3789 for (i = 0; i < num; ++i) {
3791 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3792 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3794 demux->mut_ex_streams =
3795 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
3804 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3805 return GST_FLOW_OK; /* not absolutely fatal */
3810 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3812 return g_slist_find (demux->other_streams,
3813 GINT_TO_POINTER (stream_num)) == NULL;
3816 static GstFlowReturn
3817 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3820 AsfStreamExtProps esp;
3821 AsfStream *stream = NULL;
3822 AsfObject stream_obj;
3823 guint16 stream_name_count;
3824 guint16 num_payload_ext;
3826 guint8 *stream_obj_data = NULL;
3829 guint i, stream_num;
3832 obj_size = (guint) size;
3835 goto not_enough_data;
3838 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3839 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3840 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3841 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3842 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3843 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3844 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3845 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3846 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3847 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3848 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3849 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3850 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3851 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3852 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3854 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3855 GST_TIME_ARGS (esp.start_time));
3856 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3857 GST_TIME_ARGS (esp.end_time));
3858 GST_INFO ("flags = %08x", esp.flags);
3859 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3860 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3861 GST_INFO ("stream number = %u", stream_num);
3862 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3863 (esp.lang_idx < demux->num_languages) ?
3864 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3865 GST_INFO ("stream name count = %u", stream_name_count);
3867 /* read stream names */
3868 for (i = 0; i < stream_name_count; ++i) {
3869 guint16 stream_lang_idx G_GNUC_UNUSED;
3870 gchar *stream_name = NULL;
3873 goto not_enough_data;
3874 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3875 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3876 goto not_enough_data;
3877 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3878 g_free (stream_name); /* TODO: store names in struct */
3881 /* read payload extension systems stuff */
3882 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3884 if (num_payload_ext > 0)
3885 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3887 esp.payload_extensions = NULL;
3889 for (i = 0; i < num_payload_ext; ++i) {
3890 AsfPayloadExtension ext;
3892 guint32 sys_info_len;
3894 if (size < 16 + 2 + 4)
3895 goto not_enough_data;
3897 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3898 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3899 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3901 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3902 GST_LOG ("payload systems info len = %u", sys_info_len);
3903 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3904 goto not_enough_data;
3906 esp.payload_extensions[i] = ext;
3909 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3911 /* there might be an optional STREAM_INFO object here now; if not, we
3912 * should have parsed the corresponding stream info object already (since
3913 * we are parsing the extended stream properties objects delayed) */
3915 stream = gst_asf_demux_get_stream (demux, stream_num);
3919 /* get size of the stream object */
3920 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3921 goto not_enough_data;
3923 if (stream_obj.id != ASF_OBJ_STREAM)
3924 goto expected_stream_object;
3926 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3927 stream_obj.size > (10 * 1024 * 1024))
3928 goto not_enough_data;
3930 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3932 /* process this stream object later after all the other 'normal' ones
3933 * have been processed (since the others are more important/non-hidden) */
3934 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3935 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3936 goto not_enough_data;
3938 /* parse stream object */
3939 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3940 g_free (stream_obj_data);
3945 stream->ext_props = esp;
3947 /* try to set the framerate */
3948 if (stream->is_video && stream->caps) {
3949 GValue framerate = { 0 };
3953 g_value_init (&framerate, GST_TYPE_FRACTION);
3955 num = GST_SECOND / 100;
3956 denom = esp.avg_time_per_frame;
3958 /* avoid division by 0, assume 25/1 framerate */
3959 denom = GST_SECOND / 2500;
3962 gst_value_set_fraction (&framerate, num, denom);
3964 stream->caps = gst_caps_make_writable (stream->caps);
3965 s = gst_caps_get_structure (stream->caps, 0);
3966 gst_structure_set_value (s, "framerate", &framerate);
3967 g_value_unset (&framerate);
3968 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3969 num, denom, ((gdouble) num) / denom);
3972 /* add language info now if we have it */
3973 if (stream->ext_props.lang_idx < demux->num_languages) {
3974 if (stream->pending_tags == NULL)
3975 stream->pending_tags = gst_tag_list_new_empty ();
3976 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3977 demux->languages[stream->ext_props.lang_idx]);
3978 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3979 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3982 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
3983 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3991 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3992 return GST_FLOW_OK; /* not absolutely fatal */
3994 expected_stream_object:
3996 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3997 "object: expected embedded stream object, but got %s object instead!",
3998 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3999 return GST_FLOW_OK; /* not absolutely fatal */
4003 static const gchar *
4004 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4008 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4009 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4010 nick += strlen ("ASF_OBJ_");
4012 if (demux->objpath == NULL) {
4013 demux->objpath = g_strdup (nick);
4017 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4018 g_free (demux->objpath);
4019 demux->objpath = newpath;
4022 return (const gchar *) demux->objpath;
4026 gst_asf_demux_pop_obj (GstASFDemux * demux)
4030 if ((s = g_strrstr (demux->objpath, "/"))) {
4033 g_free (demux->objpath);
4034 demux->objpath = NULL;
4039 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4044 /* Parse the queued extended stream property objects and add the info
4045 * to the existing streams or add the new embedded streams, but without
4046 * activating them yet */
4047 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4048 g_slist_length (demux->ext_stream_props));
4050 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4051 GstBuffer *buf = GST_BUFFER (l->data);
4054 gst_buffer_map (buf, &map, GST_MAP_READ);
4056 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4057 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4058 gst_buffer_unmap (buf, &map);
4059 gst_buffer_unref (buf);
4061 g_slist_free (demux->ext_stream_props);
4062 demux->ext_stream_props = NULL;
4067 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4071 for (i = 0; i < demux->num_streams; ++i) {
4076 stream = &demux->stream[i];
4078 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4080 if (stream->active) {
4081 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4086 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4089 /* check for each mutual exclusion whether it affects this stream */
4090 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4091 if (*mes == stream->id) {
4092 /* if yes, check if we've already added streams that are mutually
4093 * exclusive with the stream we're about to add */
4094 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4095 for (j = 0; j < demux->num_streams; ++j) {
4096 /* if the broadcast flag is set, assume the hidden streams aren't
4097 * actually streamed and hide them (or playbin won't work right),
4098 * otherwise assume their data is available */
4099 if (demux->stream[j].id == *mes && demux->broadcast) {
4101 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4102 "mutually exclusive with already existing stream ID %d, "
4103 "hiding stream", stream->id, demux->stream[j].id);
4115 /* FIXME: we should do stream activation based on preroll data in
4116 * streaming mode too */
4117 if (demux->streaming && !is_hidden)
4118 gst_asf_demux_activate_stream (demux, stream);
4123 static GstFlowReturn
4124 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4127 GstFlowReturn ret = GST_FLOW_OK;
4129 guint64 obj_data_size;
4131 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4132 return ASF_FLOW_NEED_MORE_DATA;
4134 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4135 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4137 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4139 if (*p_size < obj_data_size)
4140 return ASF_FLOW_NEED_MORE_DATA;
4142 gst_asf_demux_push_obj (demux, obj.id);
4144 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4147 case ASF_OBJ_STREAM:
4148 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4152 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4154 case ASF_OBJ_HEADER:
4155 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4157 case ASF_OBJ_COMMENT:
4158 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4161 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4163 case ASF_OBJ_BITRATE_PROPS:
4165 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4168 case ASF_OBJ_EXT_CONTENT_DESC:
4170 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4173 case ASF_OBJ_METADATA_OBJECT:
4174 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4176 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4179 /* process these later, we might not have parsed the corresponding
4180 * stream object yet */
4181 GST_LOG ("%s: queued for later parsing", demux->objpath);
4182 buf = gst_buffer_new_and_alloc (obj_data_size);
4183 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4184 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4188 case ASF_OBJ_LANGUAGE_LIST:
4189 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4191 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4192 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4195 case ASF_OBJ_SIMPLE_INDEX:
4196 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4198 case ASF_OBJ_CONTENT_ENCRYPTION:
4199 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4200 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4201 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4202 goto error_encrypted;
4203 case ASF_OBJ_CONCEAL_NONE:
4205 case ASF_OBJ_UNDEFINED:
4206 case ASF_OBJ_CODEC_COMMENT:
4208 case ASF_OBJ_PADDING:
4209 case ASF_OBJ_BITRATE_MUTEX:
4210 case ASF_OBJ_COMPATIBILITY:
4211 case ASF_OBJ_INDEX_PLACEHOLDER:
4212 case ASF_OBJ_INDEX_PARAMETERS:
4213 case ASF_OBJ_STREAM_PRIORITIZATION:
4214 case ASF_OBJ_SCRIPT_COMMAND:
4215 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4217 /* Unknown/unhandled object, skip it and hope for the best */
4218 GST_INFO ("%s: skipping object", demux->objpath);
4223 /* this can't fail, we checked the number of bytes available before */
4224 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4226 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4228 gst_asf_demux_pop_obj (demux);
4235 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4236 return GST_FLOW_ERROR;
4241 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4242 GstBuffer ** p_buffer)
4244 GstBuffer *descrambled_buffer;
4245 GstBuffer *scrambled_buffer;
4246 GstBuffer *sub_buffer;
4253 /* descrambled_buffer is initialised in the first iteration */
4254 descrambled_buffer = NULL;
4255 scrambled_buffer = *p_buffer;
4257 if (gst_buffer_get_size (scrambled_buffer) <
4258 stream->ds_packet_size * stream->span)
4261 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4262 offset += stream->ds_chunk_size) {
4263 off = offset / stream->ds_chunk_size;
4264 row = off / stream->span;
4265 col = off % stream->span;
4266 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4267 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4268 col, off, stream->ds_chunk_size);
4269 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4270 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4271 stream->span, stream->ds_packet_size);
4272 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4273 gst_buffer_get_size (scrambled_buffer));
4275 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4276 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4278 descrambled_buffer = sub_buffer;
4280 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4284 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4285 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4286 GST_BUFFER_DURATION (descrambled_buffer) =
4287 GST_BUFFER_DURATION (scrambled_buffer);
4288 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4289 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4290 GST_BUFFER_OFFSET_END (scrambled_buffer);
4292 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4294 gst_buffer_unref (scrambled_buffer);
4295 *p_buffer = descrambled_buffer;
4299 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4301 GstASFDemux *demux = GST_ASF_DEMUX (element);
4304 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4306 for (i = 0; i < demux->num_streams; ++i) {
4307 gst_event_ref (event);
4308 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4309 GST_OBJECT_CAST (element), event)) {
4310 gst_event_unref (event);
4315 gst_event_unref (event);
4319 /* takes ownership of the passed event */
4321 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4323 gboolean ret = TRUE;
4326 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4327 GST_EVENT_TYPE_NAME (event));
4329 for (i = 0; i < demux->num_streams; ++i) {
4330 gst_event_ref (event);
4331 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4333 gst_event_unref (event);
4338 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4342 gboolean res = FALSE;
4344 demux = GST_ASF_DEMUX (parent);
4346 GST_DEBUG ("handling %s query",
4347 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4349 switch (GST_QUERY_TYPE (query)) {
4350 case GST_QUERY_DURATION:
4354 gst_query_parse_duration (query, &format, NULL);
4356 if (format != GST_FORMAT_TIME) {
4357 GST_LOG ("only support duration queries in TIME format");
4361 res = gst_pad_query_default (pad, parent, query);
4363 GST_OBJECT_LOCK (demux);
4365 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4366 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4367 GST_TIME_ARGS (demux->segment.duration));
4369 gst_query_set_duration (query, GST_FORMAT_TIME,
4370 demux->segment.duration);
4374 GST_LOG ("duration not known yet");
4377 GST_OBJECT_UNLOCK (demux);
4382 case GST_QUERY_POSITION:{
4385 gst_query_parse_position (query, &format, NULL);
4387 if (format != GST_FORMAT_TIME) {
4388 GST_LOG ("only support position queries in TIME format");
4392 GST_OBJECT_LOCK (demux);
4394 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4395 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4396 GST_TIME_ARGS (demux->segment.position));
4398 gst_query_set_position (query, GST_FORMAT_TIME,
4399 demux->segment.position);
4403 GST_LOG ("position not known yet");
4406 GST_OBJECT_UNLOCK (demux);
4410 case GST_QUERY_SEEKING:{
4413 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4414 if (format == GST_FORMAT_TIME) {
4417 GST_OBJECT_LOCK (demux);
4418 duration = demux->segment.duration;
4419 GST_OBJECT_UNLOCK (demux);
4421 if (!demux->streaming || !demux->seekable) {
4422 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4429 /* try upstream first in TIME */
4430 res = gst_pad_query_default (pad, parent, query);
4432 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4433 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4434 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4435 /* if no luck, maybe in BYTES */
4436 if (!seekable || fmt != GST_FORMAT_TIME) {
4439 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4440 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4441 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4442 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4443 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4444 if (fmt != GST_FORMAT_BYTES)
4447 gst_query_unref (q);
4448 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4454 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4458 case GST_QUERY_LATENCY:
4461 GstClockTime min, max;
4463 /* preroll delay does not matter in non-live pipeline,
4464 * but we might end up in a live (rtsp) one ... */
4467 res = gst_pad_query_default (pad, parent, query);
4471 gst_query_parse_latency (query, &live, &min, &max);
4473 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4474 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4475 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4477 GST_OBJECT_LOCK (demux);
4478 min += demux->latency;
4480 max += demux->latency;
4481 GST_OBJECT_UNLOCK (demux);
4483 gst_query_set_latency (query, live, min, max);
4486 case GST_QUERY_SEGMENT:
4491 format = demux->segment.format;
4494 gst_segment_to_stream_time (&demux->segment, format,
4495 demux->segment.start);
4496 if ((stop = demux->segment.stop) == -1)
4497 stop = demux->segment.duration;
4499 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4501 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4506 res = gst_pad_query_default (pad, parent, query);
4513 static GstStateChangeReturn
4514 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4516 GstASFDemux *demux = GST_ASF_DEMUX (element);
4517 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4519 switch (transition) {
4520 case GST_STATE_CHANGE_NULL_TO_READY:{
4521 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4522 demux->need_newsegment = TRUE;
4523 demux->segment_running = FALSE;
4524 demux->accurate = FALSE;
4525 demux->adapter = gst_adapter_new ();
4526 demux->metadata = gst_caps_new_empty ();
4527 demux->global_metadata = gst_structure_new_empty ("metadata");
4528 demux->data_size = 0;
4529 demux->data_offset = 0;
4530 demux->index_offset = 0;
4531 demux->base_offset = 0;
4532 demux->flowcombiner = gst_flow_combiner_new ();
4539 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4540 if (ret == GST_STATE_CHANGE_FAILURE)
4543 switch (transition) {
4544 case GST_STATE_CHANGE_PAUSED_TO_READY:
4545 gst_asf_demux_reset (demux, FALSE);
4548 case GST_STATE_CHANGE_READY_TO_NULL:
4549 gst_asf_demux_reset (demux, FALSE);
4550 gst_flow_combiner_free (demux->flowcombiner);
4551 demux->flowcombiner = NULL;