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 GstFlowReturn * pflow);
104 static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109 AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
123 GstElementClass *gstelement_class;
125 gstelement_class = (GstElementClass *) klass;
127 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
129 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 gst_element_class_add_static_pad_template (gstelement_class,
132 &audio_src_template);
133 gst_element_class_add_static_pad_template (gstelement_class,
134 &video_src_template);
135 gst_element_class_add_static_pad_template (gstelement_class,
136 &gst_asf_demux_sink_template);
138 gstelement_class->change_state =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140 gstelement_class->send_event =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 gst_caps_replace (&stream->caps, NULL);
148 if (stream->pending_tags) {
149 gst_tag_list_unref (stream->pending_tags);
150 stream->pending_tags = NULL;
152 if (stream->streamheader) {
153 gst_buffer_unref (stream->streamheader);
154 stream->streamheader = NULL;
157 if (stream->active) {
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
161 gst_object_unref (stream->pad);
165 if (stream->payloads) {
166 while (stream->payloads->len > 0) {
170 last = stream->payloads->len - 1;
171 payload = &g_array_index (stream->payloads, AsfPayload, last);
172 gst_buffer_replace (&payload->buf, NULL);
173 g_array_remove_index (stream->payloads, last);
175 g_array_free (stream->payloads, TRUE);
176 stream->payloads = NULL;
179 if (stream->payloads_rev) {
180 while (stream->payloads_rev->len > 0) {
184 last = stream->payloads_rev->len - 1;
185 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186 gst_buffer_replace (&payload->buf, NULL);
187 g_array_remove_index (stream->payloads_rev, last);
189 g_array_free (stream->payloads_rev, TRUE);
190 stream->payloads_rev = NULL;
193 if (stream->ext_props.valid) {
194 g_free (stream->ext_props.payload_extensions);
195 stream->ext_props.payload_extensions = NULL;
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
202 GST_LOG_OBJECT (demux, "resetting");
204 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205 demux->segment_running = FALSE;
206 if (demux->adapter && !chain_reset) {
207 gst_adapter_clear (demux->adapter);
208 g_object_unref (demux->adapter);
209 demux->adapter = NULL;
211 if (demux->taglist) {
212 gst_tag_list_unref (demux->taglist);
213 demux->taglist = NULL;
215 if (demux->metadata) {
216 gst_caps_unref (demux->metadata);
217 demux->metadata = NULL;
219 if (demux->global_metadata) {
220 gst_structure_free (demux->global_metadata);
221 demux->global_metadata = NULL;
223 if (demux->mut_ex_streams) {
224 g_slist_free (demux->mut_ex_streams);
225 demux->mut_ex_streams = NULL;
228 demux->state = GST_ASF_DEMUX_STATE_HEADER;
229 g_free (demux->objpath);
230 demux->objpath = NULL;
231 g_strfreev (demux->languages);
232 demux->languages = NULL;
233 demux->num_languages = 0;
234 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
236 g_slist_free (demux->ext_stream_props);
237 demux->ext_stream_props = NULL;
239 while (demux->old_num_streams > 0) {
240 gst_asf_demux_free_stream (demux,
241 &demux->old_stream[demux->old_num_streams - 1]);
242 --demux->old_num_streams;
244 memset (demux->old_stream, 0, sizeof (demux->old_stream));
245 demux->old_num_streams = 0;
247 /* when resetting for a new chained asf, we don't want to remove the pads
248 * before adding the new ones */
250 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251 demux->old_num_streams = demux->num_streams;
252 demux->num_streams = 0;
255 while (demux->num_streams > 0) {
256 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257 --demux->num_streams;
259 memset (demux->stream, 0, sizeof (demux->stream));
261 /* do not remove those for not adding pads with same name */
262 demux->num_audio_streams = 0;
263 demux->num_video_streams = 0;
264 demux->have_group_id = FALSE;
265 demux->group_id = G_MAXUINT;
267 demux->num_streams = 0;
268 demux->activated_streams = FALSE;
269 demux->first_ts = GST_CLOCK_TIME_NONE;
270 demux->segment_ts = GST_CLOCK_TIME_NONE;
273 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274 demux->state = GST_ASF_DEMUX_STATE_HEADER;
275 demux->seekable = FALSE;
276 demux->broadcast = FALSE;
277 demux->sidx_interval = 0;
278 demux->sidx_num_entries = 0;
279 g_free (demux->sidx_entries);
280 demux->sidx_entries = NULL;
282 demux->speed_packets = 1;
284 demux->asf_3D_mode = GST_ASF_3D_NONE;
287 GST_LOG_OBJECT (demux, "Restarting");
288 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289 demux->need_newsegment = TRUE;
290 demux->segment_seqnum = 0;
291 demux->segment_running = FALSE;
292 demux->keyunit_sync = FALSE;
293 demux->accurate = FALSE;
294 demux->metadata = gst_caps_new_empty ();
295 demux->global_metadata = gst_structure_new_empty ("metadata");
296 demux->data_size = 0;
297 demux->data_offset = 0;
298 demux->index_offset = 0;
300 demux->base_offset = 0;
303 g_slist_free (demux->other_streams);
304 demux->other_streams = NULL;
308 gst_asf_demux_init (GstASFDemux * demux)
311 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312 gst_pad_set_chain_function (demux->sinkpad,
313 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314 gst_pad_set_event_function (demux->sinkpad,
315 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316 gst_pad_set_activate_function (demux->sinkpad,
317 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318 gst_pad_set_activatemode_function (demux->sinkpad,
319 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
322 /* set initial state */
323 gst_asf_demux_reset (demux, FALSE);
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
332 query = gst_query_new_scheduling ();
334 if (!gst_pad_peer_query (sinkpad, query)) {
335 gst_query_unref (query);
339 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341 gst_query_unref (query);
346 GST_DEBUG_OBJECT (sinkpad, "activating pull");
347 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
351 GST_DEBUG_OBJECT (sinkpad, "activating push");
352 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358 GstPadMode mode, gboolean active)
363 demux = GST_ASF_DEMUX (parent);
366 case GST_PAD_MODE_PUSH:
367 demux->state = GST_ASF_DEMUX_STATE_HEADER;
368 demux->streaming = TRUE;
371 case GST_PAD_MODE_PULL:
373 demux->state = GST_ASF_DEMUX_STATE_HEADER;
374 demux->streaming = FALSE;
376 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
379 res = gst_pad_stop_task (sinkpad);
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
395 demux = GST_ASF_DEMUX (parent);
397 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398 switch (GST_EVENT_TYPE (event)) {
399 case GST_EVENT_SEGMENT:{
400 const GstSegment *segment;
402 gst_event_parse_segment (event, &segment);
404 if (segment->format == GST_FORMAT_BYTES) {
405 if (demux->packet_size && segment->start > demux->data_offset)
406 demux->packet = (segment->start - demux->data_offset) /
410 } else if (segment->format == GST_FORMAT_TIME) {
411 /* do not know packet position, not really a problem */
414 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415 gst_event_unref (event);
419 /* record upstream segment for interpolation */
420 if (segment->format != demux->in_segment.format)
421 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422 gst_segment_copy_into (segment, &demux->in_segment);
424 /* in either case, clear some state and generate newsegment later on */
425 GST_OBJECT_LOCK (demux);
426 demux->segment_ts = GST_CLOCK_TIME_NONE;
427 demux->in_gap = GST_CLOCK_TIME_NONE;
428 demux->need_newsegment = TRUE;
429 demux->segment_seqnum = gst_event_get_seqnum (event);
430 gst_asf_demux_reset_stream_state_after_discont (demux);
431 /* if we seek back after reaching EOS, go back to packet reading state */
432 if (demux->data_offset > 0 && segment->start >= demux->data_offset
433 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
434 demux->state = GST_ASF_DEMUX_STATE_DATA;
436 GST_OBJECT_UNLOCK (demux);
438 gst_event_unref (event);
444 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
446 (_("This stream contains no data.")),
447 ("got eos and didn't receive a complete header object"));
450 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
451 if (!demux->activated_streams) {
452 /* If we still haven't got activated streams, the file is most likely corrupt */
453 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
454 (_("This stream contains no data.")),
455 ("got eos and didn't receive a complete header object"));
458 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
459 GST_ELEMENT_FLOW_ERROR (demux, flow);
463 GST_OBJECT_LOCK (demux);
464 gst_adapter_clear (demux->adapter);
465 GST_OBJECT_UNLOCK (demux);
466 gst_asf_demux_send_event_unlocked (demux, event);
470 case GST_EVENT_FLUSH_STOP:
471 GST_OBJECT_LOCK (demux);
472 gst_asf_demux_reset_stream_state_after_discont (demux);
473 GST_OBJECT_UNLOCK (demux);
474 gst_asf_demux_send_event_unlocked (demux, event);
475 /* upon activation, latency is no longer introduced, e.g. after seek */
476 if (demux->activated_streams)
481 ret = gst_pad_event_default (pad, parent, event);
489 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
490 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
491 gboolean next, gboolean * eos)
493 GstClockTime idx_time;
499 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
502 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
505 /* if we want the next keyframe, we have to go forward till we find
506 a different packet number */
508 if (idx >= demux->sidx_num_entries - 1) {
509 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
514 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
515 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
522 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
528 *packet = demux->sidx_entries[idx].packet;
530 *speed = demux->sidx_entries[idx].count;
532 /* so we get closer to the actual time of the packet ... actually, let's not
533 * do this, since we throw away superfluous payloads before the seek position
534 * anyway; this way, our key unit seek 'snap resolution' is a bit better
535 * (ie. same as index resolution) */
537 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
541 idx_time = demux->sidx_interval * idx;
542 if (G_LIKELY (idx_time >= demux->preroll))
543 idx_time -= demux->preroll;
545 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
546 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
547 GST_TIME_ARGS (idx_time));
549 if (G_LIKELY (p_idx_time))
550 *p_idx_time = idx_time;
556 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
560 gst_adapter_clear (demux->adapter);
562 GST_DEBUG_OBJECT (demux, "reset stream state");
564 gst_flow_combiner_reset (demux->flowcombiner);
565 for (n = 0; n < demux->num_streams; n++) {
566 demux->stream[n].discont = TRUE;
567 demux->stream[n].first_buffer = TRUE;
569 while (demux->stream[n].payloads->len > 0) {
573 last = demux->stream[n].payloads->len - 1;
574 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
575 gst_buffer_replace (&payload->buf, NULL);
576 g_array_remove_index (demux->stream[n].payloads, last);
582 gst_asf_demux_mark_discont (GstASFDemux * demux)
586 GST_DEBUG_OBJECT (demux, "Mark stream discont");
588 for (n = 0; n < demux->num_streams; n++)
589 demux->stream[n].discont = TRUE;
592 /* do a seek in push based mode */
594 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
599 GstSeekType cur_type, stop_type;
603 GstEvent *byte_event;
605 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
608 stop_type = GST_SEEK_TYPE_NONE;
611 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
613 /* determine packet, by index or by estimation */
614 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
617 (guint) gst_util_uint64_scale (demux->num_packets, cur,
621 if (packet > demux->num_packets) {
622 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
627 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
629 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
631 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
632 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
633 /* BYTE seek event */
634 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
635 cur, stop_type, stop);
636 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
637 res = gst_pad_push_event (demux->sinkpad, byte_event);
643 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
645 GstClockTime idx_time;
648 GstSeekType cur_type, stop_type;
650 gboolean only_need_update;
651 gboolean after, before, next;
656 guint packet, speed_count = 1;
662 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
665 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
666 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
670 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
671 * so first try to let it handle the seek event. */
672 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
675 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
676 demux->num_packets == 0 || demux->play_time == 0)) {
677 GST_LOG_OBJECT (demux, "stream is not seekable");
681 if (G_UNLIKELY (!demux->activated_streams)) {
682 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
686 if (G_UNLIKELY (rate <= 0.0)) {
687 GST_LOG_OBJECT (demux, "backward playback");
688 demux->seek_to_cur_pos = TRUE;
689 for (i = 0; i < demux->num_streams; i++) {
690 demux->stream[i].reverse_kf_ready = FALSE;
694 seqnum = gst_event_get_seqnum (event);
695 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
697 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
698 demux->keyunit_sync =
699 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
700 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
701 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
702 next = after && !before;
704 if (G_UNLIKELY (demux->streaming)) {
705 /* support it safely needs more segment handling, e.g. closing etc */
707 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
710 /* we can (re)construct the start later on, but not the end */
711 if (stop_type != GST_SEEK_TYPE_NONE &&
712 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
713 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
716 return gst_asf_demux_handle_seek_push (demux, event);
719 /* unlock the streaming thread */
720 if (G_LIKELY (flush)) {
721 fevent = gst_event_new_flush_start ();
723 gst_event_set_seqnum (fevent, seqnum);
724 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
725 gst_asf_demux_send_event_unlocked (demux, fevent);
727 gst_pad_pause_task (demux->sinkpad);
730 /* grab the stream lock so that streaming cannot continue, for
731 * non flushing seeks when the element is in PAUSED this could block
733 GST_PAD_STREAM_LOCK (demux->sinkpad);
735 if (G_LIKELY (flush)) {
736 /* we now can stop flushing, since we have the stream lock now */
737 fevent = gst_event_new_flush_stop (TRUE);
738 gst_event_set_seqnum (fevent, seqnum);
739 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
740 gst_asf_demux_send_event_unlocked (demux, fevent);
743 /* operating on copy of segment until we know the seek worked */
744 segment = demux->segment;
746 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
747 cur, stop_type, stop, &only_need_update);
749 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
750 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
752 if (cur_type != GST_SEEK_TYPE_SET)
753 seek_time = segment.start;
757 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
758 * real start of data and segment_start to indexed time for key unit seek*/
759 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
760 &idx_time, &speed_count, next, &eos))) {
764 demux->packet = demux->num_packets;
768 /* First try to query our source to see if it can convert for us. This is
769 the case when our source is an mms stream, notice that in this case
770 gstmms will do a time based seek to get the byte offset, this is not a
771 problem as the seek to this offset needs to happen anway. */
772 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
773 GST_FORMAT_BYTES, &offset)) {
774 packet = (offset - demux->data_offset) / demux->packet_size;
775 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
776 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
777 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
778 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
779 demux->packet_size, packet);
781 /* FIXME: For streams containing video, seek to an earlier position in
782 * the hope of hitting a keyframe and let the sinks throw away the stuff
783 * before the segment start. For audio-only this is unnecessary as every
785 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
786 && demux->num_video_streams > 0) {
787 seek_time -= 5 * GST_SECOND;
792 packet = (guint) gst_util_uint64_scale (demux->num_packets,
793 seek_time, demux->play_time);
795 if (packet > demux->num_packets)
796 packet = demux->num_packets;
799 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
800 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
801 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
802 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
803 segment.start = idx_time;
804 segment.position = idx_time;
805 segment.time = idx_time;
809 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
811 GST_OBJECT_LOCK (demux);
812 demux->segment = segment;
813 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
814 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
815 stop, demux->play_time);
817 demux->packet = packet;
820 demux->need_newsegment = TRUE;
821 demux->segment_seqnum = seqnum;
822 demux->speed_packets =
823 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
824 gst_asf_demux_reset_stream_state_after_discont (demux);
825 GST_OBJECT_UNLOCK (demux);
828 /* restart our task since it might have been stopped when we did the flush */
829 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
832 /* streaming can continue now */
833 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
839 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
845 demux = GST_ASF_DEMUX (parent);
847 switch (GST_EVENT_TYPE (event)) {
849 GST_LOG_OBJECT (pad, "seek event");
850 ret = gst_asf_demux_handle_seek_event (demux, event);
851 gst_event_unref (event);
854 case GST_EVENT_NAVIGATION:
855 /* just drop these two silently */
856 gst_event_unref (event);
860 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
861 ret = gst_pad_event_default (pad, parent, event);
868 static inline guint32
869 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
873 ret = gst_asf_identify_guid (guids, guid);
875 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
876 gst_asf_get_guid_nick (guids, ret),
877 guid->v1, guid->v2, guid->v3, guid->v4);
889 /* Peek for an object.
891 * Returns FALSE is the object is corrupted (such as the reported
892 * object size being greater than 2**32bits.
895 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
896 guint data_len, AsfObject * object, gboolean expect)
900 /* Callers should have made sure that data_len is big enough */
901 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
903 if (data_len < ASF_OBJECT_HEADER_SIZE)
906 guid.v1 = GST_READ_UINT32_LE (data + 0);
907 guid.v2 = GST_READ_UINT32_LE (data + 4);
908 guid.v3 = GST_READ_UINT32_LE (data + 8);
909 guid.v4 = GST_READ_UINT32_LE (data + 12);
911 /* FIXME: make asf_demux_identify_object_guid() */
912 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
913 if (object->id == ASF_OBJ_UNDEFINED && expect) {
914 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
915 guid.v1, guid.v2, guid.v3, guid.v4);
918 object->size = GST_READ_UINT64_LE (data + 16);
919 if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
920 GST_WARNING_OBJECT (demux,
921 "ASF Object size corrupted (greater than 32bit)");
930 gst_asf_demux_release_old_pads (GstASFDemux * demux)
932 GST_DEBUG_OBJECT (demux, "Releasing old pads");
934 while (demux->old_num_streams > 0) {
935 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
936 gst_event_new_eos ());
937 gst_asf_demux_free_stream (demux,
938 &demux->old_stream[demux->old_num_streams - 1]);
939 --demux->old_num_streams;
941 memset (demux->old_stream, 0, sizeof (demux->old_stream));
942 demux->old_num_streams = 0;
946 gst_asf_demux_chain_headers (GstASFDemux * demux)
949 guint8 *header_data, *data = NULL;
950 const guint8 *cdata = NULL;
952 GstFlowReturn flow = GST_FLOW_OK;
954 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
958 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
960 if (obj.id != ASF_OBJ_HEADER)
963 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
965 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
966 if (gst_adapter_available (demux->adapter) < obj.size + 50)
969 data = gst_adapter_take (demux->adapter, obj.size + 50);
972 header_size = obj.size;
973 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
974 if (flow != GST_FLOW_OK)
977 /* calculate where the packet data starts */
978 demux->data_offset = obj.size + 50;
980 /* now parse the beginning of the ASF_OBJ_DATA object */
981 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
984 if (demux->num_streams == 0)
993 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1000 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1001 ("This doesn't seem to be an ASF file"));
1003 return GST_FLOW_ERROR;
1008 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1009 ("header parsing failed, or no streams found, flow = %s",
1010 gst_flow_get_name (flow)));
1012 return GST_FLOW_ERROR;
1017 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1018 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1023 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1026 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1028 if (G_LIKELY (p_flow))
1031 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1032 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1033 "+%u", gst_flow_get_name (flow), offset, size);
1038 g_assert (*p_buf != NULL);
1040 buffer_size = gst_buffer_get_size (*p_buf);
1041 if (G_UNLIKELY (buffer_size < size)) {
1042 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1043 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1044 gst_buffer_unref (*p_buf);
1045 if (G_LIKELY (p_flow))
1046 *p_flow = GST_FLOW_EOS;
1054 static GstFlowReturn
1055 gst_asf_demux_pull_indices (GstASFDemux * demux)
1057 GstBuffer *buf = NULL;
1060 GstFlowReturn ret = GST_FLOW_OK;
1062 offset = demux->index_offset;
1064 if (G_UNLIKELY (offset == 0)) {
1065 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1070 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1076 gst_buffer_map (buf, &map, GST_MAP_READ);
1077 g_assert (map.size >= 16 + 8);
1078 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1079 GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
1080 GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
1082 gst_buffer_unmap (buf, &map);
1083 gst_buffer_replace (&buf, NULL);
1084 /* Non-fatal, return */
1087 gst_buffer_unmap (buf, &map);
1088 gst_buffer_replace (&buf, NULL);
1090 /* check for sanity */
1091 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1092 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1096 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1100 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1101 ", size %u", offset, (guint) obj.size);
1103 offset += obj.size; /* increase before _process_object changes it */
1105 gst_buffer_map (buf, &map, GST_MAP_READ);
1106 g_assert (map.size >= obj.size);
1107 bufdata = (guint8 *) map.data;
1108 obj_size = obj.size;
1109 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1110 gst_buffer_unmap (buf, &map);
1111 gst_buffer_replace (&buf, NULL);
1113 if (ret == ASF_FLOW_NEED_MORE_DATA) {
1114 /* Since indices are at the end of the file, if we need more data,
1115 * we consider it as a non-fatal corrupted index */
1120 if (G_UNLIKELY (ret != GST_FLOW_OK))
1126 GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
1127 gst_flow_get_name (ret));
1132 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1136 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1137 GST_WARNING_OBJECT (demux, "Corrupted data");
1140 if (obj.id != ASF_OBJ_DATA) {
1141 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1145 demux->state = GST_ASF_DEMUX_STATE_DATA;
1147 if (!demux->broadcast && obj.size > 50) {
1148 demux->data_size = obj.size - 50;
1149 /* CHECKME: for at least one file this is off by +158 bytes?! */
1150 demux->index_offset = demux->data_offset + demux->data_size;
1152 demux->data_size = 0;
1153 demux->index_offset = 0;
1158 if (!demux->broadcast) {
1159 /* skip object header (24 bytes) and file GUID (16 bytes) */
1160 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1162 demux->num_packets = 0;
1165 if (demux->num_packets == 0)
1166 demux->seekable = FALSE;
1168 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1169 if (demux->data_size == 0 && demux->num_packets > 0) {
1170 demux->data_size = demux->num_packets * demux->packet_size;
1171 demux->index_offset = demux->data_offset + demux->data_size;
1174 /* process pending stream objects and create pads for those */
1175 gst_asf_demux_process_queued_extended_stream_objects (demux);
1177 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1178 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1179 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1180 demux->data_offset, demux->data_size, demux->index_offset);
1186 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1188 GstFlowReturn flow = GST_FLOW_OK;
1190 GstBuffer *buf = NULL;
1195 GST_LOG_OBJECT (demux, "reading headers");
1197 /* pull HEADER object header, so we know its size */
1198 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1201 gst_buffer_map (buf, &map, GST_MAP_READ);
1202 g_assert (map.size >= 16 + 8);
1203 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1204 gst_buffer_unmap (buf, &map);
1205 gst_buffer_replace (&buf, NULL);
1206 flow = GST_FLOW_ERROR;
1209 gst_buffer_unmap (buf, &map);
1210 gst_buffer_replace (&buf, NULL);
1212 if (obj.id != ASF_OBJ_HEADER)
1215 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1217 /* pull HEADER object */
1218 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1222 size = obj.size; /* don't want obj.size changed */
1223 gst_buffer_map (buf, &map, GST_MAP_READ);
1224 g_assert (map.size >= size);
1225 bufdata = (guint8 *) map.data;
1226 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1227 gst_buffer_unmap (buf, &map);
1228 gst_buffer_replace (&buf, NULL);
1230 if (flow != GST_FLOW_OK) {
1231 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1235 /* calculate where the packet data starts */
1236 demux->data_offset = demux->base_offset + obj.size + 50;
1238 /* now pull beginning of DATA object before packet data */
1239 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1243 gst_buffer_map (buf, &map, GST_MAP_READ);
1244 g_assert (map.size >= size);
1245 bufdata = (guint8 *) map.data;
1246 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1249 if (demux->num_streams == 0)
1252 gst_buffer_unmap (buf, &map);
1253 gst_buffer_replace (&buf, NULL);
1261 gst_buffer_unmap (buf, &map);
1262 gst_buffer_replace (&buf, NULL);
1264 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1265 ("This doesn't seem to be an ASF file"));
1266 *pflow = GST_FLOW_ERROR;
1271 flow = GST_FLOW_ERROR;
1272 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1273 ("header parsing failed, or no streams found, flow = %s",
1274 gst_flow_get_name (flow)));
1279 gst_buffer_unmap (buf, &map);
1280 gst_buffer_replace (&buf, NULL);
1281 if (flow == ASF_FLOW_NEED_MORE_DATA)
1282 flow = GST_FLOW_ERROR;
1289 all_streams_prerolled (GstASFDemux * demux)
1291 GstClockTime preroll_time;
1292 guint i, num_no_data = 0;
1293 AsfStreamType prerolled_types = 0, all_types = 0;
1295 /* Allow at least 500ms of preroll_time */
1296 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1298 /* returns TRUE as long as there isn't a stream which (a) has data queued
1299 * and (b) the timestamp of last piece of data queued is < demux->preroll
1300 * AND there is at least one other stream with data queued */
1301 for (i = 0; i < demux->num_streams; ++i) {
1302 AsfPayload *last_payload = NULL;
1306 stream = &demux->stream[i];
1308 all_types |= stream->type;
1310 if (G_UNLIKELY (stream->payloads->len == 0)) {
1312 GST_LOG_OBJECT (stream->pad, "no data queued");
1316 prerolled_types |= stream->type;
1318 /* find last payload with timestamp */
1319 for (last_idx = stream->payloads->len - 1;
1320 last_idx >= 0 && (last_payload == NULL
1321 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1322 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1325 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1326 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1327 GST_TIME_ARGS (preroll_time));
1328 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1329 || last_payload->ts <= preroll_time)) {
1330 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1335 GST_LOG_OBJECT (demux, "all_types:%d prerolled_types:%d",
1336 all_types, prerolled_types);
1338 /* If streams of each present type have prerolled, we are good to go */
1339 if (all_types != 0 && prerolled_types == all_types)
1342 if (G_UNLIKELY (num_no_data > 0))
1350 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1355 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1358 /* check for each mutual exclusion group whether it affects this stream */
1359 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1360 if (*mes == stream->id) {
1361 /* we are in this group; let's check if we've already activated streams
1362 * that are in the same group (and hence mutually exclusive to this
1364 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1367 for (i = 0; i < demux->num_streams; ++i) {
1368 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1369 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1370 "to already active stream with ID %d", stream->id,
1371 demux->stream[i].id);
1376 /* we can only be in this group once, let's break out and move on to
1377 * the next mutual exclusion group */
1388 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1390 /* remember the first queued timestamp for the segment */
1391 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1392 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1393 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1394 GST_TIME_ARGS (demux->first_ts));
1395 demux->segment_ts = payload_ts;
1396 /* always note, but only determines segment when streaming */
1397 if (demux->streaming)
1398 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1399 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1400 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1405 gst_asf_demux_get_first_ts (GstASFDemux * demux)
1407 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1408 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1411 /* go trhough each stream, find smallest timestamp */
1412 for (i = 0; i < demux->num_streams; ++i) {
1415 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1416 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1417 stream = &demux->stream[i];
1419 for (j = 0; j < stream->payloads->len; ++j) {
1420 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1421 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1422 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1423 || stream_min_ts > payload->ts)) {
1424 stream_min_ts = payload->ts;
1426 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1427 payload->ts > stream_min_ts &&
1428 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1429 || stream_min_ts2 > payload->ts)) {
1430 stream_min_ts2 = payload->ts;
1434 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1435 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1436 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1437 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1438 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1440 GST_DEBUG_OBJECT (demux,
1441 "stream #%u stream_min_ts %" GST_TIME_FORMAT " stream_min_ts2 %"
1442 GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (stream_min_ts),
1443 GST_TIME_ARGS (stream_min_ts2));
1445 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1446 stream_min_ts = stream_min_ts2;
1448 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1449 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1450 first_ts = stream_min_ts;
1453 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen */
1456 demux->first_ts = first_ts;
1458 /* update packets queued before we knew first timestamp */
1459 for (i = 0; i < demux->num_streams; ++i) {
1462 stream = &demux->stream[i];
1464 for (j = 0; j < stream->payloads->len; ++j) {
1465 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1466 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1467 if (payload->ts > first_ts)
1468 payload->ts -= first_ts;
1476 gst_asf_demux_check_segment_ts (demux, 0);
1482 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1484 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1485 and often set wrong, inspecting the data is the only way that seem to be working */
1486 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1487 GstCaps *caps = NULL;
1489 GstAdapter *adapter = gst_adapter_new ();
1491 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1493 AsfPayload *payload;
1496 payload = &g_array_index (stream->payloads, AsfPayload, i);
1497 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1498 len = gst_adapter_available (adapter);
1499 data = gst_adapter_map (adapter, len);
1503 #define MIN_LENGTH 128
1505 /* look for the sync points */
1507 if (len < MIN_LENGTH || /* give typefind something to work on */
1508 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1509 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1515 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1518 if (prob < GST_TYPE_FIND_LIKELY) {
1521 if (len > MIN_LENGTH)
1522 /* this wasn't it, look for another sync point */
1526 gst_adapter_unmap (adapter);
1529 gst_object_unref (adapter);
1532 gst_caps_take (&stream->caps, caps);
1540 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1542 guint i, actual_streams = 0;
1544 if (demux->activated_streams)
1547 if (!all_streams_prerolled (demux) && !force) {
1548 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1552 if (G_UNLIKELY (!gst_asf_demux_get_first_ts (demux)))
1555 for (i = 0; i < demux->num_streams; ++i) {
1556 AsfStream *stream = &demux->stream[i];
1558 if (stream->payloads->len > 0) {
1560 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1561 !stream->active && /* do not inspect active streams (caps were already set) */
1562 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1563 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1564 /* try to gather some more data */
1567 /* we don't check mutual exclusion stuff here; either we have data for
1568 * a stream, then we active it, or we don't, then we'll ignore it */
1569 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1570 gst_asf_demux_activate_stream (demux, stream);
1571 actual_streams += 1;
1573 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1577 if (actual_streams == 0) {
1578 /* We don't have any streams activated ! */
1579 GST_ERROR_OBJECT (demux, "No streams activated!");
1583 gst_asf_demux_release_old_pads (demux);
1585 demux->activated_streams = TRUE;
1586 GST_LOG_OBJECT (demux, "signalling no more pads");
1587 gst_element_no_more_pads (GST_ELEMENT (demux));
1591 /* returns the stream that has a complete payload with the lowest timestamp
1592 * queued, or NULL (we push things by timestamp because during the internal
1593 * prerolling we might accumulate more data then the external queues can take,
1594 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1596 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1598 AsfPayload *best_payload = NULL;
1599 AsfStream *best_stream = NULL;
1602 for (i = 0; i < demux->num_streams; ++i) {
1606 stream = &demux->stream[i];
1608 /* Don't push any data until we have at least one payload that falls within
1609 * the current segment. This way we can remove out-of-segment payloads that
1610 * don't need to be decoded after a seek, sending only data from the
1611 * keyframe directly before our segment start */
1612 if (stream->payloads->len > 0) {
1613 AsfPayload *payload = NULL;
1616 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1617 /* Reverse playback */
1619 if (stream->is_video) {
1620 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1621 if (stream->reverse_kf_ready) {
1623 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1624 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1625 /* TODO : remove payload from the list? */
1632 /* find first complete payload with timestamp */
1633 for (j = stream->payloads->len - 1;
1634 j >= 0 && (payload == NULL
1635 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1636 payload = &g_array_index (stream->payloads, AsfPayload, j);
1639 /* If there's a complete payload queued for this stream */
1640 if (!gst_asf_payload_is_complete (payload))
1646 /* find last payload with timestamp */
1647 for (last_idx = stream->payloads->len - 1;
1648 last_idx >= 0 && (payload == NULL
1649 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1650 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1653 /* if this is first payload after seek we might need to update the segment */
1654 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1655 gst_asf_demux_check_segment_ts (demux, payload->ts);
1657 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1658 (payload->ts < demux->segment.start))) {
1659 if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
1660 && payload->keyframe)) {
1661 GST_DEBUG_OBJECT (stream->pad,
1662 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1663 GST_TIME_ARGS (payload->ts));
1664 demux->segment.start = payload->ts;
1665 demux->segment.time = payload->ts;
1667 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1668 GST_TIME_FORMAT " which is before our segment start %"
1669 GST_TIME_FORMAT ", not pushing yet",
1670 GST_TIME_ARGS (payload->ts),
1671 GST_TIME_ARGS (demux->segment.start));
1676 /* find first complete payload with timestamp */
1678 j < stream->payloads->len && (payload == NULL
1679 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1680 payload = &g_array_index (stream->payloads, AsfPayload, j);
1683 /* Now see if there's a complete payload queued for this stream */
1684 if (!gst_asf_payload_is_complete (payload))
1688 /* ... and whether its timestamp is lower than the current best */
1689 if (best_stream == NULL || best_payload->ts > payload->ts) {
1690 best_stream = stream;
1691 best_payload = payload;
1699 static GstFlowReturn
1700 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1703 GstFlowReturn ret = GST_FLOW_OK;
1705 if (G_UNLIKELY (!demux->activated_streams)) {
1706 if (!gst_asf_demux_check_activate_streams (demux, force))
1708 /* streams are now activated */
1711 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1712 AsfPayload *payload;
1713 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1714 GstClockTime duration = GST_CLOCK_TIME_NONE;
1716 /* wait until we had a chance to "lock on" some payload's timestamp */
1717 if (G_UNLIKELY (demux->need_newsegment
1718 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1721 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1722 && stream->payloads->len) {
1723 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1725 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1728 /* do we need to send a newsegment event */
1729 if ((G_UNLIKELY (demux->need_newsegment))) {
1730 GstEvent *segment_event;
1732 /* safe default if insufficient upstream info */
1733 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1736 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1737 demux->segment.duration > 0) {
1738 /* slight HACK; prevent clipping of last bit */
1739 demux->segment.stop = demux->segment.duration + demux->in_gap;
1742 /* FIXME : only if ACCURATE ! */
1743 if (G_LIKELY (demux->keyunit_sync && !demux->accurate
1744 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1745 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1746 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1747 GST_TIME_ARGS (payload->ts));
1748 demux->segment.start = payload->ts;
1749 demux->segment.time = payload->ts;
1752 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1755 /* note: we fix up all timestamps to start from 0, so this should be ok */
1756 segment_event = gst_event_new_segment (&demux->segment);
1757 if (demux->segment_seqnum)
1758 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1759 gst_asf_demux_send_event_unlocked (demux, segment_event);
1761 /* now post any global tags we may have found */
1762 if (demux->taglist == NULL) {
1763 demux->taglist = gst_tag_list_new_empty ();
1764 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1767 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1768 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1770 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1771 gst_asf_demux_send_event_unlocked (demux,
1772 gst_event_new_tag (demux->taglist));
1773 demux->taglist = NULL;
1775 demux->need_newsegment = FALSE;
1776 demux->segment_seqnum = 0;
1777 demux->segment_running = TRUE;
1780 /* Do we have tags pending for this stream? */
1781 if (G_UNLIKELY (stream->pending_tags)) {
1782 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1783 gst_pad_push_event (stream->pad,
1784 gst_event_new_tag (stream->pending_tags));
1785 stream->pending_tags = NULL;
1788 /* We have the whole packet now so we should push the packet to
1789 * the src pad now. First though we should check if we need to do
1791 if (G_UNLIKELY (stream->span > 1)) {
1792 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1795 payload->buf = gst_buffer_make_writable (payload->buf);
1797 if (G_LIKELY (!payload->keyframe)) {
1798 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1801 if (G_UNLIKELY (stream->discont)) {
1802 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1803 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1804 stream->discont = FALSE;
1807 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1808 (payload->par_x != stream->par_x) &&
1809 (payload->par_y != stream->par_y))) {
1810 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1811 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1812 stream->par_x = payload->par_x;
1813 stream->par_y = payload->par_y;
1814 stream->caps = gst_caps_make_writable (stream->caps);
1815 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1816 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1817 gst_pad_set_caps (stream->pad, stream->caps);
1820 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1821 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1822 payload->interlaced);
1823 stream->interlaced = payload->interlaced;
1824 stream->caps = gst_caps_make_writable (stream->caps);
1825 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1826 (stream->interlaced ? "mixed" : "progressive"), NULL);
1827 gst_pad_set_caps (stream->pad, stream->caps);
1830 /* (sort of) interpolate timestamps using upstream "frame of reference",
1831 * typically useful for live src, but might (unavoidably) mess with
1832 * position reporting if a live src is playing not so live content
1833 * (e.g. rtspsrc taking some time to fall back to tcp) */
1834 timestamp = payload->ts;
1835 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1836 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1837 timestamp += demux->in_gap;
1839 /* Check if we're after the segment already, if so no need to push
1841 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1842 GST_DEBUG_OBJECT (stream->pad,
1843 "Payload after segment stop %" GST_TIME_FORMAT,
1844 GST_TIME_ARGS (demux->segment.stop));
1846 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1848 gst_buffer_unref (payload->buf);
1849 payload->buf = NULL;
1850 g_array_remove_index (stream->payloads, 0);
1851 /* Break out as soon as we have an issue */
1852 if (G_UNLIKELY (ret != GST_FLOW_OK))
1859 GST_BUFFER_PTS (payload->buf) = timestamp;
1861 if (payload->duration == GST_CLOCK_TIME_NONE
1862 && stream->ext_props.avg_time_per_frame != 0) {
1863 duration = stream->ext_props.avg_time_per_frame * 100;
1865 duration = payload->duration;
1867 GST_BUFFER_DURATION (payload->buf) = duration;
1869 /* FIXME: we should really set durations on buffers if we can */
1871 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1874 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1875 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1876 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1878 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1879 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1883 if (stream->active) {
1884 if (G_UNLIKELY (stream->first_buffer)) {
1885 if (stream->streamheader != NULL) {
1886 GST_DEBUG_OBJECT (stream->pad,
1887 "Pushing streamheader before first buffer");
1888 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1890 stream->first_buffer = FALSE;
1893 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1894 && timestamp > demux->segment.position) {
1895 demux->segment.position = timestamp;
1896 if (GST_CLOCK_TIME_IS_VALID (duration))
1897 demux->segment.position += timestamp;
1900 ret = gst_pad_push (stream->pad, payload->buf);
1902 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1905 gst_buffer_unref (payload->buf);
1908 payload->buf = NULL;
1909 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1910 && stream->reverse_kf_ready) {
1911 g_array_remove_index (stream->payloads, stream->kf_pos);
1914 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1916 stream->reverse_kf_ready = FALSE;
1919 g_array_remove_index (stream->payloads, 0);
1922 /* Break out as soon as we have an issue */
1923 if (G_UNLIKELY (ret != GST_FLOW_OK))
1931 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1936 g_assert (buf != NULL);
1938 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1940 gst_buffer_map (buf, &map, GST_MAP_READ);
1942 /* we return false on buffer too small */
1943 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1944 gst_buffer_unmap (buf, &map);
1948 /* check if it is a header */
1950 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1952 gst_buffer_unmap (buf, &map);
1953 if (valid && obj.id == ASF_OBJ_HEADER) {
1960 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1962 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1963 GstFlowReturn ret = GST_FLOW_OK;
1964 GstBuffer *buf = NULL;
1965 gboolean header = FALSE;
1967 /* TODO maybe we should skip index objects after the data and look
1968 * further for a new header */
1969 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1970 g_assert (buf != NULL);
1971 /* check if it is a header */
1972 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1973 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1974 demux->base_offset = off;
1978 gst_buffer_unref (buf);
1985 gst_asf_demux_loop (GstASFDemux * demux)
1987 GstFlowReturn flow = GST_FLOW_OK;
1988 GstBuffer *buf = NULL;
1991 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1992 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1996 flow = gst_asf_demux_pull_indices (demux);
1997 if (flow != GST_FLOW_OK)
2001 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
2003 if (G_UNLIKELY (demux->num_packets != 0
2004 && demux->packet >= demux->num_packets))
2007 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2008 (guint) demux->num_packets);
2010 off = demux->data_offset + (demux->packet * demux->packet_size);
2012 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2013 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2014 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2015 if (flow == GST_FLOW_EOS) {
2017 } else if (flow == GST_FLOW_FLUSHING) {
2018 GST_DEBUG_OBJECT (demux, "Not fatal");
2025 if (G_LIKELY (demux->speed_packets == 1)) {
2026 GstAsfDemuxParsePacketError err;
2027 err = gst_asf_demux_parse_packet (demux, buf);
2028 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2029 /* when we don't know when the data object ends, we should check
2030 * for a chained asf */
2031 if (demux->num_packets == 0) {
2032 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2033 GST_INFO_OBJECT (demux, "Chained asf found");
2034 demux->base_offset = off;
2035 gst_asf_demux_reset (demux, TRUE);
2036 gst_buffer_unref (buf);
2040 /* FIXME: We should tally up fatal errors and error out only
2041 * after a few broken packets in a row? */
2043 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2044 gst_buffer_unref (buf);
2046 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2047 && !demux->seek_to_cur_pos) {
2049 if (demux->packet < 0) {
2059 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2061 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2062 && !demux->seek_to_cur_pos) {
2064 if (demux->packet < 0) {
2073 for (n = 0; n < demux->speed_packets; n++) {
2075 GstAsfDemuxParsePacketError err;
2078 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2079 n * demux->packet_size, demux->packet_size);
2080 err = gst_asf_demux_parse_packet (demux, sub);
2081 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2082 /* when we don't know when the data object ends, we should check
2083 * for a chained asf */
2084 if (demux->num_packets == 0) {
2085 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2086 GST_INFO_OBJECT (demux, "Chained asf found");
2087 demux->base_offset = off + n * demux->packet_size;
2088 gst_asf_demux_reset (demux, TRUE);
2089 gst_buffer_unref (sub);
2090 gst_buffer_unref (buf);
2094 /* FIXME: We should tally up fatal errors and error out only
2095 * after a few broken packets in a row? */
2097 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2101 gst_buffer_unref (sub);
2103 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2104 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2110 /* reset speed pull */
2111 demux->speed_packets = 1;
2114 gst_buffer_unref (buf);
2116 if (G_UNLIKELY ((demux->num_packets > 0
2117 && demux->packet >= demux->num_packets)
2118 || flow == GST_FLOW_EOS)) {
2119 GST_LOG_OBJECT (demux, "reached EOS");
2123 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2124 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2128 /* check if we're at the end of the configured segment */
2129 /* FIXME: check if segment end reached etc. */
2135 /* if we haven't activated our streams yet, this might be because we have
2136 * less data queued than required for preroll; force stream activation and
2137 * send any pending payloads before sending EOS */
2138 if (!demux->activated_streams)
2139 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2141 /* we want to push an eos or post a segment-done in any case */
2142 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2145 /* for segment playback we need to post when (in stream time)
2146 * we stopped, this is either stop (when set) or the duration. */
2147 if ((stop = demux->segment.stop) == -1)
2148 stop = demux->segment.duration;
2150 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2151 gst_element_post_message (GST_ELEMENT_CAST (demux),
2152 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2154 gst_asf_demux_send_event_unlocked (demux,
2155 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2156 } else if (flow != GST_FLOW_EOS) {
2157 /* check if we have a chained asf, in case, we don't eos yet */
2158 if (gst_asf_demux_check_chained_asf (demux)) {
2159 GST_INFO_OBJECT (demux, "Chained ASF starting");
2160 gst_asf_demux_reset (demux, TRUE);
2165 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2166 if (demux->activated_streams) {
2167 /* normal playback, send EOS to all linked pads */
2168 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2169 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2171 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2172 flow = GST_FLOW_EOS;
2175 /* ... and fall through to pause */
2179 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2180 gst_flow_get_name (flow));
2181 demux->segment_running = FALSE;
2182 gst_pad_pause_task (demux->sinkpad);
2184 /* For the error cases */
2185 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2186 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2187 ("This doesn't seem to be an ASF file"));
2188 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2189 /* Post an error. Hopefully something else already has, but if not... */
2190 GST_ELEMENT_FLOW_ERROR (demux, flow);
2191 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2200 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2201 flow = GST_FLOW_EOS;
2205 /* See FIXMEs above */
2208 gst_buffer_unref (buf);
2209 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2210 ("Error parsing ASF packet %u", (guint) demux->packet));
2211 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2212 flow = GST_FLOW_ERROR;
2218 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2219 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2220 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2223 gst_asf_demux_check_header (GstASFDemux * demux)
2226 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2227 ASF_OBJECT_HEADER_SIZE);
2228 if (cdata == NULL) /* need more data */
2229 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2231 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
2232 && obj.id == ASF_OBJ_HEADER) {
2233 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2236 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2239 static GstFlowReturn
2240 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2242 GstFlowReturn ret = GST_FLOW_OK;
2245 demux = GST_ASF_DEMUX (parent);
2247 GST_LOG_OBJECT (demux,
2248 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2249 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2250 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2252 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2253 GST_DEBUG_OBJECT (demux, "received DISCONT");
2254 gst_asf_demux_mark_discont (demux);
2257 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2258 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2259 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2260 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2261 ", interpolation gap: %" GST_TIME_FORMAT,
2262 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2265 gst_adapter_push (demux->adapter, buf);
2267 switch (demux->state) {
2268 case GST_ASF_DEMUX_STATE_INDEX:{
2269 gint result = gst_asf_demux_check_header (demux);
2270 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2273 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2274 /* we don't care about this, probably an index */
2275 /* TODO maybe would be smarter to skip all the indices
2276 * until we got a new header or EOS to decide */
2277 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2280 GST_INFO_OBJECT (demux, "Chained asf starting");
2281 /* cleanup and get ready for a chained asf */
2282 gst_asf_demux_reset (demux, TRUE);
2286 case GST_ASF_DEMUX_STATE_HEADER:{
2287 ret = gst_asf_demux_chain_headers (demux);
2288 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2290 /* otherwise fall through */
2292 case GST_ASF_DEMUX_STATE_DATA:
2296 data_size = demux->packet_size;
2298 while (gst_adapter_available (demux->adapter) >= data_size) {
2300 GstAsfDemuxParsePacketError err;
2302 /* we don't know the length of the stream
2303 * check for a chained asf everytime */
2304 if (demux->num_packets == 0) {
2305 gint result = gst_asf_demux_check_header (demux);
2307 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2308 GST_INFO_OBJECT (demux, "Chained asf starting");
2309 /* cleanup and get ready for a chained asf */
2310 gst_asf_demux_reset (demux, TRUE);
2313 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2314 && demux->packet >= demux->num_packets)) {
2315 /* do not overshoot data section when streaming */
2319 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2321 /* FIXME: We should tally up fatal errors and error out only
2322 * after a few broken packets in a row? */
2323 err = gst_asf_demux_parse_packet (demux, buf);
2325 gst_buffer_unref (buf);
2327 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2328 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2330 GST_WARNING_OBJECT (demux, "Parse error");
2332 if (demux->packet >= 0)
2335 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2336 && demux->packet >= demux->num_packets)) {
2337 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2342 g_assert_not_reached ();
2346 if (ret != GST_FLOW_OK)
2347 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2353 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2359 static inline gboolean
2360 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2362 if (*p_size < num_bytes)
2365 *p_data += num_bytes;
2366 *p_size -= num_bytes;
2370 static inline guint8
2371 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2375 g_assert (*p_size >= 1);
2376 ret = GST_READ_UINT8 (*p_data);
2377 *p_data += sizeof (guint8);
2378 *p_size -= sizeof (guint8);
2382 static inline guint16
2383 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2387 g_assert (*p_size >= 2);
2388 ret = GST_READ_UINT16_LE (*p_data);
2389 *p_data += sizeof (guint16);
2390 *p_size -= sizeof (guint16);
2394 static inline guint32
2395 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2399 g_assert (*p_size >= 4);
2400 ret = GST_READ_UINT32_LE (*p_data);
2401 *p_data += sizeof (guint32);
2402 *p_size -= sizeof (guint32);
2406 static inline guint64
2407 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2411 g_assert (*p_size >= 8);
2412 ret = GST_READ_UINT64_LE (*p_data);
2413 *p_data += sizeof (guint64);
2414 *p_size -= sizeof (guint64);
2419 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2420 guint8 ** p_data, guint64 * p_size)
2424 if (*p_size < num_bytes_to_read)
2427 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2428 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2430 *p_data += num_bytes_to_read;
2431 *p_size -= num_bytes_to_read;
2437 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2438 guint8 ** p_data, guint64 * p_size)
2442 if (*p_size < num_bytes_to_read)
2445 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2446 *p_data += num_bytes_to_read;
2447 *p_size -= num_bytes_to_read;
2452 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2453 guint8 ** p_data, guint64 * p_size)
2463 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2466 *p_strlen = s_length;
2468 if (s_length == 0) {
2469 GST_WARNING ("zero-length string");
2470 *p_str = g_strdup ("");
2474 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2477 g_assert (s != NULL);
2479 /* just because They don't exist doesn't
2480 * mean They are not out to get you ... */
2481 if (s[s_length - 1] != '\0') {
2482 s = g_realloc (s, s_length + 1);
2486 *p_str = (gchar *) s;
2492 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2494 g_assert (*p_size >= 4 * sizeof (guint32));
2496 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2497 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2498 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2499 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2503 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2506 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2509 /* WAVEFORMATEX Structure */
2510 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2511 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2512 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2513 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2514 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2515 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2516 /* Codec specific data size */
2517 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2518 if (audio->size > *p_size) {
2519 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2520 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2527 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2530 if (*p_size < (4 + 4 + 1 + 2))
2533 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2534 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2535 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2536 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2541 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2542 guint8 ** p_data, guint64 * p_size)
2544 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2547 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2549 if (fmt->size < 40) {
2550 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2553 if ((guint64) fmt->size - 4 > *p_size) {
2554 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2557 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2558 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2559 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2560 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2561 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2562 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2563 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2564 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2565 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2566 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2571 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2575 for (i = 0; i < demux->num_streams; i++) {
2576 if (demux->stream[i].id == id)
2577 return &demux->stream[i];
2580 if (gst_asf_demux_is_unknown_stream (demux, id))
2581 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2586 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2587 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2592 gst_pad_use_fixed_caps (src_pad);
2593 gst_pad_set_caps (src_pad, caps);
2595 gst_pad_set_event_function (src_pad,
2596 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2597 gst_pad_set_query_function (src_pad,
2598 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2600 stream = &demux->stream[demux->num_streams];
2601 stream->caps = caps;
2602 stream->pad = src_pad;
2604 stream->fps_known = !is_video; /* bit hacky for audio */
2605 stream->is_video = is_video;
2606 stream->pending_tags = tags;
2607 stream->discont = TRUE;
2608 stream->first_buffer = TRUE;
2609 stream->streamheader = streamheader;
2610 if (stream->streamheader) {
2611 stream->streamheader = gst_buffer_make_writable (streamheader);
2612 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2617 st = gst_caps_get_structure (caps, 0);
2618 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2619 par_x > 0 && par_y > 0) {
2620 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2621 stream->par_x = par_x;
2622 stream->par_y = par_y;
2626 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2628 /* TODO: create this array during reverse play? */
2629 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2631 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2632 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2634 ++demux->num_streams;
2636 stream->active = FALSE;
2642 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2643 GstBuffer * buffer, GstStructure * structure)
2645 GValue arr_val = G_VALUE_INIT;
2646 GValue buf_val = G_VALUE_INIT;
2648 g_value_init (&arr_val, GST_TYPE_ARRAY);
2649 g_value_init (&buf_val, GST_TYPE_BUFFER);
2651 gst_value_set_buffer (&buf_val, buffer);
2652 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2654 gst_structure_take_value (structure, "streamheader", &arr_val);
2658 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2659 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2661 GstTagList *tags = NULL;
2662 GstBuffer *extradata = NULL;
2665 guint16 size_left = 0;
2666 gchar *codec_name = NULL;
2669 size_left = audio->size;
2671 /* Create the audio pad */
2672 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2674 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2677 /* Swallow up any left over data and set up the
2678 * standard properties from the header info */
2680 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2681 "codec specific data", size_left);
2683 g_assert (size_left <= *p_size);
2684 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2687 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2688 * additional two bytes indicating extradata. */
2689 /* FIXME: Handle the channel reorder map here */
2690 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2691 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2694 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2695 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2698 /* Informing about that audio format we just added */
2700 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2701 g_free (codec_name);
2704 if (audio->byte_rate > 0) {
2705 /* Some ASF files have no bitrate props object (often seen with
2706 * ASF files that contain raw audio data). Example files can
2707 * be generated with FFmpeg (tested with v2.8.6), like this:
2709 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2711 * In this case, if audio->byte_rate is nonzero, use that as
2714 guint bitrate = audio->byte_rate * 8;
2717 tags = gst_tag_list_new_empty ();
2719 /* Add bitrate, but only if there is none set already, since
2720 * this is just a fallback in case there is no bitrate tag
2721 * already present */
2722 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2726 gst_buffer_unref (extradata);
2728 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2729 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2730 audio->codec_tag, tags);
2732 ++demux->num_audio_streams;
2734 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2738 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2739 asf_stream_video_format * video, guint16 id,
2740 guint8 ** p_data, guint64 * p_size)
2742 GstTagList *tags = NULL;
2743 GstStructure *caps_s;
2744 GstBuffer *extradata = NULL;
2749 gchar *codec_name = NULL;
2750 guint64 size_left = video->size - 40;
2751 GstBuffer *streamheader = NULL;
2752 guint par_w = 1, par_h = 1;
2754 /* Create the video pad */
2755 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2756 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2759 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2761 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2762 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2764 g_assert (size_left <= *p_size);
2765 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2768 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2770 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2771 caps = gst_riff_create_video_caps (video->tag, NULL,
2772 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2775 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2776 G_TYPE_UINT, video->tag, NULL);
2781 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2782 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2783 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2786 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2790 /* retry with the global metadata */
2791 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2792 demux->global_metadata);
2793 s = demux->global_metadata;
2794 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2795 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2796 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2797 if (ax > 0 && ay > 0) {
2800 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2805 s = gst_caps_get_structure (caps, 0);
2806 gst_structure_remove_field (s, "framerate");
2809 caps_s = gst_caps_get_structure (caps, 0);
2811 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2812 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2813 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2814 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2817 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2818 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2819 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2821 GstBuffer *buf = gst_value_get_buffer (value);
2824 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2825 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2826 /* this looks like a bytestream start */
2827 streamheader = gst_buffer_ref (buf);
2828 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2829 gst_structure_remove_field (caps_s, "codec_data");
2830 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING,
2831 "byte-stream", NULL);
2833 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "avc",
2837 gst_buffer_unmap (buf, &mapinfo);
2840 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "byte-stream",
2845 /* For a 3D video, set multiview information into the caps based on
2846 * what was detected during object parsing */
2847 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2848 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2849 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2850 const gchar *mview_mode_str;
2852 switch (demux->asf_3D_mode) {
2853 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2854 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2856 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2857 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2858 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2860 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2861 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2863 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2864 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2865 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2867 case GST_ASF_3D_DUAL_STREAM:{
2868 gboolean is_right_view = FALSE;
2869 /* if Advanced_Mutual_Exclusion object exists, use it
2870 * to figure out which is the left view (lower ID) */
2871 if (demux->mut_ex_streams != NULL) {
2875 length = g_slist_length (demux->mut_ex_streams);
2877 for (i = 0; i < length; i++) {
2880 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2882 GST_DEBUG_OBJECT (demux,
2883 "has Mutual_Exclusion object. stream id in object is %d",
2884 GPOINTER_TO_INT (v_s_id));
2886 if (id > GPOINTER_TO_INT (v_s_id))
2887 is_right_view = TRUE;
2890 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2891 * first video stream encountered has the lower ID */
2892 if (demux->num_video_streams > 0) {
2893 /* This is not the first video stream, assuming right eye view */
2894 is_right_view = TRUE;
2898 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2900 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2907 GST_INFO_OBJECT (demux,
2908 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2911 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2912 if (mview_mode_str != NULL) {
2913 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2914 video->height, par_w, par_h))
2915 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2917 gst_caps_set_simple (caps,
2918 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2919 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2920 GST_FLAG_SET_MASK_EXACT, NULL);
2925 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2926 g_free (codec_name);
2930 gst_buffer_unref (extradata);
2932 GST_INFO ("Adding video stream #%u, id %u, codec %"
2933 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2934 GST_FOURCC_ARGS (video->tag), video->tag);
2936 ++demux->num_video_streams;
2938 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2939 streamheader, tags);
2943 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2945 if (!stream->active) {
2949 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2950 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2951 gst_pad_set_active (stream->pad, TRUE);
2954 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2955 "%03u", stream->id);
2958 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2960 if (gst_event_parse_group_id (event, &demux->group_id))
2961 demux->have_group_id = TRUE;
2963 demux->have_group_id = FALSE;
2964 gst_event_unref (event);
2965 } else if (!demux->have_group_id) {
2966 demux->have_group_id = TRUE;
2967 demux->group_id = gst_util_group_id_next ();
2970 event = gst_event_new_stream_start (stream_id);
2971 if (demux->have_group_id)
2972 gst_event_set_group_id (event, demux->group_id);
2974 gst_pad_push_event (stream->pad, event);
2976 gst_pad_set_caps (stream->pad, stream->caps);
2978 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2979 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2980 stream->active = TRUE;
2985 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2988 AsfCorrectionType correction_type;
2989 AsfStreamType stream_type;
2990 GstClockTime time_offset;
2991 gboolean is_encrypted G_GNUC_UNUSED;
2995 guint stream_specific_size;
2996 guint type_specific_size G_GNUC_UNUSED;
2997 guint unknown G_GNUC_UNUSED;
2998 gboolean inspect_payload = FALSE;
2999 AsfStream *stream = NULL;
3001 /* Get the rest of the header's header */
3002 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
3003 goto not_enough_data;
3005 gst_asf_demux_get_guid (&guid, &data, &size);
3006 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
3008 gst_asf_demux_get_guid (&guid, &data, &size);
3009 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
3011 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
3013 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3014 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3016 flags = gst_asf_demux_get_uint16 (&data, &size);
3017 stream_id = flags & 0x7f;
3018 is_encrypted = ! !(flags & 0x8000);
3019 unknown = gst_asf_demux_get_uint32 (&data, &size);
3021 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3022 stream_id, GST_TIME_ARGS (time_offset));
3024 /* dvr-ms has audio stream declared in stream specific data */
3025 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3026 AsfExtStreamType ext_stream_type;
3027 gst_asf_demux_get_guid (&guid, &data, &size);
3028 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3030 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3031 inspect_payload = TRUE;
3033 gst_asf_demux_get_guid (&guid, &data, &size);
3034 gst_asf_demux_get_uint32 (&data, &size);
3035 gst_asf_demux_get_uint32 (&data, &size);
3036 gst_asf_demux_get_uint32 (&data, &size);
3037 gst_asf_demux_get_guid (&guid, &data, &size);
3038 gst_asf_demux_get_uint32 (&data, &size);
3039 stream_type = ASF_STREAM_AUDIO;
3043 switch (stream_type) {
3044 case ASF_STREAM_AUDIO:{
3045 asf_stream_audio audio_object;
3047 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3048 goto not_enough_data;
3050 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3053 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3056 switch (correction_type) {
3057 case ASF_CORRECTION_ON:{
3058 guint span, packet_size, chunk_size, data_size, silence_data;
3060 GST_INFO ("Using error correction");
3062 if (size < (1 + 2 + 2 + 2 + 1))
3063 goto not_enough_data;
3065 span = gst_asf_demux_get_uint8 (&data, &size);
3066 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3067 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3068 data_size = gst_asf_demux_get_uint16 (&data, &size);
3069 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3071 stream->span = span;
3073 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3074 packet_size, chunk_size, data_size, span, silence_data);
3076 if (stream->span > 1) {
3077 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3078 /* Disable descrambling */
3081 /* FIXME: this else branch was added for
3082 * weird_al_yankovic - the saga begins.asf */
3083 stream->ds_packet_size = packet_size;
3084 stream->ds_chunk_size = chunk_size;
3087 /* Descambling is enabled */
3088 stream->ds_packet_size = packet_size;
3089 stream->ds_chunk_size = chunk_size;
3092 /* Now skip the rest of the silence data */
3094 gst_bytestream_flush (demux->bs, data_size - 1);
3096 /* FIXME: CHECKME. And why -1? */
3097 if (data_size > 1) {
3098 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3099 goto not_enough_data;
3105 case ASF_CORRECTION_OFF:{
3106 GST_INFO ("Error correction off");
3107 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3108 goto not_enough_data;
3112 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3113 ("Audio stream using unknown error correction"));
3120 case ASF_STREAM_VIDEO:{
3121 asf_stream_video_format video_format_object;
3122 asf_stream_video video_object;
3125 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3126 goto not_enough_data;
3128 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3130 GST_INFO ("object is a video stream with %u bytes of "
3131 "additional data", vsize);
3133 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3135 goto not_enough_data;
3138 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3139 stream_id, &data, &size);
3145 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3147 demux->other_streams =
3148 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3153 stream->inspect_payload = inspect_payload;
3154 stream->type = stream_type;
3160 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3161 /* we'll error out later if we found no streams */
3166 static const gchar *
3167 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3171 const gchar *asf_name;
3172 const gchar *gst_name;
3175 "WM/Genre", GST_TAG_GENRE}, {
3176 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3177 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3178 "WM/Picture", GST_TAG_IMAGE}, {
3179 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3180 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3181 "WM/Year", GST_TAG_DATE_TIME}
3182 /* { "WM/Composer", GST_TAG_COMPOSER } */
3187 if (name_utf8 == NULL) {
3188 GST_WARNING ("Failed to convert name to UTF8, skipping");
3192 out = strlen (name_utf8);
3194 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3195 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3196 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3197 return tags[i].gst_name;
3204 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3206 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3210 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3212 if (taglist == NULL)
3215 if (gst_tag_list_is_empty (taglist)) {
3216 gst_tag_list_unref (taglist);
3220 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3221 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3223 gst_tag_list_unref (demux->taglist);
3224 gst_tag_list_unref (taglist);
3226 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3229 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3230 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3231 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3232 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3235 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3239 const guint8 *img_data = NULL;
3240 guint32 img_data_len = 0;
3241 guint8 pic_type = 0;
3243 gst_byte_reader_init (&r, tag_data, tag_data_len);
3245 /* skip mime type string (we don't trust it and do our own typefinding),
3246 * and also skip the description string, since we don't use it */
3247 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3248 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3249 !gst_byte_reader_skip_string_utf16 (&r) ||
3250 !gst_byte_reader_skip_string_utf16 (&r) ||
3251 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3252 goto not_enough_data;
3256 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3257 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3263 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3264 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3269 /* Extended Content Description Object */
3270 static GstFlowReturn
3271 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3274 /* Other known (and unused) 'text/unicode' metadata available :
3277 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3278 * WMFSDKVersion = 9.00.00.2980
3279 * WMFSDKNeeded = 0.0.0.0000
3280 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3281 * WM/Publisher = 4AD
3283 * WM/ProviderRating = 8
3284 * WM/ProviderStyle = Rock (similar to WM/Genre)
3285 * WM/GenreID (similar to WM/Genre)
3286 * WM/TrackNumber (same as WM/Track but as a string)
3288 * Other known (and unused) 'non-text' metadata available :
3294 * We might want to read WM/TrackNumber and use atoi() if we don't have
3298 GstTagList *taglist;
3299 guint16 blockcount, i;
3300 gboolean content3D = FALSE;
3304 const gchar *interleave_name;
3305 GstASF3DMode interleaving_type;
3306 } stereoscopic_layout_map[] = {
3308 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3309 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3310 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3311 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3312 "DualStream", GST_ASF_3D_DUAL_STREAM}
3314 GST_INFO_OBJECT (demux, "object is an extended content description");
3316 taglist = gst_tag_list_new_empty ();
3318 /* Content Descriptor Count */
3320 goto not_enough_data;
3322 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3324 for (i = 1; i <= blockcount; ++i) {
3325 const gchar *gst_tag_name;
3329 GValue tag_value = { 0, };
3332 gchar *name_utf8 = NULL;
3336 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3337 goto not_enough_data;
3341 goto not_enough_data;
3343 /* Descriptor Value Data Type */
3344 datatype = gst_asf_demux_get_uint16 (&data, &size);
3346 /* Descriptor Value (not really a string, but same thing reading-wise) */
3347 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3349 goto not_enough_data;
3353 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3355 if (name_utf8 != NULL) {
3356 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3358 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3359 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3362 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3365 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3368 /* get rid of tags with empty value */
3369 if (value_utf8 != NULL && *value_utf8 != '\0') {
3370 GST_DEBUG ("string value %s", value_utf8);
3372 value_utf8[out] = '\0';
3374 if (gst_tag_name != NULL) {
3375 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3376 guint year = atoi (value_utf8);
3379 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3380 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3382 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3383 guint id3v1_genre_id;
3384 const gchar *genre_str;
3386 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3387 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3388 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3389 g_free (value_utf8);
3390 value_utf8 = g_strdup (genre_str);
3395 /* convert tag from string to other type if required */
3396 tag_type = gst_tag_get_type (gst_tag_name);
3397 g_value_init (&tag_value, tag_type);
3398 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3399 GValue from_val = { 0, };
3401 g_value_init (&from_val, G_TYPE_STRING);
3402 g_value_set_string (&from_val, value_utf8);
3403 if (!g_value_transform (&from_val, &tag_value)) {
3404 GST_WARNING_OBJECT (demux,
3405 "Could not transform string tag to " "%s tag type %s",
3406 gst_tag_name, g_type_name (tag_type));
3407 g_value_unset (&tag_value);
3409 g_value_unset (&from_val);
3414 GST_DEBUG ("Setting metadata");
3415 g_value_init (&tag_value, G_TYPE_STRING);
3416 g_value_set_string (&tag_value, value_utf8);
3417 /* If we found a stereoscopic marker, look for StereoscopicLayout
3421 if (strncmp ("StereoscopicLayout", name_utf8,
3422 strlen (name_utf8)) == 0) {
3423 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3424 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3426 demux->asf_3D_mode =
3427 stereoscopic_layout_map[i].interleaving_type;
3428 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3432 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3434 demux->asf_3D_mode = GST_ASF_3D_NONE;
3435 GST_INFO_OBJECT (demux, "None 3d type");
3438 } else if (value_utf8 == NULL) {
3439 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3441 GST_DEBUG ("Skipping empty string value for %s",
3442 GST_STR_NULL (gst_tag_name));
3444 g_free (value_utf8);
3447 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3449 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3450 GST_FIXME ("Unhandled byte array tag %s",
3451 GST_STR_NULL (gst_tag_name));
3454 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3460 case ASF_DEMUX_DATA_TYPE_DWORD:{
3466 uint_val = GST_READ_UINT32_LE (value);
3468 /* this is the track number */
3469 g_value_init (&tag_value, G_TYPE_UINT);
3471 /* WM/Track counts from 0 */
3472 if (!strcmp (name_utf8, "WM/Track"))
3475 g_value_set_uint (&tag_value, uint_val);
3479 case ASF_DEMUX_DATA_TYPE_BOOL:{
3485 bool_val = GST_READ_UINT32_LE (value);
3487 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3489 GST_INFO_OBJECT (demux, "This is 3D contents");
3492 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3500 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3505 if (G_IS_VALUE (&tag_value)) {
3507 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3509 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3510 * is supposed to have a 0 base but is often wrongly written to start
3511 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3512 * replace the value added earlier from WM/Track or put it first in
3513 * the list, so that it will get picked up by _get_uint() */
3514 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3515 merge_mode = GST_TAG_MERGE_REPLACE;
3517 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3520 GST_DEBUG ("Setting global metadata %s", name_utf8);
3521 gst_structure_set_value (demux->global_metadata, name_utf8,
3525 g_value_unset (&tag_value);
3534 gst_asf_demux_add_global_tags (demux, taglist);
3541 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3542 gst_tag_list_unref (taglist);
3543 return GST_FLOW_OK; /* not really fatal */
3547 static GstStructure *
3548 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3553 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3555 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3558 s = gst_caps_get_structure (demux->metadata, i);
3559 if (gst_structure_has_name (s, sname))
3563 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3565 /* try lookup again; demux->metadata took ownership of the structure, so we
3566 * can't really make any assumptions about what happened to it, so we can't
3567 * just return it directly after appending it */
3568 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3571 static GstFlowReturn
3572 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3575 guint16 blockcount, i;
3577 GST_INFO_OBJECT (demux, "object is a metadata object");
3579 /* Content Descriptor Count */
3581 goto not_enough_data;
3583 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3585 for (i = 0; i < blockcount; ++i) {
3587 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3588 guint32 data_len, ival;
3591 if (size < (2 + 2 + 2 + 2 + 4))
3592 goto not_enough_data;
3594 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3595 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3596 name_len = gst_asf_demux_get_uint16 (&data, &size);
3597 data_type = gst_asf_demux_get_uint16 (&data, &size);
3598 data_len = gst_asf_demux_get_uint32 (&data, &size);
3600 if (size < name_len + data_len)
3601 goto not_enough_data;
3603 /* convert name to UTF-8 */
3604 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3606 gst_asf_demux_skip_bytes (name_len, &data, &size);
3608 if (name_utf8 == NULL) {
3609 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3610 gst_asf_demux_skip_bytes (data_len, &data, &size);
3614 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3615 gst_asf_demux_skip_bytes (data_len, &data, &size);
3623 goto not_enough_data;
3626 ival = gst_asf_demux_get_uint32 (&data, &size);
3628 /* skip anything else there may be, just in case */
3629 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3631 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3632 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3636 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3642 GST_WARNING ("Unexpected end of data parsing metadata object");
3643 return GST_FLOW_OK; /* not really fatal */
3647 static GstFlowReturn
3648 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3650 GstFlowReturn ret = GST_FLOW_OK;
3651 guint32 i, num_objects;
3652 guint8 unknown G_GNUC_UNUSED;
3654 /* Get the rest of the header's header */
3655 if (size < (4 + 1 + 1))
3656 goto not_enough_data;
3658 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3659 unknown = gst_asf_demux_get_uint8 (&data, &size);
3660 unknown = gst_asf_demux_get_uint8 (&data, &size);
3662 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3663 demux->saw_file_header = FALSE;
3664 /* Loop through the header's objects, processing those */
3665 for (i = 0; i < num_objects; ++i) {
3666 GST_INFO_OBJECT (demux, "reading header part %u", i);
3667 ret = gst_asf_demux_process_object (demux, &data, &size);
3668 if (ret != GST_FLOW_OK) {
3669 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3673 if (!demux->saw_file_header) {
3674 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3675 ("Header does not have mandatory FILE section"));
3676 return GST_FLOW_ERROR;
3683 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3684 ("short read parsing HEADER object"));
3685 return GST_FLOW_ERROR;
3689 static GstFlowReturn
3690 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3692 guint64 creation_time G_GNUC_UNUSED;
3693 guint64 file_size G_GNUC_UNUSED;
3694 guint64 send_time G_GNUC_UNUSED;
3695 guint64 packets_count, play_time, preroll;
3696 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3698 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3699 goto not_enough_data;
3701 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3702 file_size = gst_asf_demux_get_uint64 (&data, &size);
3703 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3704 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3705 play_time = gst_asf_demux_get_uint64 (&data, &size);
3706 send_time = gst_asf_demux_get_uint64 (&data, &size);
3707 preroll = gst_asf_demux_get_uint64 (&data, &size);
3708 flags = gst_asf_demux_get_uint32 (&data, &size);
3709 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3710 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3711 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3713 demux->broadcast = ! !(flags & 0x01);
3714 demux->seekable = ! !(flags & 0x02);
3716 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3717 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3718 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3720 if (demux->broadcast) {
3721 /* these fields are invalid if the broadcast flag is set */
3726 if (min_pktsize != max_pktsize)
3727 goto non_fixed_packet_size;
3729 demux->packet_size = max_pktsize;
3731 /* FIXME: do we need send_time as well? what is it? */
3732 if ((play_time * 100) >= (preroll * GST_MSECOND))
3733 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3735 demux->play_time = 0;
3737 demux->preroll = preroll * GST_MSECOND;
3739 /* initial latency */
3740 demux->latency = demux->preroll;
3742 if (demux->play_time == 0)
3743 demux->seekable = FALSE;
3745 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3746 GST_TIME_ARGS (demux->play_time));
3747 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3748 GST_TIME_ARGS (demux->preroll));
3750 if (demux->play_time > 0) {
3751 demux->segment.duration = demux->play_time;
3754 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3756 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3758 demux->saw_file_header = TRUE;
3763 non_fixed_packet_size:
3765 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3766 ("packet size must be fixed"));
3767 return GST_FLOW_ERROR;
3771 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3772 ("short read parsing FILE object"));
3773 return GST_FLOW_ERROR;
3777 /* Content Description Object */
3778 static GstFlowReturn
3779 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3783 const gchar *gst_tag;
3788 GST_TAG_TITLE, 0, NULL}, {
3789 GST_TAG_ARTIST, 0, NULL}, {
3790 GST_TAG_COPYRIGHT, 0, NULL}, {
3791 GST_TAG_DESCRIPTION, 0, NULL}, {
3792 GST_TAG_COMMENT, 0, NULL}
3794 GstTagList *taglist;
3795 GValue value = { 0 };
3799 GST_INFO_OBJECT (demux, "object is a comment");
3801 if (size < (2 + 2 + 2 + 2 + 2))
3802 goto not_enough_data;
3804 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3805 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3806 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3807 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3808 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3810 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3811 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3812 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3814 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3815 if (size < tags[i].val_length)
3816 goto not_enough_data;
3818 /* might be just '/0', '/0'... */
3819 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3820 /* convert to UTF-8 */
3821 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3822 "UTF-8", "UTF-16LE", &in, &out, NULL);
3824 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3827 /* parse metadata into taglist */
3828 taglist = gst_tag_list_new_empty ();
3829 g_value_init (&value, G_TYPE_STRING);
3830 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3831 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3832 g_value_set_string (&value, tags[i].val_utf8);
3833 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3834 tags[i].gst_tag, &value, NULL);
3837 g_value_unset (&value);
3839 gst_asf_demux_add_global_tags (demux, taglist);
3841 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3842 g_free (tags[i].val_utf8);
3848 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3849 "comment tag section %d, skipping comment object", i);
3850 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3851 g_free (tags[i].val_utf8);
3852 return GST_FLOW_OK; /* not really fatal */
3856 static GstFlowReturn
3857 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3860 guint16 num_streams, i;
3864 goto not_enough_data;
3866 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3868 GST_INFO ("object is a bitrate properties object with %u streams",
3871 if (size < (num_streams * (2 + 4)))
3872 goto not_enough_data;
3874 for (i = 0; i < num_streams; ++i) {
3878 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3879 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3881 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3882 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3883 stream = gst_asf_demux_get_stream (demux, stream_id);
3885 if (stream->pending_tags == NULL)
3886 stream->pending_tags = gst_tag_list_new_empty ();
3887 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3888 GST_TAG_BITRATE, bitrate, NULL);
3890 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3893 GST_WARNING ("stream id %u is too large", stream_id);
3901 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3902 return GST_FLOW_OK; /* not really fatal */
3906 static GstFlowReturn
3907 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3910 GstFlowReturn ret = GST_FLOW_OK;
3913 /* Get the rest of the header's header */
3914 if (size < (16 + 2 + 4))
3915 goto not_enough_data;
3917 /* skip GUID and two other bytes */
3918 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3919 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3921 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3923 /* FIXME: does data_size include the rest of the header that we have read? */
3924 if (hdr_size > size)
3925 goto not_enough_data;
3927 while (hdr_size > 0) {
3928 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3929 if (ret != GST_FLOW_OK)
3937 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3938 ("short read parsing extended header object"));
3939 return GST_FLOW_ERROR;
3943 static GstFlowReturn
3944 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3950 goto not_enough_data;
3952 if (demux->languages) {
3953 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3954 g_strfreev (demux->languages);
3955 demux->languages = NULL;
3956 demux->num_languages = 0;
3959 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3960 GST_LOG ("%u languages:", demux->num_languages);
3962 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3963 for (i = 0; i < demux->num_languages; ++i) {
3964 guint8 len, *lang_data = NULL;
3967 goto not_enough_data;
3968 len = gst_asf_demux_get_uint8 (&data, &size);
3969 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3972 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3975 /* truncate "en-us" etc. to just "en" */
3976 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3979 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3980 demux->languages[i] = utf8;
3983 goto not_enough_data;
3991 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3992 g_free (demux->languages);
3993 demux->languages = NULL;
3994 demux->num_languages = 0;
3995 return GST_FLOW_OK; /* not fatal */
3999 static GstFlowReturn
4000 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
4003 GstClockTime interval;
4006 if (size < (16 + 8 + 4 + 4))
4007 goto not_enough_data;
4010 gst_asf_demux_skip_bytes (16, &data, &size);
4011 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
4012 gst_asf_demux_skip_bytes (4, &data, &size);
4013 count = gst_asf_demux_get_uint32 (&data, &size);
4015 demux->sidx_interval = interval;
4016 demux->sidx_num_entries = count;
4017 g_free (demux->sidx_entries);
4018 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
4020 for (i = 0; i < count; ++i) {
4021 if (G_UNLIKELY (size < 6)) {
4022 /* adjust for broken files, to avoid having entries at the end
4023 * of the parsed index that point to time=0. Resulting in seeking to
4024 * the end of the file leading back to the beginning */
4025 demux->sidx_num_entries -= (count - i);
4028 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4029 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4030 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4031 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4032 demux->sidx_entries[i].count);
4035 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4042 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4043 return GST_FLOW_OK; /* not fatal */
4047 static GstFlowReturn
4048 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4049 guint8 * data, guint64 size)
4054 if (size < 16 + 2 + (2 * 2))
4055 goto not_enough_data;
4057 gst_asf_demux_get_guid (&guid, &data, &size);
4058 num = gst_asf_demux_get_uint16 (&data, &size);
4061 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4065 if (size < (num * sizeof (guint16)))
4066 goto not_enough_data;
4068 /* read mutually exclusive stream numbers */
4069 for (i = 0; i < num; ++i) {
4071 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4072 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4074 demux->mut_ex_streams =
4075 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4084 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4085 return GST_FLOW_OK; /* not absolutely fatal */
4090 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4092 return g_slist_find (demux->other_streams,
4093 GINT_TO_POINTER (stream_num)) == NULL;
4096 static GstFlowReturn
4097 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4100 AsfStreamExtProps esp;
4101 AsfStream *stream = NULL;
4102 AsfObject stream_obj;
4103 guint16 stream_name_count;
4104 guint16 num_payload_ext;
4106 guint8 *stream_obj_data = NULL;
4109 guint i, stream_num;
4112 obj_size = (guint) size;
4114 esp.payload_extensions = NULL;
4117 goto not_enough_data;
4120 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4121 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4122 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4123 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4124 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4125 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4126 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4127 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4128 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4129 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4130 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4131 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4132 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4133 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4134 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4136 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4137 GST_TIME_ARGS (esp.start_time));
4138 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4139 GST_TIME_ARGS (esp.end_time));
4140 GST_INFO ("flags = %08x", esp.flags);
4141 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4142 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4143 GST_INFO ("stream number = %u", stream_num);
4144 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4145 (esp.lang_idx < demux->num_languages) ?
4146 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4147 GST_INFO ("stream name count = %u", stream_name_count);
4149 /* read stream names */
4150 for (i = 0; i < stream_name_count; ++i) {
4151 guint16 stream_lang_idx G_GNUC_UNUSED;
4152 gchar *stream_name = NULL;
4155 goto not_enough_data;
4156 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4157 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4158 goto not_enough_data;
4159 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4160 g_free (stream_name); /* TODO: store names in struct */
4163 /* read payload extension systems stuff */
4164 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4166 if (num_payload_ext > 0)
4167 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4169 for (i = 0; i < num_payload_ext; ++i) {
4170 AsfPayloadExtension ext;
4172 guint32 sys_info_len;
4174 if (size < 16 + 2 + 4)
4175 goto not_enough_data;
4177 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4178 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4179 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4181 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4182 GST_LOG ("payload systems info len = %u", sys_info_len);
4183 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4184 goto not_enough_data;
4186 esp.payload_extensions[i] = ext;
4189 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4191 /* there might be an optional STREAM_INFO object here now; if not, we
4192 * should have parsed the corresponding stream info object already (since
4193 * we are parsing the extended stream properties objects delayed) */
4195 stream = gst_asf_demux_get_stream (demux, stream_num);
4199 if (size < ASF_OBJECT_HEADER_SIZE)
4200 goto not_enough_data;
4202 /* get size of the stream object */
4203 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4204 goto corrupted_stream;
4206 if (stream_obj.id != ASF_OBJ_STREAM)
4207 goto expected_stream_object;
4209 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4210 stream_obj.size > (10 * 1024 * 1024))
4211 goto not_enough_data;
4213 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4215 /* process this stream object later after all the other 'normal' ones
4216 * have been processed (since the others are more important/non-hidden) */
4217 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4218 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4219 goto not_enough_data;
4221 /* parse stream object */
4222 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4223 g_free (stream_obj_data);
4228 stream->ext_props = esp;
4230 /* try to set the framerate */
4231 if (stream->is_video && stream->caps) {
4232 GValue framerate = { 0 };
4236 g_value_init (&framerate, GST_TYPE_FRACTION);
4238 num = GST_SECOND / 100;
4239 denom = esp.avg_time_per_frame;
4241 /* avoid division by 0, assume 25/1 framerate */
4242 denom = GST_SECOND / 2500;
4245 gst_value_set_fraction (&framerate, num, denom);
4247 stream->caps = gst_caps_make_writable (stream->caps);
4248 s = gst_caps_get_structure (stream->caps, 0);
4249 gst_structure_set_value (s, "framerate", &framerate);
4250 g_value_unset (&framerate);
4251 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4252 num, denom, ((gdouble) num) / denom);
4255 /* add language info now if we have it */
4256 if (stream->ext_props.lang_idx < demux->num_languages) {
4257 if (stream->pending_tags == NULL)
4258 stream->pending_tags = gst_tag_list_new_empty ();
4259 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4260 demux->languages[stream->ext_props.lang_idx]);
4261 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4262 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4265 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4266 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4270 g_free (esp.payload_extensions);
4277 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4278 g_free (esp.payload_extensions);
4279 return GST_FLOW_OK; /* not absolutely fatal */
4281 expected_stream_object:
4283 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4284 "object: expected embedded stream object, but got %s object instead!",
4285 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4286 g_free (esp.payload_extensions);
4287 return GST_FLOW_OK; /* not absolutely fatal */
4291 GST_WARNING_OBJECT (demux, "Corrupted stream");
4292 g_free (esp.payload_extensions);
4293 return GST_FLOW_ERROR;
4297 static const gchar *
4298 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4302 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4303 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4304 nick += strlen ("ASF_OBJ_");
4306 if (demux->objpath == NULL) {
4307 demux->objpath = g_strdup (nick);
4311 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4312 g_free (demux->objpath);
4313 demux->objpath = newpath;
4316 return (const gchar *) demux->objpath;
4320 gst_asf_demux_pop_obj (GstASFDemux * demux)
4324 if ((s = g_strrstr (demux->objpath, "/"))) {
4327 g_free (demux->objpath);
4328 demux->objpath = NULL;
4333 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4338 /* Parse the queued extended stream property objects and add the info
4339 * to the existing streams or add the new embedded streams, but without
4340 * activating them yet */
4341 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4342 g_slist_length (demux->ext_stream_props));
4344 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4345 GstBuffer *buf = GST_BUFFER (l->data);
4348 gst_buffer_map (buf, &map, GST_MAP_READ);
4350 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4351 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4352 gst_buffer_unmap (buf, &map);
4353 gst_buffer_unref (buf);
4355 g_slist_free (demux->ext_stream_props);
4356 demux->ext_stream_props = NULL;
4361 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4365 for (i = 0; i < demux->num_streams; ++i) {
4370 stream = &demux->stream[i];
4372 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4374 if (stream->active) {
4375 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4380 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4383 /* check for each mutual exclusion whether it affects this stream */
4384 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4385 if (*mes == stream->id) {
4386 /* if yes, check if we've already added streams that are mutually
4387 * exclusive with the stream we're about to add */
4388 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4389 for (j = 0; j < demux->num_streams; ++j) {
4390 /* if the broadcast flag is set, assume the hidden streams aren't
4391 * actually streamed and hide them (or playbin won't work right),
4392 * otherwise assume their data is available */
4393 if (demux->stream[j].id == *mes && demux->broadcast) {
4395 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4396 "mutually exclusive with already existing stream ID %d, "
4397 "hiding stream", stream->id, demux->stream[j].id);
4409 /* FIXME: we should do stream activation based on preroll data in
4410 * streaming mode too */
4411 if (demux->streaming && !is_hidden)
4412 gst_asf_demux_activate_stream (demux, stream);
4417 static GstFlowReturn
4418 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4421 GstFlowReturn ret = GST_FLOW_OK;
4423 guint64 obj_data_size;
4425 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4426 return ASF_FLOW_NEED_MORE_DATA;
4428 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4430 return GST_FLOW_ERROR;
4431 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4433 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4435 if (*p_size < obj_data_size)
4436 return ASF_FLOW_NEED_MORE_DATA;
4438 gst_asf_demux_push_obj (demux, obj.id);
4440 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4443 case ASF_OBJ_STREAM:
4444 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4448 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4450 case ASF_OBJ_HEADER:
4451 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4453 case ASF_OBJ_COMMENT:
4454 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4457 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4459 case ASF_OBJ_BITRATE_PROPS:
4461 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4464 case ASF_OBJ_EXT_CONTENT_DESC:
4466 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4469 case ASF_OBJ_METADATA_OBJECT:
4470 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4472 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4475 /* process these later, we might not have parsed the corresponding
4476 * stream object yet */
4477 GST_LOG ("%s: queued for later parsing", demux->objpath);
4478 buf = gst_buffer_new_and_alloc (obj_data_size);
4479 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4480 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4484 case ASF_OBJ_LANGUAGE_LIST:
4485 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4487 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4488 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4491 case ASF_OBJ_SIMPLE_INDEX:
4492 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4494 case ASF_OBJ_CONTENT_ENCRYPTION:
4495 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4496 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4497 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4498 goto error_encrypted;
4499 case ASF_OBJ_CONCEAL_NONE:
4501 case ASF_OBJ_UNDEFINED:
4502 case ASF_OBJ_CODEC_COMMENT:
4504 case ASF_OBJ_PADDING:
4505 case ASF_OBJ_BITRATE_MUTEX:
4506 case ASF_OBJ_COMPATIBILITY:
4507 case ASF_OBJ_INDEX_PLACEHOLDER:
4508 case ASF_OBJ_INDEX_PARAMETERS:
4509 case ASF_OBJ_STREAM_PRIORITIZATION:
4510 case ASF_OBJ_SCRIPT_COMMAND:
4511 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4513 /* Unknown/unhandled object, skip it and hope for the best */
4514 GST_INFO ("%s: skipping object", demux->objpath);
4519 /* this can't fail, we checked the number of bytes available before */
4520 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4522 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4524 gst_asf_demux_pop_obj (demux);
4531 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4532 return GST_FLOW_ERROR;
4537 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4538 GstBuffer ** p_buffer)
4540 GstBuffer *descrambled_buffer;
4541 GstBuffer *scrambled_buffer;
4542 GstBuffer *sub_buffer;
4549 /* descrambled_buffer is initialised in the first iteration */
4550 descrambled_buffer = NULL;
4551 scrambled_buffer = *p_buffer;
4553 if (gst_buffer_get_size (scrambled_buffer) <
4554 stream->ds_packet_size * stream->span)
4557 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4558 offset += stream->ds_chunk_size) {
4559 off = offset / stream->ds_chunk_size;
4560 row = off / stream->span;
4561 col = off % stream->span;
4562 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4563 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4564 col, off, stream->ds_chunk_size);
4565 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4566 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4567 stream->span, stream->ds_packet_size);
4568 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4569 gst_buffer_get_size (scrambled_buffer));
4571 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4572 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4574 descrambled_buffer = sub_buffer;
4576 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4580 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4581 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4582 GST_BUFFER_DURATION (descrambled_buffer) =
4583 GST_BUFFER_DURATION (scrambled_buffer);
4584 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4585 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4586 GST_BUFFER_OFFSET_END (scrambled_buffer);
4588 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4590 gst_buffer_unref (scrambled_buffer);
4591 *p_buffer = descrambled_buffer;
4595 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4597 GstASFDemux *demux = GST_ASF_DEMUX (element);
4600 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4602 for (i = 0; i < demux->num_streams; ++i) {
4603 gst_event_ref (event);
4604 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4605 GST_OBJECT_CAST (element), event)) {
4606 gst_event_unref (event);
4611 gst_event_unref (event);
4615 /* takes ownership of the passed event */
4617 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4619 gboolean ret = TRUE;
4622 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4623 GST_EVENT_TYPE_NAME (event));
4625 for (i = 0; i < demux->num_streams; ++i) {
4626 gst_event_ref (event);
4627 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4629 gst_event_unref (event);
4634 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4638 gboolean res = FALSE;
4640 demux = GST_ASF_DEMUX (parent);
4642 GST_DEBUG ("handling %s query",
4643 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4645 switch (GST_QUERY_TYPE (query)) {
4646 case GST_QUERY_DURATION:
4650 gst_query_parse_duration (query, &format, NULL);
4652 if (format != GST_FORMAT_TIME) {
4653 GST_LOG ("only support duration queries in TIME format");
4657 res = gst_pad_query_default (pad, parent, query);
4659 GST_OBJECT_LOCK (demux);
4661 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4662 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4663 GST_TIME_ARGS (demux->segment.duration));
4665 gst_query_set_duration (query, GST_FORMAT_TIME,
4666 demux->segment.duration);
4670 GST_LOG ("duration not known yet");
4673 GST_OBJECT_UNLOCK (demux);
4678 case GST_QUERY_POSITION:{
4681 gst_query_parse_position (query, &format, NULL);
4683 if (format != GST_FORMAT_TIME) {
4684 GST_LOG ("only support position queries in TIME format");
4688 GST_OBJECT_LOCK (demux);
4690 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4691 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4692 GST_TIME_ARGS (demux->segment.position));
4694 gst_query_set_position (query, GST_FORMAT_TIME,
4695 demux->segment.position);
4699 GST_LOG ("position not known yet");
4702 GST_OBJECT_UNLOCK (demux);
4706 case GST_QUERY_SEEKING:{
4709 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4710 if (format == GST_FORMAT_TIME) {
4713 GST_OBJECT_LOCK (demux);
4714 duration = demux->segment.duration;
4715 GST_OBJECT_UNLOCK (demux);
4717 if (!demux->streaming || !demux->seekable) {
4718 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4725 /* try upstream first in TIME */
4726 res = gst_pad_query_default (pad, parent, query);
4728 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4729 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4730 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4731 /* if no luck, maybe in BYTES */
4732 if (!seekable || fmt != GST_FORMAT_TIME) {
4735 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4736 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4737 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4738 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4739 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4740 if (fmt != GST_FORMAT_BYTES)
4743 gst_query_unref (q);
4744 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4750 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4754 case GST_QUERY_LATENCY:
4757 GstClockTime min, max;
4759 /* preroll delay does not matter in non-live pipeline,
4760 * but we might end up in a live (rtsp) one ... */
4763 res = gst_pad_query_default (pad, parent, query);
4767 gst_query_parse_latency (query, &live, &min, &max);
4769 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4770 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4771 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4773 GST_OBJECT_LOCK (demux);
4774 min += demux->latency;
4776 max += demux->latency;
4777 GST_OBJECT_UNLOCK (demux);
4779 gst_query_set_latency (query, live, min, max);
4782 case GST_QUERY_SEGMENT:
4787 format = demux->segment.format;
4790 gst_segment_to_stream_time (&demux->segment, format,
4791 demux->segment.start);
4792 if ((stop = demux->segment.stop) == -1)
4793 stop = demux->segment.duration;
4795 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4797 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4802 res = gst_pad_query_default (pad, parent, query);
4809 static GstStateChangeReturn
4810 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4812 GstASFDemux *demux = GST_ASF_DEMUX (element);
4813 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4815 switch (transition) {
4816 case GST_STATE_CHANGE_NULL_TO_READY:{
4817 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4818 demux->need_newsegment = TRUE;
4819 demux->segment_running = FALSE;
4820 demux->keyunit_sync = FALSE;
4821 demux->accurate = FALSE;
4822 demux->adapter = gst_adapter_new ();
4823 demux->metadata = gst_caps_new_empty ();
4824 demux->global_metadata = gst_structure_new_empty ("metadata");
4825 demux->data_size = 0;
4826 demux->data_offset = 0;
4827 demux->index_offset = 0;
4828 demux->base_offset = 0;
4829 demux->flowcombiner = gst_flow_combiner_new ();
4837 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4838 if (ret == GST_STATE_CHANGE_FAILURE)
4841 switch (transition) {
4842 case GST_STATE_CHANGE_PAUSED_TO_READY:
4843 gst_asf_demux_reset (demux, FALSE);
4846 case GST_STATE_CHANGE_READY_TO_NULL:
4847 gst_asf_demux_reset (demux, FALSE);
4848 gst_flow_combiner_free (demux->flowcombiner);
4849 demux->flowcombiner = NULL;