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 "gstasfelements.h"
47 #include "gstasfdemux.h"
48 #include "asfheaders.h"
49 #include "asfpacket.h"
51 GST_DEBUG_CATEGORY (asfdemux_dbg);
52 #define GST_CAT_DEFAULT asfdemux_dbg
54 static GstStaticPadTemplate gst_asf_demux_sink_template =
55 GST_STATIC_PAD_TEMPLATE ("sink",
58 GST_STATIC_CAPS ("video/x-ms-asf")
61 static GstStaticPadTemplate audio_src_template =
62 GST_STATIC_PAD_TEMPLATE ("audio_%u",
67 static GstStaticPadTemplate video_src_template =
68 GST_STATIC_PAD_TEMPLATE ("video_%u",
73 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
74 #define ASF_OBJECT_HEADER_SIZE (16+8)
76 /* FIXME: get rid of this */
77 /* abuse this GstFlowReturn enum for internal usage */
78 #define ASF_FLOW_NEED_MORE_DATA 99
80 #define gst_asf_get_flow_name(flow) \
81 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
82 "need-more-data" : gst_flow_get_name (flow)
84 static void gst_asf_demux_finalize (GObject * object);
85 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
86 GstStateChange transition);
87 static gboolean gst_asf_demux_element_send_event (GstElement * element,
89 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
91 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
92 GstObject * parent, GstQuery * query);
93 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
95 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
97 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
98 guint8 ** p_data, guint64 * p_size);
99 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
100 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
101 GstObject * parent, GstPadMode mode, gboolean active);
102 static void gst_asf_demux_loop (GstASFDemux * demux);
104 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
105 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
106 GstFlowReturn * pflow);
107 static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
108 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
110 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
111 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
112 AsfStream * stream, GstBuffer ** p_buffer);
113 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
115 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
117 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
120 #define gst_asf_demux_parent_class parent_class
121 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
122 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (asfdemux, "asfdemux", GST_RANK_SECONDARY,
123 GST_TYPE_ASF_DEMUX, asf_element_init (plugin));
126 gst_asf_demux_class_init (GstASFDemuxClass * klass)
128 GObjectClass *gobject_class;
129 GstElementClass *gstelement_class;
131 gobject_class = G_OBJECT_CLASS (klass);
132 gstelement_class = (GstElementClass *) klass;
134 gobject_class->finalize = gst_asf_demux_finalize;
136 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
138 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
140 gst_element_class_add_static_pad_template (gstelement_class,
141 &audio_src_template);
142 gst_element_class_add_static_pad_template (gstelement_class,
143 &video_src_template);
144 gst_element_class_add_static_pad_template (gstelement_class,
145 &gst_asf_demux_sink_template);
147 gstelement_class->change_state =
148 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
149 gstelement_class->send_event =
150 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
154 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
156 gst_caps_replace (&stream->caps, NULL);
157 if (stream->pending_tags) {
158 gst_tag_list_unref (stream->pending_tags);
159 stream->pending_tags = NULL;
161 if (stream->streamheader) {
162 gst_buffer_unref (stream->streamheader);
163 stream->streamheader = NULL;
166 if (stream->active) {
167 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
168 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
170 gst_object_unref (stream->pad);
174 if (stream->payloads) {
175 while (stream->payloads->len > 0) {
179 last = stream->payloads->len - 1;
180 payload = &g_array_index (stream->payloads, AsfPayload, last);
181 gst_buffer_replace (&payload->buf, NULL);
182 g_array_remove_index (stream->payloads, last);
184 g_array_free (stream->payloads, TRUE);
185 stream->payloads = NULL;
188 if (stream->payloads_rev) {
189 while (stream->payloads_rev->len > 0) {
193 last = stream->payloads_rev->len - 1;
194 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
195 gst_buffer_replace (&payload->buf, NULL);
196 g_array_remove_index (stream->payloads_rev, last);
198 g_array_free (stream->payloads_rev, TRUE);
199 stream->payloads_rev = NULL;
202 if (stream->ext_props.valid) {
203 g_free (stream->ext_props.payload_extensions);
204 stream->ext_props.payload_extensions = NULL;
209 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
211 GST_LOG_OBJECT (demux, "resetting");
213 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
214 demux->segment_running = FALSE;
215 if (demux->adapter && !chain_reset) {
216 gst_adapter_clear (demux->adapter);
217 g_object_unref (demux->adapter);
218 demux->adapter = NULL;
220 if (demux->taglist) {
221 gst_tag_list_unref (demux->taglist);
222 demux->taglist = NULL;
224 if (demux->metadata) {
225 gst_caps_unref (demux->metadata);
226 demux->metadata = NULL;
228 demux->metadata = gst_caps_new_empty ();
229 if (demux->global_metadata) {
230 gst_structure_free (demux->global_metadata);
231 demux->global_metadata = NULL;
233 demux->global_metadata = gst_structure_new_empty ("metadata");
234 if (demux->mut_ex_streams) {
235 g_slist_free (demux->mut_ex_streams);
236 demux->mut_ex_streams = NULL;
239 demux->state = GST_ASF_DEMUX_STATE_HEADER;
240 g_free (demux->objpath);
241 demux->objpath = NULL;
242 g_strfreev (demux->languages);
243 demux->languages = NULL;
244 demux->num_languages = 0;
245 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
247 g_slist_free (demux->ext_stream_props);
248 demux->ext_stream_props = NULL;
250 while (demux->old_num_streams > 0) {
251 gst_asf_demux_free_stream (demux,
252 &demux->old_stream[demux->old_num_streams - 1]);
253 --demux->old_num_streams;
255 memset (demux->old_stream, 0, sizeof (demux->old_stream));
256 demux->old_num_streams = 0;
258 /* when resetting for a new chained asf, we don't want to remove the pads
259 * before adding the new ones */
261 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
262 demux->old_num_streams = demux->num_streams;
263 demux->num_streams = 0;
266 while (demux->num_streams > 0) {
267 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
268 --demux->num_streams;
270 memset (demux->stream, 0, sizeof (demux->stream));
272 /* do not remove those for not adding pads with same name */
273 demux->num_audio_streams = 0;
274 demux->num_video_streams = 0;
275 demux->have_group_id = FALSE;
276 demux->group_id = G_MAXUINT;
278 demux->num_streams = 0;
279 demux->activated_streams = FALSE;
280 demux->first_ts = GST_CLOCK_TIME_NONE;
281 demux->segment_ts = GST_CLOCK_TIME_NONE;
284 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
285 demux->state = GST_ASF_DEMUX_STATE_HEADER;
286 demux->seekable = FALSE;
287 demux->broadcast = FALSE;
288 demux->sidx_interval = 0;
289 demux->sidx_num_entries = 0;
290 g_free (demux->sidx_entries);
291 demux->sidx_entries = NULL;
293 demux->speed_packets = 1;
295 demux->asf_3D_mode = GST_ASF_3D_NONE;
298 GST_LOG_OBJECT (demux, "Restarting");
299 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
300 demux->need_newsegment = TRUE;
301 demux->segment_seqnum = 0;
302 demux->segment_running = FALSE;
303 demux->keyunit_sync = FALSE;
304 demux->accurate = FALSE;
305 demux->data_size = 0;
306 demux->data_offset = 0;
307 demux->index_offset = 0;
309 demux->base_offset = 0;
312 g_slist_free (demux->other_streams);
313 demux->other_streams = NULL;
317 gst_asf_demux_init (GstASFDemux * demux)
320 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
321 gst_pad_set_chain_function (demux->sinkpad,
322 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
323 gst_pad_set_event_function (demux->sinkpad,
324 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
325 gst_pad_set_activate_function (demux->sinkpad,
326 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
327 gst_pad_set_activatemode_function (demux->sinkpad,
328 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
329 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
331 /* set initial state */
332 gst_asf_demux_reset (demux, FALSE);
336 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
341 query = gst_query_new_scheduling ();
343 if (!gst_pad_peer_query (sinkpad, query)) {
344 gst_query_unref (query);
348 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
349 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
350 gst_query_unref (query);
355 GST_DEBUG_OBJECT (sinkpad, "activating pull");
356 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
360 GST_DEBUG_OBJECT (sinkpad, "activating push");
361 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
366 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
367 GstPadMode mode, gboolean active)
372 demux = GST_ASF_DEMUX (parent);
375 case GST_PAD_MODE_PUSH:
376 demux->state = GST_ASF_DEMUX_STATE_HEADER;
377 demux->streaming = TRUE;
380 case GST_PAD_MODE_PULL:
382 demux->state = GST_ASF_DEMUX_STATE_HEADER;
383 demux->streaming = FALSE;
385 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
388 res = gst_pad_stop_task (sinkpad);
399 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
404 demux = GST_ASF_DEMUX (parent);
406 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
407 switch (GST_EVENT_TYPE (event)) {
408 case GST_EVENT_SEGMENT:{
409 const GstSegment *segment;
411 gst_event_parse_segment (event, &segment);
413 if (segment->format == GST_FORMAT_BYTES) {
414 if (demux->packet_size && segment->start > demux->data_offset)
415 demux->packet = (segment->start - demux->data_offset) /
419 } else if (segment->format == GST_FORMAT_TIME) {
420 /* do not know packet position, not really a problem */
423 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
424 gst_event_unref (event);
428 /* record upstream segment for interpolation */
429 if (segment->format != demux->in_segment.format)
430 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
431 gst_segment_copy_into (segment, &demux->in_segment);
433 /* in either case, clear some state and generate newsegment later on */
434 GST_OBJECT_LOCK (demux);
435 demux->segment_ts = GST_CLOCK_TIME_NONE;
436 demux->in_gap = GST_CLOCK_TIME_NONE;
437 demux->need_newsegment = TRUE;
438 demux->segment_seqnum = gst_event_get_seqnum (event);
439 gst_asf_demux_reset_stream_state_after_discont (demux);
440 /* if we seek back after reaching EOS, go back to packet reading state */
441 if (demux->data_offset > 0 && segment->start >= demux->data_offset
442 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
443 demux->state = GST_ASF_DEMUX_STATE_DATA;
445 GST_OBJECT_UNLOCK (demux);
447 gst_event_unref (event);
453 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
454 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
455 (_("This stream contains no data.")),
456 ("got eos and didn't receive a complete header object"));
459 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
460 if (!demux->activated_streams) {
461 /* If we still haven't got activated streams, the file is most likely corrupt */
462 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
463 (_("This stream contains no data.")),
464 ("got eos and didn't receive a complete header object"));
467 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
468 GST_ELEMENT_FLOW_ERROR (demux, flow);
472 GST_OBJECT_LOCK (demux);
473 gst_adapter_clear (demux->adapter);
474 GST_OBJECT_UNLOCK (demux);
475 gst_asf_demux_send_event_unlocked (demux, event);
479 case GST_EVENT_FLUSH_STOP:
480 GST_OBJECT_LOCK (demux);
481 gst_asf_demux_reset_stream_state_after_discont (demux);
482 GST_OBJECT_UNLOCK (demux);
483 gst_asf_demux_send_event_unlocked (demux, event);
484 /* upon activation, latency is no longer introduced, e.g. after seek */
485 if (demux->activated_streams)
490 ret = gst_pad_event_default (pad, parent, event);
498 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
499 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
500 gboolean next, gboolean * eos)
502 GstClockTime idx_time;
508 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
511 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
514 /* if we want the next keyframe, we have to go forward till we find
515 a different packet number */
517 if (idx >= demux->sidx_num_entries - 1) {
518 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
523 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
524 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
531 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
537 *packet = demux->sidx_entries[idx].packet;
539 *speed = demux->sidx_entries[idx].count;
541 /* so we get closer to the actual time of the packet ... actually, let's not
542 * do this, since we throw away superfluous payloads before the seek position
543 * anyway; this way, our key unit seek 'snap resolution' is a bit better
544 * (ie. same as index resolution) */
546 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
550 idx_time = demux->sidx_interval * idx;
551 if (G_LIKELY (idx_time >= demux->preroll))
552 idx_time -= demux->preroll;
554 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
555 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
556 GST_TIME_ARGS (idx_time));
558 if (G_LIKELY (p_idx_time))
559 *p_idx_time = idx_time;
565 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
569 gst_adapter_clear (demux->adapter);
571 GST_DEBUG_OBJECT (demux, "reset stream state");
573 gst_flow_combiner_reset (demux->flowcombiner);
574 for (n = 0; n < demux->num_streams; n++) {
575 demux->stream[n].discont = TRUE;
576 demux->stream[n].first_buffer = TRUE;
578 while (demux->stream[n].payloads->len > 0) {
582 last = demux->stream[n].payloads->len - 1;
583 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
584 gst_buffer_replace (&payload->buf, NULL);
585 g_array_remove_index (demux->stream[n].payloads, last);
591 gst_asf_demux_mark_discont (GstASFDemux * demux)
595 GST_DEBUG_OBJECT (demux, "Mark stream discont");
597 for (n = 0; n < demux->num_streams; n++)
598 demux->stream[n].discont = TRUE;
601 /* do a seek in push based mode */
603 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
608 GstSeekType cur_type, stop_type;
612 GstEvent *byte_event;
614 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
617 stop_type = GST_SEEK_TYPE_NONE;
620 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
622 /* determine packet, by index or by estimation */
623 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
626 (guint) gst_util_uint64_scale (demux->num_packets, cur,
630 if (packet > demux->num_packets) {
631 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
636 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
638 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
640 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
641 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
642 /* BYTE seek event */
643 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
644 cur, stop_type, stop);
645 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
646 res = gst_pad_push_event (demux->sinkpad, byte_event);
652 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
655 GstClockTime idx_time;
658 GstSeekType cur_type, stop_type;
660 gboolean only_need_update;
661 gboolean after, before, next;
666 guint packet, speed_count = 1;
672 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
675 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
676 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
680 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
681 demux->num_packets == 0 || demux->play_time == 0)) {
682 GST_LOG_OBJECT (demux, "stream is not seekable");
686 if (G_UNLIKELY (!demux->activated_streams)) {
687 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
691 if (G_UNLIKELY (rate <= 0.0)) {
692 GST_LOG_OBJECT (demux, "backward playback");
693 demux->seek_to_cur_pos = TRUE;
694 for (i = 0; i < demux->num_streams; i++) {
695 demux->stream[i].reverse_kf_ready = FALSE;
699 seqnum = gst_event_get_seqnum (event);
700 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
702 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
703 demux->keyunit_sync =
704 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
705 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
706 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
707 next = after && !before;
709 if (G_UNLIKELY (demux->streaming)) {
710 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
711 * so first try to let it handle the seek event. */
712 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
715 /* support it safely needs more segment handling, e.g. closing etc */
717 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
720 /* we can (re)construct the start later on, but not the end */
721 if (stop_type != GST_SEEK_TYPE_NONE &&
722 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
723 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
726 return gst_asf_demux_handle_seek_push (demux, event);
729 /* unlock the streaming thread */
730 if (G_LIKELY (flush)) {
731 fevent = gst_event_new_flush_start ();
733 gst_event_set_seqnum (fevent, seqnum);
734 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
735 gst_asf_demux_send_event_unlocked (demux, fevent);
737 gst_pad_pause_task (demux->sinkpad);
740 /* grab the stream lock so that streaming cannot continue, for
741 * non flushing seeks when the element is in PAUSED this could block
743 GST_PAD_STREAM_LOCK (demux->sinkpad);
745 if (G_LIKELY (flush)) {
746 /* we now can stop flushing, since we have the stream lock now */
747 fevent = gst_event_new_flush_stop (TRUE);
748 gst_event_set_seqnum (fevent, seqnum);
749 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
750 gst_asf_demux_send_event_unlocked (demux, fevent);
753 /* operating on copy of segment until we know the seek worked */
754 segment = demux->segment;
756 if (!gst_segment_do_seek (&segment, rate, format, flags, cur_type,
757 cur, stop_type, stop, &only_need_update)) {
762 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
763 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
765 if (cur_type != GST_SEEK_TYPE_SET)
766 seek_time = segment.start;
770 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
771 * real start of data and segment_start to indexed time for key unit seek*/
772 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
773 &idx_time, &speed_count, next, &eos))) {
777 demux->packet = demux->num_packets;
781 /* First try to query our source to see if it can convert for us. This is
782 the case when our source is an mms stream, notice that in this case
783 gstmms will do a time based seek to get the byte offset, this is not a
784 problem as the seek to this offset needs to happen anyway. */
785 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
786 GST_FORMAT_BYTES, &offset)) {
787 packet = (offset - demux->data_offset) / demux->packet_size;
788 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
789 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
790 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
791 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
792 demux->packet_size, packet);
794 /* FIXME: For streams containing video, seek to an earlier position in
795 * the hope of hitting a keyframe and let the sinks throw away the stuff
796 * before the segment start. For audio-only this is unnecessary as every
798 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
799 && demux->num_video_streams > 0) {
800 seek_time -= 5 * GST_SECOND;
805 packet = (guint) gst_util_uint64_scale (demux->num_packets,
806 seek_time, demux->play_time);
808 if (packet > demux->num_packets)
809 packet = demux->num_packets;
812 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
813 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
814 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
815 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
816 segment.start = idx_time;
817 segment.position = idx_time;
818 segment.time = idx_time;
822 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
824 GST_OBJECT_LOCK (demux);
825 demux->segment = segment;
826 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
827 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
828 stop, demux->play_time);
830 demux->packet = packet;
833 demux->need_newsegment = TRUE;
834 demux->segment_seqnum = seqnum;
835 demux->speed_packets =
836 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
837 gst_asf_demux_reset_stream_state_after_discont (demux);
838 GST_OBJECT_UNLOCK (demux);
841 /* restart our task since it might have been stopped when we did the flush */
842 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
845 /* streaming can continue now */
846 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
852 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
859 demux = GST_ASF_DEMUX (parent);
861 switch (GST_EVENT_TYPE (event)) {
863 GST_LOG_OBJECT (pad, "seek event");
864 seqnum = gst_event_get_seqnum (event);
865 if (demux->segment_seqnum == seqnum) {
867 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
868 gst_event_unref (event);
872 ret = gst_asf_demux_handle_seek_event (demux, event);
873 gst_event_unref (event);
876 case GST_EVENT_NAVIGATION:
877 /* just drop these two silently */
878 gst_event_unref (event);
882 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
883 ret = gst_pad_event_default (pad, parent, event);
890 static inline guint32
891 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
895 ret = gst_asf_identify_guid (guids, guid);
897 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
898 gst_asf_get_guid_nick (guids, ret),
899 guid->v1, guid->v2, guid->v3, guid->v4);
911 /* Peek for an object.
913 * Returns FALSE is the object is corrupted (such as the reported
914 * object size being greater than 2**32bits.
917 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
918 guint data_len, AsfObject * object, gboolean expect)
922 /* Callers should have made sure that data_len is big enough */
923 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
925 if (data_len < ASF_OBJECT_HEADER_SIZE)
928 guid.v1 = GST_READ_UINT32_LE (data + 0);
929 guid.v2 = GST_READ_UINT32_LE (data + 4);
930 guid.v3 = GST_READ_UINT32_LE (data + 8);
931 guid.v4 = GST_READ_UINT32_LE (data + 12);
933 /* FIXME: make asf_demux_identify_object_guid() */
934 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
935 if (object->id == ASF_OBJ_UNDEFINED && expect) {
936 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
937 guid.v1, guid.v2, guid.v3, guid.v4);
940 object->size = GST_READ_UINT64_LE (data + 16);
941 if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
942 GST_WARNING_OBJECT (demux,
943 "ASF Object size corrupted (greater than 32bit)");
952 gst_asf_demux_release_old_pads (GstASFDemux * demux)
954 GST_DEBUG_OBJECT (demux, "Releasing old pads");
956 while (demux->old_num_streams > 0) {
957 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
958 gst_event_new_eos ());
959 gst_asf_demux_free_stream (demux,
960 &demux->old_stream[demux->old_num_streams - 1]);
961 --demux->old_num_streams;
963 memset (demux->old_stream, 0, sizeof (demux->old_stream));
964 demux->old_num_streams = 0;
968 gst_asf_demux_chain_headers (GstASFDemux * demux)
971 guint8 *header_data, *data = NULL;
972 const guint8 *cdata = NULL;
974 GstFlowReturn flow = GST_FLOW_OK;
976 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
980 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
982 if (obj.id != ASF_OBJ_HEADER)
985 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
987 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
988 if (gst_adapter_available (demux->adapter) < obj.size + 50)
991 data = gst_adapter_take (demux->adapter, obj.size + 50);
994 header_size = obj.size;
995 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
996 if (flow != GST_FLOW_OK)
999 /* calculate where the packet data starts */
1000 demux->data_offset = obj.size + 50;
1002 /* now parse the beginning of the ASF_OBJ_DATA object */
1003 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
1006 if (demux->num_streams == 0)
1015 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1022 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1023 ("This doesn't seem to be an ASF file"));
1025 return GST_FLOW_ERROR;
1030 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1031 ("header parsing failed, or no streams found, flow = %s",
1032 gst_flow_get_name (flow)));
1034 return GST_FLOW_ERROR;
1039 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1040 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1045 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1048 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1050 if (G_LIKELY (p_flow))
1053 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1054 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1055 "+%u", gst_flow_get_name (flow), offset, size);
1060 g_assert (*p_buf != NULL);
1062 buffer_size = gst_buffer_get_size (*p_buf);
1063 if (G_UNLIKELY (buffer_size < size)) {
1064 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1065 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1066 gst_buffer_unref (*p_buf);
1067 if (G_LIKELY (p_flow))
1068 *p_flow = GST_FLOW_EOS;
1076 static GstFlowReturn
1077 gst_asf_demux_pull_indices (GstASFDemux * demux)
1079 GstBuffer *buf = NULL;
1082 GstFlowReturn ret = GST_FLOW_OK;
1084 offset = demux->index_offset;
1086 if (G_UNLIKELY (offset == 0)) {
1087 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1092 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1098 gst_buffer_map (buf, &map, GST_MAP_READ);
1099 g_assert (map.size >= 16 + 8);
1100 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1101 GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
1102 GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
1104 gst_buffer_unmap (buf, &map);
1105 gst_buffer_replace (&buf, NULL);
1106 /* Non-fatal, return */
1109 gst_buffer_unmap (buf, &map);
1110 gst_buffer_replace (&buf, NULL);
1112 /* check for sanity */
1113 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1114 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1118 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1122 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1123 ", size %u", offset, (guint) obj.size);
1125 offset += obj.size; /* increase before _process_object changes it */
1127 gst_buffer_map (buf, &map, GST_MAP_READ);
1128 g_assert (map.size >= obj.size);
1129 bufdata = (guint8 *) map.data;
1130 obj_size = obj.size;
1131 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1132 gst_buffer_unmap (buf, &map);
1133 gst_buffer_replace (&buf, NULL);
1135 if (ret == ASF_FLOW_NEED_MORE_DATA) {
1136 /* Since indices are at the end of the file, if we need more data,
1137 * we consider it as a non-fatal corrupted index */
1142 if (G_UNLIKELY (ret != GST_FLOW_OK))
1148 GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
1149 gst_flow_get_name (ret));
1154 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1158 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1159 GST_WARNING_OBJECT (demux, "Corrupted data");
1162 if (obj.id != ASF_OBJ_DATA) {
1163 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1167 demux->state = GST_ASF_DEMUX_STATE_DATA;
1169 if (!demux->broadcast && obj.size > 50) {
1170 demux->data_size = obj.size - 50;
1171 /* CHECKME: for at least one file this is off by +158 bytes?! */
1172 demux->index_offset = demux->data_offset + demux->data_size;
1174 demux->data_size = 0;
1175 demux->index_offset = 0;
1180 if (!demux->broadcast) {
1181 /* skip object header (24 bytes) and file GUID (16 bytes) */
1182 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1184 demux->num_packets = 0;
1187 if (demux->num_packets == 0)
1188 demux->seekable = FALSE;
1190 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1191 if (demux->data_size == 0 && demux->num_packets > 0) {
1192 demux->data_size = demux->num_packets * demux->packet_size;
1193 demux->index_offset = demux->data_offset + demux->data_size;
1196 /* process pending stream objects and create pads for those */
1197 gst_asf_demux_process_queued_extended_stream_objects (demux);
1199 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1200 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1201 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1202 demux->data_offset, demux->data_size, demux->index_offset);
1208 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1210 GstFlowReturn flow = GST_FLOW_OK;
1212 GstBuffer *buf = NULL;
1217 GST_LOG_OBJECT (demux, "reading headers");
1219 /* pull HEADER object header, so we know its size */
1220 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1223 gst_buffer_map (buf, &map, GST_MAP_READ);
1224 g_assert (map.size >= 16 + 8);
1225 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1226 gst_buffer_unmap (buf, &map);
1227 gst_buffer_replace (&buf, NULL);
1228 flow = GST_FLOW_ERROR;
1231 gst_buffer_unmap (buf, &map);
1232 gst_buffer_replace (&buf, NULL);
1234 if (obj.id != ASF_OBJ_HEADER)
1237 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1239 /* pull HEADER object */
1240 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1244 size = obj.size; /* don't want obj.size changed */
1245 gst_buffer_map (buf, &map, GST_MAP_READ);
1246 g_assert (map.size >= size);
1247 bufdata = (guint8 *) map.data;
1248 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1249 gst_buffer_unmap (buf, &map);
1250 gst_buffer_replace (&buf, NULL);
1252 if (flow != GST_FLOW_OK) {
1253 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1257 /* calculate where the packet data starts */
1258 demux->data_offset = demux->base_offset + obj.size + 50;
1260 /* now pull beginning of DATA object before packet data */
1261 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1265 gst_buffer_map (buf, &map, GST_MAP_READ);
1266 g_assert (map.size >= size);
1267 bufdata = (guint8 *) map.data;
1268 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1271 if (demux->num_streams == 0)
1274 gst_buffer_unmap (buf, &map);
1275 gst_buffer_replace (&buf, NULL);
1283 gst_buffer_unmap (buf, &map);
1284 gst_buffer_replace (&buf, NULL);
1286 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1287 ("This doesn't seem to be an ASF file"));
1288 *pflow = GST_FLOW_ERROR;
1293 flow = GST_FLOW_ERROR;
1294 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1295 ("header parsing failed, or no streams found, flow = %s",
1296 gst_flow_get_name (flow)));
1301 gst_buffer_unmap (buf, &map);
1302 gst_buffer_replace (&buf, NULL);
1303 if (flow == ASF_FLOW_NEED_MORE_DATA)
1304 flow = GST_FLOW_ERROR;
1311 all_streams_prerolled (GstASFDemux * demux)
1313 GstClockTime preroll_time;
1314 guint i, num_no_data = 0;
1315 AsfStreamType prerolled_types = 0, all_types = 0;
1317 /* Allow at least 500ms of preroll_time */
1318 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1320 /* returns TRUE as long as there isn't a stream which (a) has data queued
1321 * and (b) the timestamp of last piece of data queued is < demux->preroll
1322 * AND there is at least one other stream with data queued */
1323 for (i = 0; i < demux->num_streams; ++i) {
1324 AsfPayload *last_payload = NULL;
1328 stream = &demux->stream[i];
1330 all_types |= stream->type;
1332 if (G_UNLIKELY (stream->payloads->len == 0)) {
1334 GST_LOG_OBJECT (stream->pad, "no data queued");
1338 prerolled_types |= stream->type;
1340 /* find last payload with timestamp */
1341 for (last_idx = stream->payloads->len - 1;
1342 last_idx >= 0 && (last_payload == NULL
1343 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1344 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1347 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1348 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1349 GST_TIME_ARGS (preroll_time));
1350 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1351 || last_payload->ts <= preroll_time)) {
1352 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1357 GST_LOG_OBJECT (demux, "all_types:%d prerolled_types:%d",
1358 all_types, prerolled_types);
1360 /* If streams of each present type have prerolled, we are good to go */
1361 if (all_types != 0 && prerolled_types == all_types)
1364 if (G_UNLIKELY (num_no_data > 0))
1372 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1377 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1380 /* check for each mutual exclusion group whether it affects this stream */
1381 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1382 if (*mes == stream->id) {
1383 /* we are in this group; let's check if we've already activated streams
1384 * that are in the same group (and hence mutually exclusive to this
1386 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1389 for (i = 0; i < demux->num_streams; ++i) {
1390 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1391 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1392 "to already active stream with ID %d", stream->id,
1393 demux->stream[i].id);
1398 /* we can only be in this group once, let's break out and move on to
1399 * the next mutual exclusion group */
1410 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1412 /* remember the first queued timestamp for the segment */
1413 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1414 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1415 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1416 GST_TIME_ARGS (demux->first_ts));
1417 demux->segment_ts = payload_ts;
1418 /* always note, but only determines segment when streaming */
1419 if (demux->streaming)
1420 if (!gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1421 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1422 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0,
1424 GST_WARNING_OBJECT (demux, "Initial segment seek failed");
1430 gst_asf_demux_get_first_ts (GstASFDemux * demux)
1432 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1433 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1436 /* go trhough each stream, find smallest timestamp */
1437 for (i = 0; i < demux->num_streams; ++i) {
1440 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1441 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1442 stream = &demux->stream[i];
1444 for (j = 0; j < stream->payloads->len; ++j) {
1445 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1446 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1447 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1448 || stream_min_ts > payload->ts)) {
1449 stream_min_ts = payload->ts;
1451 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1452 payload->ts > stream_min_ts &&
1453 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1454 || stream_min_ts2 > payload->ts)) {
1455 stream_min_ts2 = payload->ts;
1459 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1460 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1461 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1462 from it. I haven't found a better way to distinguish between these two, except to set an arbitrary boundary
1463 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1465 GST_DEBUG_OBJECT (demux,
1466 "stream #%u stream_min_ts %" GST_TIME_FORMAT " stream_min_ts2 %"
1467 GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (stream_min_ts),
1468 GST_TIME_ARGS (stream_min_ts2));
1470 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1471 stream_min_ts = stream_min_ts2;
1473 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1474 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1475 first_ts = stream_min_ts;
1478 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen */
1481 demux->first_ts = first_ts;
1483 /* update packets queued before we knew first timestamp */
1484 for (i = 0; i < demux->num_streams; ++i) {
1487 stream = &demux->stream[i];
1489 for (j = 0; j < stream->payloads->len; ++j) {
1490 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1491 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1492 if (payload->ts > first_ts)
1493 payload->ts -= first_ts;
1501 gst_asf_demux_check_segment_ts (demux, 0);
1507 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1509 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1510 and often set wrong, inspecting the data is the only way that seem to be working */
1511 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1512 GstCaps *caps = NULL;
1514 GstAdapter *adapter = gst_adapter_new ();
1516 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1518 AsfPayload *payload;
1521 payload = &g_array_index (stream->payloads, AsfPayload, i);
1522 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1523 len = gst_adapter_available (adapter);
1524 data = gst_adapter_map (adapter, len);
1528 #define MIN_LENGTH 128
1530 /* look for the sync points */
1532 if (len < MIN_LENGTH || /* give typefind something to work on */
1533 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1534 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1540 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1543 if (prob < GST_TYPE_FIND_LIKELY) {
1546 if (len > MIN_LENGTH)
1547 /* this wasn't it, look for another sync point */
1551 gst_adapter_unmap (adapter);
1554 gst_object_unref (adapter);
1557 gst_caps_take (&stream->caps, caps);
1565 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1567 guint i, actual_streams = 0;
1569 if (demux->activated_streams)
1572 if (!all_streams_prerolled (demux) && !force) {
1573 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1577 if (G_UNLIKELY (!gst_asf_demux_get_first_ts (demux)))
1580 for (i = 0; i < demux->num_streams; ++i) {
1581 AsfStream *stream = &demux->stream[i];
1583 if (stream->payloads->len > 0) {
1585 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1586 !stream->active && /* do not inspect active streams (caps were already set) */
1587 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1588 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1589 /* try to gather some more data */
1592 /* we don't check mutual exclusion stuff here; either we have data for
1593 * a stream, then we active it, or we don't, then we'll ignore it */
1594 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1595 gst_asf_demux_activate_stream (demux, stream);
1596 actual_streams += 1;
1598 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1602 if (actual_streams == 0) {
1603 /* We don't have any streams activated ! */
1604 GST_ERROR_OBJECT (demux, "No streams activated!");
1608 gst_asf_demux_release_old_pads (demux);
1610 demux->activated_streams = TRUE;
1611 GST_LOG_OBJECT (demux, "signalling no more pads");
1612 gst_element_no_more_pads (GST_ELEMENT (demux));
1616 /* returns the stream that has a complete payload with the lowest timestamp
1617 * queued, or NULL (we push things by timestamp because during the internal
1618 * prerolling we might accumulate more data then the external queues can take,
1619 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1621 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1623 AsfPayload *best_payload = NULL;
1624 AsfStream *best_stream = NULL;
1627 for (i = 0; i < demux->num_streams; ++i) {
1631 stream = &demux->stream[i];
1633 /* Don't push any data until we have at least one payload that falls within
1634 * the current segment. This way we can remove out-of-segment payloads that
1635 * don't need to be decoded after a seek, sending only data from the
1636 * keyframe directly before our segment start */
1637 if (stream->payloads->len > 0) {
1638 AsfPayload *payload = NULL;
1641 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1642 /* Reverse playback */
1644 if (stream->is_video) {
1645 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1646 if (stream->reverse_kf_ready) {
1648 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1649 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1650 /* TODO : remove payload from the list? */
1657 /* find first complete payload with timestamp */
1658 for (j = stream->payloads->len - 1;
1659 j >= 0 && (payload == NULL
1660 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1661 payload = &g_array_index (stream->payloads, AsfPayload, j);
1664 /* If there's a complete payload queued for this stream */
1665 if (!gst_asf_payload_is_complete (payload))
1671 /* find last payload with timestamp */
1672 for (last_idx = stream->payloads->len - 1;
1673 last_idx >= 0 && (payload == NULL
1674 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1675 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1678 /* if this is first payload after seek we might need to update the segment */
1679 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1680 gst_asf_demux_check_segment_ts (demux, payload->ts);
1682 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1683 (payload->ts < demux->segment.start))) {
1684 if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
1685 && payload->keyframe)) {
1686 GST_DEBUG_OBJECT (stream->pad,
1687 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1688 GST_TIME_ARGS (payload->ts));
1689 demux->segment.start = payload->ts;
1690 demux->segment.time = payload->ts;
1692 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1693 GST_TIME_FORMAT " which is before our segment start %"
1694 GST_TIME_FORMAT ", not pushing yet",
1695 GST_TIME_ARGS (payload->ts),
1696 GST_TIME_ARGS (demux->segment.start));
1701 /* find first complete payload with timestamp */
1703 j < stream->payloads->len && (payload == NULL
1704 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1705 payload = &g_array_index (stream->payloads, AsfPayload, j);
1708 /* Now see if there's a complete payload queued for this stream */
1709 if (!gst_asf_payload_is_complete (payload))
1713 /* ... and whether its timestamp is lower than the current best */
1714 if (best_stream == NULL || best_payload->ts > payload->ts) {
1715 best_stream = stream;
1716 best_payload = payload;
1724 static GstFlowReturn
1725 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1728 GstFlowReturn ret = GST_FLOW_OK;
1730 if (G_UNLIKELY (!demux->activated_streams)) {
1731 if (!gst_asf_demux_check_activate_streams (demux, force))
1733 /* streams are now activated */
1736 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1737 AsfPayload *payload;
1738 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1739 GstClockTime duration = GST_CLOCK_TIME_NONE;
1741 /* wait until we had a chance to "lock on" some payload's timestamp */
1742 if (G_UNLIKELY (demux->need_newsegment
1743 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1746 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1747 && stream->payloads->len) {
1748 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1750 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1753 /* do we need to send a newsegment event */
1754 if ((G_UNLIKELY (demux->need_newsegment))) {
1755 GstEvent *segment_event;
1757 /* safe default if insufficient upstream info */
1758 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1761 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1762 demux->segment.duration > 0) {
1763 /* slight HACK; prevent clipping of last bit */
1764 demux->segment.stop = demux->segment.duration + demux->in_gap;
1767 /* FIXME : only if ACCURATE ! */
1768 if (G_LIKELY (demux->keyunit_sync && !demux->accurate
1769 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1770 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1771 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1772 GST_TIME_ARGS (payload->ts));
1773 demux->segment.start = payload->ts;
1774 demux->segment.time = payload->ts;
1777 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1780 /* note: we fix up all timestamps to start from 0, so this should be ok */
1781 segment_event = gst_event_new_segment (&demux->segment);
1782 if (demux->segment_seqnum)
1783 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1784 gst_asf_demux_send_event_unlocked (demux, segment_event);
1786 /* now post any global tags we may have found */
1787 if (demux->taglist == NULL) {
1788 demux->taglist = gst_tag_list_new_empty ();
1789 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1792 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1793 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1795 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1796 gst_asf_demux_send_event_unlocked (demux,
1797 gst_event_new_tag (demux->taglist));
1798 demux->taglist = NULL;
1800 demux->need_newsegment = FALSE;
1801 demux->segment_running = TRUE;
1804 /* Do we have tags pending for this stream? */
1805 if (G_UNLIKELY (stream->pending_tags)) {
1806 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1807 gst_pad_push_event (stream->pad,
1808 gst_event_new_tag (stream->pending_tags));
1809 stream->pending_tags = NULL;
1812 /* We have the whole packet now so we should push the packet to
1813 * the src pad now. First though we should check if we need to do
1815 if (G_UNLIKELY (stream->span > 1)) {
1816 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1819 payload->buf = gst_buffer_make_writable (payload->buf);
1821 if (G_LIKELY (!payload->keyframe)) {
1822 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1825 if (G_UNLIKELY (stream->discont)) {
1826 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1827 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1828 stream->discont = FALSE;
1831 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1832 (payload->par_x != stream->par_x) &&
1833 (payload->par_y != stream->par_y))) {
1834 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1835 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1836 stream->par_x = payload->par_x;
1837 stream->par_y = payload->par_y;
1838 stream->caps = gst_caps_make_writable (stream->caps);
1839 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1840 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1841 gst_pad_set_caps (stream->pad, stream->caps);
1844 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1845 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1846 payload->interlaced);
1847 stream->interlaced = payload->interlaced;
1848 stream->caps = gst_caps_make_writable (stream->caps);
1849 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1850 (stream->interlaced ? "mixed" : "progressive"), NULL);
1851 gst_pad_set_caps (stream->pad, stream->caps);
1854 /* (sort of) interpolate timestamps using upstream "frame of reference",
1855 * typically useful for live src, but might (unavoidably) mess with
1856 * position reporting if a live src is playing not so live content
1857 * (e.g. rtspsrc taking some time to fall back to tcp) */
1858 timestamp = payload->ts;
1859 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1860 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1861 timestamp += demux->in_gap;
1863 /* Check if we're after the segment already, if so no need to push
1865 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1866 GST_DEBUG_OBJECT (stream->pad,
1867 "Payload after segment stop %" GST_TIME_FORMAT,
1868 GST_TIME_ARGS (demux->segment.stop));
1870 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1872 gst_buffer_unref (payload->buf);
1873 payload->buf = NULL;
1874 g_array_remove_index (stream->payloads, 0);
1875 /* Break out as soon as we have an issue */
1876 if (G_UNLIKELY (ret != GST_FLOW_OK))
1883 GST_BUFFER_PTS (payload->buf) = timestamp;
1885 if (payload->duration == GST_CLOCK_TIME_NONE
1886 && stream->ext_props.avg_time_per_frame != 0) {
1887 duration = stream->ext_props.avg_time_per_frame * 100;
1889 duration = payload->duration;
1891 GST_BUFFER_DURATION (payload->buf) = duration;
1893 /* FIXME: we should really set durations on buffers if we can */
1895 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1898 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1899 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1900 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1902 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1903 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1907 if (stream->active) {
1908 if (G_UNLIKELY (stream->first_buffer)) {
1909 if (stream->streamheader != NULL) {
1910 GST_DEBUG_OBJECT (stream->pad,
1911 "Pushing streamheader before first buffer");
1912 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1914 stream->first_buffer = FALSE;
1917 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1918 && timestamp > demux->segment.position) {
1919 demux->segment.position = timestamp;
1920 if (GST_CLOCK_TIME_IS_VALID (duration))
1921 demux->segment.position += timestamp;
1924 ret = gst_pad_push (stream->pad, payload->buf);
1926 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1929 gst_buffer_unref (payload->buf);
1932 payload->buf = NULL;
1933 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1934 && stream->reverse_kf_ready) {
1935 g_array_remove_index (stream->payloads, stream->kf_pos);
1938 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1940 stream->reverse_kf_ready = FALSE;
1943 g_array_remove_index (stream->payloads, 0);
1946 /* Break out as soon as we have an issue */
1947 if (G_UNLIKELY (ret != GST_FLOW_OK))
1955 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1960 g_assert (buf != NULL);
1962 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1964 gst_buffer_map (buf, &map, GST_MAP_READ);
1966 /* we return false on buffer too small */
1967 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1968 gst_buffer_unmap (buf, &map);
1972 /* check if it is a header */
1974 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1976 gst_buffer_unmap (buf, &map);
1977 if (valid && obj.id == ASF_OBJ_HEADER) {
1984 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1986 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1987 GstFlowReturn ret = GST_FLOW_OK;
1988 GstBuffer *buf = NULL;
1989 gboolean header = FALSE;
1991 /* TODO maybe we should skip index objects after the data and look
1992 * further for a new header */
1993 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1994 g_assert (buf != NULL);
1995 /* check if it is a header */
1996 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1997 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1998 demux->base_offset = off;
2002 gst_buffer_unref (buf);
2009 gst_asf_demux_loop (GstASFDemux * demux)
2011 GstFlowReturn flow = GST_FLOW_OK;
2012 GstBuffer *buf = NULL;
2015 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
2016 if (!gst_asf_demux_pull_headers (demux, &flow)) {
2020 flow = gst_asf_demux_pull_indices (demux);
2021 if (flow != GST_FLOW_OK)
2025 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
2027 if (G_UNLIKELY (demux->num_packets != 0
2028 && demux->packet >= demux->num_packets))
2031 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2032 (guint) demux->num_packets);
2034 off = demux->data_offset + (demux->packet * demux->packet_size);
2036 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2037 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2038 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2039 if (flow == GST_FLOW_EOS) {
2041 } else if (flow == GST_FLOW_FLUSHING) {
2042 GST_DEBUG_OBJECT (demux, "Not fatal");
2049 if (G_LIKELY (demux->speed_packets == 1)) {
2050 GstAsfDemuxParsePacketError err;
2051 err = gst_asf_demux_parse_packet (demux, buf);
2052 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2053 /* when we don't know when the data object ends, we should check
2054 * for a chained asf */
2055 if (demux->num_packets == 0) {
2056 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2057 GST_INFO_OBJECT (demux, "Chained asf found");
2058 demux->base_offset = off;
2059 gst_asf_demux_reset (demux, TRUE);
2060 gst_buffer_unref (buf);
2064 /* FIXME: We should tally up fatal errors and error out only
2065 * after a few broken packets in a row? */
2067 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2068 gst_buffer_unref (buf);
2070 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2071 && !demux->seek_to_cur_pos) {
2073 if (demux->packet < 0) {
2083 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2085 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2086 && !demux->seek_to_cur_pos) {
2088 if (demux->packet < 0) {
2097 for (n = 0; n < demux->speed_packets; n++) {
2099 GstAsfDemuxParsePacketError err;
2102 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2103 n * demux->packet_size, demux->packet_size);
2104 err = gst_asf_demux_parse_packet (demux, sub);
2105 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2106 /* when we don't know when the data object ends, we should check
2107 * for a chained asf */
2108 if (demux->num_packets == 0) {
2109 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2110 GST_INFO_OBJECT (demux, "Chained asf found");
2111 demux->base_offset = off + n * demux->packet_size;
2112 gst_asf_demux_reset (demux, TRUE);
2113 gst_buffer_unref (sub);
2114 gst_buffer_unref (buf);
2118 /* FIXME: We should tally up fatal errors and error out only
2119 * after a few broken packets in a row? */
2121 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2125 gst_buffer_unref (sub);
2127 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2128 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2134 /* reset speed pull */
2135 demux->speed_packets = 1;
2138 gst_buffer_unref (buf);
2140 if (G_UNLIKELY ((demux->num_packets > 0
2141 && demux->packet >= demux->num_packets)
2142 || flow == GST_FLOW_EOS)) {
2143 GST_LOG_OBJECT (demux, "reached EOS");
2147 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2148 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2152 /* check if we're at the end of the configured segment */
2153 /* FIXME: check if segment end reached etc. */
2159 /* if we haven't activated our streams yet, this might be because we have
2160 * less data queued than required for preroll; force stream activation and
2161 * send any pending payloads before sending EOS */
2162 if (!demux->activated_streams)
2163 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2165 /* we want to push an eos or post a segment-done in any case */
2166 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2169 /* for segment playback we need to post when (in stream time)
2170 * we stopped, this is either stop (when set) or the duration. */
2171 if ((stop = demux->segment.stop) == -1)
2172 stop = demux->segment.duration;
2174 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2175 gst_element_post_message (GST_ELEMENT_CAST (demux),
2176 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2178 gst_asf_demux_send_event_unlocked (demux,
2179 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2180 } else if (flow != GST_FLOW_EOS) {
2181 /* check if we have a chained asf, in case, we don't eos yet */
2182 if (gst_asf_demux_check_chained_asf (demux)) {
2183 GST_INFO_OBJECT (demux, "Chained ASF starting");
2184 gst_asf_demux_reset (demux, TRUE);
2189 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2190 if (demux->activated_streams) {
2191 /* normal playback, send EOS to all linked pads */
2192 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2193 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2195 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2196 flow = GST_FLOW_EOS;
2199 /* ... and fall through to pause */
2203 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2204 gst_flow_get_name (flow));
2205 demux->segment_running = FALSE;
2206 gst_pad_pause_task (demux->sinkpad);
2208 /* For the error cases */
2209 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2210 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2211 ("This doesn't seem to be an ASF file"));
2212 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2213 /* Post an error. Hopefully something else already has, but if not... */
2214 GST_ELEMENT_FLOW_ERROR (demux, flow);
2215 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2224 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2225 flow = GST_FLOW_EOS;
2229 /* See FIXMEs above */
2232 gst_buffer_unref (buf);
2233 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2234 ("Error parsing ASF packet %u", (guint) demux->packet));
2235 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2236 flow = GST_FLOW_ERROR;
2242 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2243 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2244 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2247 gst_asf_demux_check_header (GstASFDemux * demux)
2250 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2251 ASF_OBJECT_HEADER_SIZE);
2252 if (cdata == NULL) /* need more data */
2253 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2255 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
2256 && obj.id == ASF_OBJ_HEADER) {
2257 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2260 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2263 static GstFlowReturn
2264 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2266 GstFlowReturn ret = GST_FLOW_OK;
2269 demux = GST_ASF_DEMUX (parent);
2271 GST_LOG_OBJECT (demux,
2272 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2273 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2274 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2276 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2277 GST_DEBUG_OBJECT (demux, "received DISCONT");
2278 gst_asf_demux_mark_discont (demux);
2281 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2282 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2283 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2284 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2285 ", interpolation gap: %" GST_TIME_FORMAT,
2286 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2289 gst_adapter_push (demux->adapter, buf);
2291 switch (demux->state) {
2292 case GST_ASF_DEMUX_STATE_INDEX:{
2293 gint result = gst_asf_demux_check_header (demux);
2294 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2297 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2298 /* we don't care about this, probably an index */
2299 /* TODO maybe would be smarter to skip all the indices
2300 * until we got a new header or EOS to decide */
2301 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2304 GST_INFO_OBJECT (demux, "Chained asf starting");
2305 /* cleanup and get ready for a chained asf */
2306 gst_asf_demux_reset (demux, TRUE);
2310 case GST_ASF_DEMUX_STATE_HEADER:{
2311 ret = gst_asf_demux_chain_headers (demux);
2312 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2314 /* otherwise fall through */
2316 case GST_ASF_DEMUX_STATE_DATA:
2320 data_size = demux->packet_size;
2322 while (gst_adapter_available (demux->adapter) >= data_size) {
2324 GstAsfDemuxParsePacketError err;
2326 /* we don't know the length of the stream
2327 * check for a chained asf every time */
2328 if (demux->num_packets == 0) {
2329 gint result = gst_asf_demux_check_header (demux);
2331 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2332 GST_INFO_OBJECT (demux, "Chained asf starting");
2333 /* cleanup and get ready for a chained asf */
2334 gst_asf_demux_reset (demux, TRUE);
2337 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2338 && demux->packet >= demux->num_packets)) {
2339 /* do not overshoot data section when streaming */
2343 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2345 /* FIXME: We should tally up fatal errors and error out only
2346 * after a few broken packets in a row? */
2347 err = gst_asf_demux_parse_packet (demux, buf);
2349 gst_buffer_unref (buf);
2351 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2352 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2354 GST_WARNING_OBJECT (demux, "Parse error");
2356 if (demux->packet >= 0)
2359 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2360 && demux->packet >= demux->num_packets)) {
2361 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2366 g_assert_not_reached ();
2370 if (ret != GST_FLOW_OK)
2371 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2377 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2383 static inline gboolean
2384 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2386 if (*p_size < num_bytes)
2389 *p_data += num_bytes;
2390 *p_size -= num_bytes;
2394 static inline guint8
2395 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2399 g_assert (*p_size >= 1);
2400 ret = GST_READ_UINT8 (*p_data);
2401 *p_data += sizeof (guint8);
2402 *p_size -= sizeof (guint8);
2406 static inline guint16
2407 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2411 g_assert (*p_size >= 2);
2412 ret = GST_READ_UINT16_LE (*p_data);
2413 *p_data += sizeof (guint16);
2414 *p_size -= sizeof (guint16);
2418 static inline guint32
2419 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2423 g_assert (*p_size >= 4);
2424 ret = GST_READ_UINT32_LE (*p_data);
2425 *p_data += sizeof (guint32);
2426 *p_size -= sizeof (guint32);
2430 static inline guint64
2431 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2435 g_assert (*p_size >= 8);
2436 ret = GST_READ_UINT64_LE (*p_data);
2437 *p_data += sizeof (guint64);
2438 *p_size -= sizeof (guint64);
2443 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2444 guint8 ** p_data, guint64 * p_size)
2448 if (*p_size < num_bytes_to_read)
2451 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2452 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2454 *p_data += num_bytes_to_read;
2455 *p_size -= num_bytes_to_read;
2461 gst_asf_demux_get_bytes (guint8 ** p_buf, guint64 num_bytes_to_read,
2462 guint8 ** p_data, guint64 * p_size)
2466 if (num_bytes_to_read >= G_MAXUINT)
2469 if (*p_size < num_bytes_to_read)
2472 *p_buf = g_memdup2 (*p_data, num_bytes_to_read);
2473 *p_data += num_bytes_to_read;
2474 *p_size -= num_bytes_to_read;
2479 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2480 guint8 ** p_data, guint64 * p_size)
2490 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2493 *p_strlen = s_length;
2495 if (s_length == 0) {
2496 GST_WARNING ("zero-length string");
2497 *p_str = g_strdup ("");
2501 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2504 g_assert (s != NULL);
2506 /* just because They don't exist doesn't
2507 * mean They are not out to get you ... */
2508 if (s[s_length - 1] != '\0') {
2509 s = g_realloc (s, s_length + 1);
2513 *p_str = (gchar *) s;
2519 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2521 g_assert (*p_size >= 4 * sizeof (guint32));
2523 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2524 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2525 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2526 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2530 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2533 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2536 /* WAVEFORMATEX Structure */
2537 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2538 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2539 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2540 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2541 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2542 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2543 /* Codec specific data size */
2544 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2545 if (audio->size > *p_size) {
2546 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2547 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2554 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2557 if (*p_size < (4 + 4 + 1 + 2))
2560 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2561 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2562 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2563 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2568 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2569 guint8 ** p_data, guint64 * p_size)
2571 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2574 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2576 if (fmt->size < 40) {
2577 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2580 if ((guint64) fmt->size - 4 > *p_size) {
2581 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2584 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2585 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2586 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2587 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2588 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2589 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2590 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2591 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2592 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2593 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2598 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2602 for (i = 0; i < demux->num_streams; i++) {
2603 if (demux->stream[i].id == id)
2604 return &demux->stream[i];
2607 if (gst_asf_demux_is_unknown_stream (demux, id))
2608 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2613 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2614 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2619 gst_pad_use_fixed_caps (src_pad);
2620 gst_pad_set_caps (src_pad, caps);
2622 gst_pad_set_event_function (src_pad,
2623 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2624 gst_pad_set_query_function (src_pad,
2625 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2627 stream = &demux->stream[demux->num_streams];
2628 stream->caps = caps;
2629 stream->pad = src_pad;
2631 stream->fps_known = !is_video; /* bit hacky for audio */
2632 stream->is_video = is_video;
2633 stream->pending_tags = tags;
2634 stream->discont = TRUE;
2635 stream->first_buffer = TRUE;
2636 stream->streamheader = streamheader;
2637 if (stream->streamheader) {
2638 stream->streamheader = gst_buffer_make_writable (streamheader);
2639 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2644 st = gst_caps_get_structure (caps, 0);
2645 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2646 par_x > 0 && par_y > 0) {
2647 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2648 stream->par_x = par_x;
2649 stream->par_y = par_y;
2653 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2655 /* TODO: create this array during reverse play? */
2656 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2658 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2659 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2661 ++demux->num_streams;
2663 stream->active = FALSE;
2669 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2670 GstBuffer * buffer, GstStructure * structure)
2672 GValue arr_val = G_VALUE_INIT;
2673 GValue buf_val = G_VALUE_INIT;
2675 g_value_init (&arr_val, GST_TYPE_ARRAY);
2676 g_value_init (&buf_val, GST_TYPE_BUFFER);
2678 gst_value_set_buffer (&buf_val, buffer);
2679 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2681 gst_structure_take_value (structure, "streamheader", &arr_val);
2685 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2686 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2688 GstTagList *tags = NULL;
2689 GstBuffer *extradata = NULL;
2692 guint16 size_left = 0;
2693 gchar *codec_name = NULL;
2696 size_left = audio->size;
2698 /* Create the audio pad */
2699 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2701 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2704 /* Swallow up any left over data and set up the
2705 * standard properties from the header info */
2707 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2708 "codec specific data", size_left);
2710 g_assert (size_left <= *p_size);
2711 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2714 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2715 * additional two bytes indicating extradata. */
2716 /* FIXME: Handle the channel reorder map here */
2717 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2718 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2721 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2722 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2725 /* Informing about that audio format we just added */
2727 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2728 g_free (codec_name);
2731 if (audio->byte_rate > 0) {
2732 /* Some ASF files have no bitrate props object (often seen with
2733 * ASF files that contain raw audio data). Example files can
2734 * be generated with FFmpeg (tested with v2.8.6), like this:
2736 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2738 * In this case, if audio->byte_rate is nonzero, use that as
2741 guint bitrate = audio->byte_rate * 8;
2744 tags = gst_tag_list_new_empty ();
2746 /* Add bitrate, but only if there is none set already, since
2747 * this is just a fallback in case there is no bitrate tag
2748 * already present */
2749 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2753 gst_buffer_unref (extradata);
2755 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2756 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2757 audio->codec_tag, tags);
2759 ++demux->num_audio_streams;
2761 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2765 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2766 asf_stream_video_format * video, guint16 id,
2767 guint8 ** p_data, guint64 * p_size)
2769 GstTagList *tags = NULL;
2770 GstStructure *caps_s;
2771 GstBuffer *extradata = NULL;
2776 gchar *codec_name = NULL;
2777 guint64 size_left = video->size - 40;
2778 GstBuffer *streamheader = NULL;
2779 guint par_w = 1, par_h = 1;
2781 /* Create the video pad */
2782 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2783 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2786 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2788 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2789 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2791 g_assert (size_left <= *p_size);
2792 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2795 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2797 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2798 caps = gst_riff_create_video_caps (video->tag, NULL,
2799 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2802 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2803 G_TYPE_UINT, video->tag, NULL);
2808 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2809 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2810 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2813 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2817 /* retry with the global metadata */
2818 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2819 demux->global_metadata);
2820 s = demux->global_metadata;
2821 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2822 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2823 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2824 if (ax > 0 && ay > 0) {
2827 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2832 s = gst_caps_get_structure (caps, 0);
2833 gst_structure_remove_field (s, "framerate");
2836 caps_s = gst_caps_get_structure (caps, 0);
2838 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2839 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2840 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2841 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2844 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2845 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2846 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2848 GstBuffer *buf = gst_value_get_buffer (value);
2851 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2852 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2853 /* this looks like a bytestream start */
2854 streamheader = gst_buffer_ref (buf);
2855 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2856 gst_structure_remove_field (caps_s, "codec_data");
2857 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING,
2858 "byte-stream", NULL);
2860 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "avc",
2864 gst_buffer_unmap (buf, &mapinfo);
2867 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "byte-stream",
2872 /* For a 3D video, set multiview information into the caps based on
2873 * what was detected during object parsing */
2874 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2875 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2876 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2877 const gchar *mview_mode_str;
2879 switch (demux->asf_3D_mode) {
2880 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2881 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2883 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2884 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2885 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2887 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2888 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2890 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2891 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2892 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2894 case GST_ASF_3D_DUAL_STREAM:{
2895 gboolean is_right_view = FALSE;
2896 /* if Advanced_Mutual_Exclusion object exists, use it
2897 * to figure out which is the left view (lower ID) */
2898 if (demux->mut_ex_streams != NULL) {
2902 length = g_slist_length (demux->mut_ex_streams);
2904 for (i = 0; i < length; i++) {
2907 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2909 GST_DEBUG_OBJECT (demux,
2910 "has Mutual_Exclusion object. stream id in object is %d",
2911 GPOINTER_TO_INT (v_s_id));
2913 if (id > GPOINTER_TO_INT (v_s_id))
2914 is_right_view = TRUE;
2917 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2918 * first video stream encountered has the lower ID */
2919 if (demux->num_video_streams > 0) {
2920 /* This is not the first video stream, assuming right eye view */
2921 is_right_view = TRUE;
2925 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2927 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2934 GST_INFO_OBJECT (demux,
2935 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2938 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2939 if (mview_mode_str != NULL) {
2940 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2941 video->height, par_w, par_h))
2942 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2944 gst_caps_set_simple (caps,
2945 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2946 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2947 GST_FLAG_SET_MASK_EXACT, NULL);
2952 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2953 g_free (codec_name);
2957 gst_buffer_unref (extradata);
2959 GST_INFO ("Adding video stream #%u, id %u, codec %"
2960 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2961 GST_FOURCC_ARGS (video->tag), video->tag);
2963 ++demux->num_video_streams;
2965 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2966 streamheader, tags);
2970 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2972 if (!stream->active) {
2976 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2977 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2978 gst_pad_set_active (stream->pad, TRUE);
2981 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2982 "%03u", stream->id);
2985 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2987 if (gst_event_parse_group_id (event, &demux->group_id))
2988 demux->have_group_id = TRUE;
2990 demux->have_group_id = FALSE;
2991 gst_event_unref (event);
2992 } else if (!demux->have_group_id) {
2993 demux->have_group_id = TRUE;
2994 demux->group_id = gst_util_group_id_next ();
2997 event = gst_event_new_stream_start (stream_id);
2998 if (demux->have_group_id)
2999 gst_event_set_group_id (event, demux->group_id);
3001 gst_pad_push_event (stream->pad, event);
3003 gst_pad_set_caps (stream->pad, stream->caps);
3005 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
3006 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
3007 stream->active = TRUE;
3012 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
3015 AsfCorrectionType correction_type;
3016 AsfStreamType stream_type;
3017 GstClockTime time_offset;
3018 gboolean is_encrypted G_GNUC_UNUSED;
3022 guint stream_specific_size;
3023 guint type_specific_size G_GNUC_UNUSED;
3024 guint unknown G_GNUC_UNUSED;
3025 gboolean inspect_payload = FALSE;
3026 AsfStream *stream = NULL;
3028 /* Get the rest of the header's header */
3029 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
3030 goto not_enough_data;
3032 gst_asf_demux_get_guid (&guid, &data, &size);
3033 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
3035 gst_asf_demux_get_guid (&guid, &data, &size);
3036 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
3038 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
3040 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3041 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3043 flags = gst_asf_demux_get_uint16 (&data, &size);
3044 stream_id = flags & 0x7f;
3045 is_encrypted = ! !(flags & 0x8000);
3046 unknown = gst_asf_demux_get_uint32 (&data, &size);
3048 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3049 stream_id, GST_TIME_ARGS (time_offset));
3051 /* dvr-ms has audio stream declared in stream specific data */
3052 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3053 AsfExtStreamType ext_stream_type;
3054 gst_asf_demux_get_guid (&guid, &data, &size);
3055 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3057 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3058 inspect_payload = TRUE;
3060 gst_asf_demux_get_guid (&guid, &data, &size);
3061 gst_asf_demux_get_uint32 (&data, &size);
3062 gst_asf_demux_get_uint32 (&data, &size);
3063 gst_asf_demux_get_uint32 (&data, &size);
3064 gst_asf_demux_get_guid (&guid, &data, &size);
3065 gst_asf_demux_get_uint32 (&data, &size);
3066 stream_type = ASF_STREAM_AUDIO;
3070 switch (stream_type) {
3071 case ASF_STREAM_AUDIO:{
3072 asf_stream_audio audio_object;
3074 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3075 goto not_enough_data;
3077 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3080 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3083 switch (correction_type) {
3084 case ASF_CORRECTION_ON:{
3085 guint span, packet_size, chunk_size, data_size, silence_data;
3087 GST_INFO ("Using error correction");
3089 if (size < (1 + 2 + 2 + 2 + 1))
3090 goto not_enough_data;
3092 span = gst_asf_demux_get_uint8 (&data, &size);
3093 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3094 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3095 data_size = gst_asf_demux_get_uint16 (&data, &size);
3096 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3098 stream->span = span;
3100 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3101 packet_size, chunk_size, data_size, span, silence_data);
3103 if (stream->span > 1) {
3104 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3105 /* Disable descrambling */
3108 /* FIXME: this else branch was added for
3109 * weird_al_yankovic - the saga begins.asf */
3110 stream->ds_packet_size = packet_size;
3111 stream->ds_chunk_size = chunk_size;
3114 /* Descambling is enabled */
3115 stream->ds_packet_size = packet_size;
3116 stream->ds_chunk_size = chunk_size;
3119 /* Now skip the rest of the silence data */
3121 gst_bytestream_flush (demux->bs, data_size - 1);
3123 /* FIXME: CHECKME. And why -1? */
3124 if (data_size > 1) {
3125 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3126 goto not_enough_data;
3132 case ASF_CORRECTION_OFF:{
3133 GST_INFO ("Error correction off");
3134 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3135 goto not_enough_data;
3139 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3140 ("Audio stream using unknown error correction"));
3147 case ASF_STREAM_VIDEO:{
3148 asf_stream_video_format video_format_object;
3149 asf_stream_video video_object;
3152 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3153 goto not_enough_data;
3155 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3157 GST_INFO ("object is a video stream with %u bytes of "
3158 "additional data", vsize);
3160 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3162 goto not_enough_data;
3165 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3166 stream_id, &data, &size);
3172 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3174 demux->other_streams =
3175 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3180 stream->inspect_payload = inspect_payload;
3181 stream->type = stream_type;
3187 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3188 /* we'll error out later if we found no streams */
3193 static const gchar *
3194 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3199 const gchar *asf_name;
3200 const gchar *gst_name;
3203 "WM/Genre", GST_TAG_GENRE}, {
3204 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3205 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3206 "WM/PartOfSet", GST_TAG_ALBUM_VOLUME_COUNT}, {
3207 "WM/Picture", GST_TAG_IMAGE}, {
3208 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3209 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3210 "WM/Year", GST_TAG_DATE_TIME}
3211 /* { "WM/Composer", GST_TAG_COMPOSER } */
3217 if (name_utf8 == NULL) {
3218 GST_WARNING ("Failed to convert name to UTF8, skipping");
3222 out = strlen (name_utf8);
3224 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3225 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3226 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3227 return tags[i].gst_name;
3234 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3236 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3240 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3242 if (taglist == NULL)
3245 if (gst_tag_list_is_empty (taglist)) {
3246 gst_tag_list_unref (taglist);
3250 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3251 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3253 gst_tag_list_unref (demux->taglist);
3254 gst_tag_list_unref (taglist);
3256 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3259 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3260 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3261 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3262 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3265 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3269 const guint8 *img_data = NULL;
3270 guint32 img_data_len = 0;
3271 guint8 pic_type = 0;
3273 gst_byte_reader_init (&r, tag_data, tag_data_len);
3275 /* skip mime type string (we don't trust it and do our own typefinding),
3276 * and also skip the description string, since we don't use it */
3277 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3278 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3279 !gst_byte_reader_skip_string_utf16 (&r) ||
3280 !gst_byte_reader_skip_string_utf16 (&r) ||
3281 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3282 goto not_enough_data;
3286 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3287 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3293 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3294 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3299 /* Extended Content Description Object */
3300 static GstFlowReturn
3301 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3304 /* Other known (and unused) 'text/unicode' metadata available :
3307 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3308 * WMFSDKVersion = 9.00.00.2980
3309 * WMFSDKNeeded = 0.0.0.0000
3310 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3311 * WM/Publisher = 4AD
3313 * WM/ProviderRating = 8
3314 * WM/ProviderStyle = Rock (similar to WM/Genre)
3315 * WM/GenreID (similar to WM/Genre)
3316 * WM/TrackNumber (same as WM/Track but as a string)
3318 * Other known (and unused) 'non-text' metadata available :
3324 * We might want to read WM/TrackNumber and use atoi() if we don't have
3328 GstTagList *taglist;
3329 guint16 blockcount, i;
3330 gboolean content3D = FALSE;
3335 const gchar *interleave_name;
3336 GstASF3DMode interleaving_type;
3337 } stereoscopic_layout_map[] = {
3339 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3340 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3341 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3342 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3343 "DualStream", GST_ASF_3D_DUAL_STREAM}
3347 GST_INFO_OBJECT (demux, "object is an extended content description");
3349 taglist = gst_tag_list_new_empty ();
3351 /* Content Descriptor Count */
3353 goto not_enough_data;
3355 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3357 for (i = 1; i <= blockcount; ++i) {
3358 const gchar *gst_tag_name;
3362 GValue tag_value = { 0, };
3365 gchar *name_utf8 = NULL;
3369 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3370 goto not_enough_data;
3374 goto not_enough_data;
3376 /* Descriptor Value Data Type */
3377 datatype = gst_asf_demux_get_uint16 (&data, &size);
3379 /* Descriptor Value (not really a string, but same thing reading-wise) */
3380 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3382 goto not_enough_data;
3386 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3388 if (name_utf8 != NULL) {
3389 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3391 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3392 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3395 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3398 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3401 /* get rid of tags with empty value */
3402 if (value_utf8 != NULL && *value_utf8 != '\0') {
3403 GST_DEBUG ("string value %s", value_utf8);
3405 value_utf8[out] = '\0';
3407 if (gst_tag_name != NULL) {
3408 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3409 guint year = atoi (value_utf8);
3412 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3413 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3415 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3416 guint id3v1_genre_id;
3417 const gchar *genre_str;
3419 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3420 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3421 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3422 g_free (value_utf8);
3423 value_utf8 = g_strdup (genre_str);
3425 } else if (!strcmp (gst_tag_name, GST_TAG_ALBUM_VOLUME_COUNT)) {
3426 guint num = 0, count = 0;
3428 if (sscanf (value_utf8, "%u/%u", &num, &count) == 2
3429 && num > 0 && num <= 99999 && count > 0 && count <= 99999) {
3430 GST_DEBUG ("Disc %u of %u (%s)", num, count, value_utf8);
3431 g_value_init (&tag_value, G_TYPE_UINT);
3433 g_value_set_uint (&tag_value, num);
3434 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3435 GST_TAG_ALBUM_VOLUME_NUMBER, &tag_value, NULL);
3436 /* disc count (will be added to the taglist below) */
3437 g_value_set_uint (&tag_value, count);
3439 GST_DEBUG ("Couldn't parse PartOfSet value %s", value_utf8);
3444 /* convert tag from string to other type if required */
3445 tag_type = gst_tag_get_type (gst_tag_name);
3446 g_value_init (&tag_value, tag_type);
3447 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3448 GValue from_val = { 0, };
3450 g_value_init (&from_val, G_TYPE_STRING);
3451 g_value_set_string (&from_val, value_utf8);
3452 if (!g_value_transform (&from_val, &tag_value)) {
3453 GST_WARNING_OBJECT (demux,
3454 "Could not transform string tag to " "%s tag type %s",
3455 gst_tag_name, g_type_name (tag_type));
3456 g_value_unset (&tag_value);
3458 g_value_unset (&from_val);
3463 GST_DEBUG ("Setting metadata");
3464 g_value_init (&tag_value, G_TYPE_STRING);
3465 g_value_set_string (&tag_value, value_utf8);
3466 /* If we found a stereoscopic marker, look for StereoscopicLayout
3470 if (strncmp ("StereoscopicLayout", name_utf8,
3471 strlen (name_utf8)) == 0) {
3472 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3473 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3475 demux->asf_3D_mode =
3476 stereoscopic_layout_map[i].interleaving_type;
3477 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3481 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3483 demux->asf_3D_mode = GST_ASF_3D_NONE;
3484 GST_INFO_OBJECT (demux, "None 3d type");
3487 } else if (value_utf8 == NULL) {
3488 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3490 GST_DEBUG ("Skipping empty string value for %s",
3491 GST_STR_NULL (gst_tag_name));
3493 g_free (value_utf8);
3496 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3498 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3499 GST_FIXME ("Unhandled byte array tag %s",
3500 GST_STR_NULL (gst_tag_name));
3503 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3509 case ASF_DEMUX_DATA_TYPE_DWORD:{
3515 uint_val = GST_READ_UINT32_LE (value);
3517 /* this is the track number */
3518 g_value_init (&tag_value, G_TYPE_UINT);
3520 /* WM/Track counts from 0 */
3521 if (!strcmp (name_utf8, "WM/Track"))
3524 g_value_set_uint (&tag_value, uint_val);
3528 case ASF_DEMUX_DATA_TYPE_BOOL:{
3534 bool_val = GST_READ_UINT32_LE (value);
3536 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3538 GST_INFO_OBJECT (demux, "This is 3D contents");
3541 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3549 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3554 if (G_IS_VALUE (&tag_value)) {
3556 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3558 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3559 * is supposed to have a 0 base but is often wrongly written to start
3560 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3561 * replace the value added earlier from WM/Track or put it first in
3562 * the list, so that it will get picked up by _get_uint() */
3563 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3564 merge_mode = GST_TAG_MERGE_REPLACE;
3566 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3569 GST_DEBUG ("Setting global metadata %s", name_utf8);
3570 gst_structure_set_value (demux->global_metadata, name_utf8,
3574 g_value_unset (&tag_value);
3583 gst_asf_demux_add_global_tags (demux, taglist);
3590 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3591 gst_tag_list_unref (taglist);
3592 return GST_FLOW_OK; /* not really fatal */
3596 static GstStructure *
3597 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3602 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3604 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3607 s = gst_caps_get_structure (demux->metadata, i);
3608 if (gst_structure_has_name (s, sname))
3612 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3614 /* try lookup again; demux->metadata took ownership of the structure, so we
3615 * can't really make any assumptions about what happened to it, so we can't
3616 * just return it directly after appending it */
3617 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3620 static GstFlowReturn
3621 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3624 guint16 blockcount, i;
3626 GST_INFO_OBJECT (demux, "object is a metadata object");
3628 /* Content Descriptor Count */
3630 goto not_enough_data;
3632 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3634 for (i = 0; i < blockcount; ++i) {
3636 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3637 guint32 data_len, ival;
3640 if (size < (2 + 2 + 2 + 2 + 4))
3641 goto not_enough_data;
3643 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3644 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3645 name_len = gst_asf_demux_get_uint16 (&data, &size);
3646 data_type = gst_asf_demux_get_uint16 (&data, &size);
3647 data_len = gst_asf_demux_get_uint32 (&data, &size);
3649 if (size < name_len + data_len)
3650 goto not_enough_data;
3652 /* convert name to UTF-8 */
3653 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3655 gst_asf_demux_skip_bytes (name_len, &data, &size);
3657 if (name_utf8 == NULL) {
3658 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3659 gst_asf_demux_skip_bytes (data_len, &data, &size);
3663 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3664 gst_asf_demux_skip_bytes (data_len, &data, &size);
3672 goto not_enough_data;
3675 ival = gst_asf_demux_get_uint32 (&data, &size);
3677 /* skip anything else there may be, just in case */
3678 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3680 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3681 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3685 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3691 GST_WARNING ("Unexpected end of data parsing metadata object");
3692 return GST_FLOW_OK; /* not really fatal */
3696 static GstFlowReturn
3697 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3699 GstFlowReturn ret = GST_FLOW_OK;
3700 guint32 i, num_objects;
3701 guint8 unknown G_GNUC_UNUSED;
3703 /* Get the rest of the header's header */
3704 if (size < (4 + 1 + 1))
3705 goto not_enough_data;
3707 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3708 unknown = gst_asf_demux_get_uint8 (&data, &size);
3709 unknown = gst_asf_demux_get_uint8 (&data, &size);
3711 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3712 demux->saw_file_header = FALSE;
3713 /* Loop through the header's objects, processing those */
3714 for (i = 0; i < num_objects; ++i) {
3715 GST_INFO_OBJECT (demux, "reading header part %u", i);
3716 ret = gst_asf_demux_process_object (demux, &data, &size);
3717 if (ret != GST_FLOW_OK) {
3718 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3722 if (!demux->saw_file_header) {
3723 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3724 ("Header does not have mandatory FILE section"));
3725 return GST_FLOW_ERROR;
3732 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3733 ("short read parsing HEADER object"));
3734 return GST_FLOW_ERROR;
3738 static GstFlowReturn
3739 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3741 guint64 creation_time G_GNUC_UNUSED;
3742 guint64 file_size G_GNUC_UNUSED;
3743 guint64 send_time G_GNUC_UNUSED;
3744 guint64 packets_count, play_time, preroll;
3745 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3747 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3748 goto not_enough_data;
3750 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3751 file_size = gst_asf_demux_get_uint64 (&data, &size);
3752 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3753 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3754 play_time = gst_asf_demux_get_uint64 (&data, &size);
3755 send_time = gst_asf_demux_get_uint64 (&data, &size);
3756 preroll = gst_asf_demux_get_uint64 (&data, &size);
3757 flags = gst_asf_demux_get_uint32 (&data, &size);
3758 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3759 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3760 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3762 demux->broadcast = ! !(flags & 0x01);
3763 demux->seekable = ! !(flags & 0x02);
3765 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3766 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3767 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3769 if (demux->broadcast) {
3770 /* these fields are invalid if the broadcast flag is set */
3775 if (min_pktsize != max_pktsize)
3776 goto non_fixed_packet_size;
3778 demux->packet_size = max_pktsize;
3780 /* FIXME: do we need send_time as well? what is it? */
3781 if ((play_time * 100) >= (preroll * GST_MSECOND))
3782 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3784 demux->play_time = 0;
3786 demux->preroll = preroll * GST_MSECOND;
3788 /* initial latency */
3789 demux->latency = demux->preroll;
3791 if (demux->play_time == 0)
3792 demux->seekable = FALSE;
3794 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3795 GST_TIME_ARGS (demux->play_time));
3796 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3797 GST_TIME_ARGS (demux->preroll));
3799 if (demux->play_time > 0) {
3800 demux->segment.duration = demux->play_time;
3803 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3805 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3807 demux->saw_file_header = TRUE;
3812 non_fixed_packet_size:
3814 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3815 ("packet size must be fixed"));
3816 return GST_FLOW_ERROR;
3820 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3821 ("short read parsing FILE object"));
3822 return GST_FLOW_ERROR;
3826 /* Content Description Object */
3827 static GstFlowReturn
3828 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3833 const gchar *gst_tag;
3838 GST_TAG_TITLE, 0, NULL}, {
3839 GST_TAG_ARTIST, 0, NULL}, {
3840 GST_TAG_COPYRIGHT, 0, NULL}, {
3841 GST_TAG_DESCRIPTION, 0, NULL}, {
3842 GST_TAG_COMMENT, 0, NULL}
3845 GstTagList *taglist;
3846 GValue value = { 0 };
3850 GST_INFO_OBJECT (demux, "object is a comment");
3852 if (size < (2 + 2 + 2 + 2 + 2))
3853 goto not_enough_data;
3855 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3856 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3857 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3858 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3859 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3861 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3862 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3863 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3865 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3866 if (size < tags[i].val_length)
3867 goto not_enough_data;
3869 /* might be just '/0', '/0'... */
3870 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3871 /* convert to UTF-8 */
3872 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3873 "UTF-8", "UTF-16LE", &in, &out, NULL);
3875 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3878 /* parse metadata into taglist */
3879 taglist = gst_tag_list_new_empty ();
3880 g_value_init (&value, G_TYPE_STRING);
3881 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3882 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3883 g_value_set_string (&value, tags[i].val_utf8);
3884 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3885 tags[i].gst_tag, &value, NULL);
3888 g_value_unset (&value);
3890 gst_asf_demux_add_global_tags (demux, taglist);
3892 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3893 g_free (tags[i].val_utf8);
3899 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3900 "comment tag section %d, skipping comment object", i);
3901 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3902 g_free (tags[i].val_utf8);
3903 return GST_FLOW_OK; /* not really fatal */
3907 static GstFlowReturn
3908 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3911 guint16 num_streams, i;
3915 goto not_enough_data;
3917 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3919 GST_INFO ("object is a bitrate properties object with %u streams",
3922 if (size < (num_streams * (2 + 4)))
3923 goto not_enough_data;
3925 for (i = 0; i < num_streams; ++i) {
3929 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3930 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3932 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3933 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3934 stream = gst_asf_demux_get_stream (demux, stream_id);
3936 if (stream->pending_tags == NULL)
3937 stream->pending_tags = gst_tag_list_new_empty ();
3938 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3939 GST_TAG_BITRATE, bitrate, NULL);
3941 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3944 GST_WARNING ("stream id %u is too large", stream_id);
3952 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3953 return GST_FLOW_OK; /* not really fatal */
3957 static GstFlowReturn
3958 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3961 GstFlowReturn ret = GST_FLOW_OK;
3964 /* Get the rest of the header's header */
3965 if (size < (16 + 2 + 4))
3966 goto not_enough_data;
3968 /* skip GUID and two other bytes */
3969 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3970 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3972 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3974 /* FIXME: does data_size include the rest of the header that we have read? */
3975 if (hdr_size > size)
3976 goto not_enough_data;
3978 while (hdr_size > 0) {
3979 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3980 if (ret != GST_FLOW_OK)
3988 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3989 ("short read parsing extended header object"));
3990 return GST_FLOW_ERROR;
3994 static GstFlowReturn
3995 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
4001 goto not_enough_data;
4003 if (demux->languages) {
4004 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
4005 g_strfreev (demux->languages);
4006 demux->languages = NULL;
4007 demux->num_languages = 0;
4010 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
4011 GST_LOG ("%u languages:", demux->num_languages);
4013 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
4014 for (i = 0; i < demux->num_languages; ++i) {
4015 guint8 len, *lang_data = NULL;
4018 goto not_enough_data;
4019 len = gst_asf_demux_get_uint8 (&data, &size);
4020 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
4023 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
4026 /* truncate "en-us" etc. to just "en" */
4027 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
4030 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
4031 demux->languages[i] = utf8;
4034 goto not_enough_data;
4042 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
4043 g_free (demux->languages);
4044 demux->languages = NULL;
4045 demux->num_languages = 0;
4046 return GST_FLOW_OK; /* not fatal */
4050 static GstFlowReturn
4051 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
4054 GstClockTime interval;
4057 if (size < (16 + 8 + 4 + 4))
4058 goto not_enough_data;
4061 gst_asf_demux_skip_bytes (16, &data, &size);
4062 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
4063 gst_asf_demux_skip_bytes (4, &data, &size);
4064 count = gst_asf_demux_get_uint32 (&data, &size);
4066 demux->sidx_interval = interval;
4067 demux->sidx_num_entries = count;
4068 g_free (demux->sidx_entries);
4069 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
4071 for (i = 0; i < count; ++i) {
4072 if (G_UNLIKELY (size < 6)) {
4073 /* adjust for broken files, to avoid having entries at the end
4074 * of the parsed index that point to time=0. Resulting in seeking to
4075 * the end of the file leading back to the beginning */
4076 demux->sidx_num_entries -= (count - i);
4079 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4080 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4081 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4082 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4083 demux->sidx_entries[i].count);
4086 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4093 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4094 return GST_FLOW_OK; /* not fatal */
4098 static GstFlowReturn
4099 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4100 guint8 * data, guint64 size)
4105 if (size < 16 + 2 + (2 * 2))
4106 goto not_enough_data;
4108 gst_asf_demux_get_guid (&guid, &data, &size);
4109 num = gst_asf_demux_get_uint16 (&data, &size);
4112 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4116 if (size < (num * sizeof (guint16)))
4117 goto not_enough_data;
4119 /* read mutually exclusive stream numbers */
4120 for (i = 0; i < num; ++i) {
4122 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4123 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4125 demux->mut_ex_streams =
4126 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4135 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4136 return GST_FLOW_OK; /* not absolutely fatal */
4141 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4143 return g_slist_find (demux->other_streams,
4144 GINT_TO_POINTER (stream_num)) == NULL;
4147 static GstFlowReturn
4148 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4151 AsfStreamExtProps esp;
4152 AsfStream *stream = NULL;
4153 AsfObject stream_obj;
4154 guint16 stream_name_count;
4155 guint16 num_payload_ext;
4157 guint8 *stream_obj_data = NULL;
4160 guint i, stream_num;
4163 obj_size = (guint) size;
4165 esp.payload_extensions = NULL;
4168 goto not_enough_data;
4171 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4172 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4173 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4174 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4175 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4176 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4177 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4178 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4179 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4180 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4181 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4182 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4183 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4184 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4185 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4187 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4188 GST_TIME_ARGS (esp.start_time));
4189 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4190 GST_TIME_ARGS (esp.end_time));
4191 GST_INFO ("flags = %08x", esp.flags);
4192 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4193 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4194 GST_INFO ("stream number = %u", stream_num);
4195 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4196 (esp.lang_idx < demux->num_languages) ?
4197 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4198 GST_INFO ("stream name count = %u", stream_name_count);
4200 /* read stream names */
4201 for (i = 0; i < stream_name_count; ++i) {
4202 guint16 stream_lang_idx G_GNUC_UNUSED;
4203 gchar *stream_name = NULL;
4206 goto not_enough_data;
4207 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4208 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4209 goto not_enough_data;
4210 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4211 g_free (stream_name); /* TODO: store names in struct */
4214 /* read payload extension systems stuff */
4215 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4217 if (num_payload_ext > 0)
4218 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4220 for (i = 0; i < num_payload_ext; ++i) {
4221 AsfPayloadExtension ext;
4223 guint32 sys_info_len;
4225 if (size < 16 + 2 + 4)
4226 goto not_enough_data;
4228 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4229 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4230 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4232 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4233 GST_LOG ("payload systems info len = %u", sys_info_len);
4234 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4235 goto not_enough_data;
4237 esp.payload_extensions[i] = ext;
4240 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4242 /* there might be an optional STREAM_INFO object here now; if not, we
4243 * should have parsed the corresponding stream info object already (since
4244 * we are parsing the extended stream properties objects delayed) */
4246 stream = gst_asf_demux_get_stream (demux, stream_num);
4250 if (size < ASF_OBJECT_HEADER_SIZE)
4251 goto not_enough_data;
4253 /* get size of the stream object */
4254 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4255 goto corrupted_stream;
4257 if (stream_obj.id != ASF_OBJ_STREAM)
4258 goto expected_stream_object;
4260 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4261 stream_obj.size > (10 * 1024 * 1024))
4262 goto not_enough_data;
4264 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4266 /* process this stream object later after all the other 'normal' ones
4267 * have been processed (since the others are more important/non-hidden) */
4268 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4269 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4270 goto not_enough_data;
4272 /* parse stream object */
4273 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4274 g_free (stream_obj_data);
4279 stream->ext_props = esp;
4281 /* try to set the framerate */
4282 if (stream->is_video && stream->caps) {
4283 GValue framerate = { 0 };
4287 g_value_init (&framerate, GST_TYPE_FRACTION);
4289 num = GST_SECOND / 100;
4290 denom = esp.avg_time_per_frame;
4292 /* avoid division by 0, assume 25/1 framerate */
4293 denom = GST_SECOND / 2500;
4296 gst_value_set_fraction (&framerate, num, denom);
4298 stream->caps = gst_caps_make_writable (stream->caps);
4299 s = gst_caps_get_structure (stream->caps, 0);
4300 gst_structure_set_value (s, "framerate", &framerate);
4301 g_value_unset (&framerate);
4302 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4303 num, denom, ((gdouble) num) / denom);
4306 /* add language info now if we have it */
4307 if (stream->ext_props.lang_idx < demux->num_languages) {
4308 if (stream->pending_tags == NULL)
4309 stream->pending_tags = gst_tag_list_new_empty ();
4310 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4311 demux->languages[stream->ext_props.lang_idx]);
4312 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4313 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4316 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4317 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4321 g_free (esp.payload_extensions);
4328 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4329 g_free (esp.payload_extensions);
4330 return GST_FLOW_OK; /* not absolutely fatal */
4332 expected_stream_object:
4334 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4335 "object: expected embedded stream object, but got %s object instead!",
4336 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4337 g_free (esp.payload_extensions);
4338 return GST_FLOW_OK; /* not absolutely fatal */
4342 GST_WARNING_OBJECT (demux, "Corrupted stream");
4343 g_free (esp.payload_extensions);
4344 return GST_FLOW_ERROR;
4348 static const gchar *
4349 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4353 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4354 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4355 nick += strlen ("ASF_OBJ_");
4357 if (demux->objpath == NULL) {
4358 demux->objpath = g_strdup (nick);
4362 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4363 g_free (demux->objpath);
4364 demux->objpath = newpath;
4367 return (const gchar *) demux->objpath;
4371 gst_asf_demux_pop_obj (GstASFDemux * demux)
4375 if ((s = g_strrstr (demux->objpath, "/"))) {
4378 g_free (demux->objpath);
4379 demux->objpath = NULL;
4384 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4389 /* Parse the queued extended stream property objects and add the info
4390 * to the existing streams or add the new embedded streams, but without
4391 * activating them yet */
4392 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4393 g_slist_length (demux->ext_stream_props));
4395 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4396 GstBuffer *buf = GST_BUFFER (l->data);
4399 gst_buffer_map (buf, &map, GST_MAP_READ);
4401 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4402 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4403 gst_buffer_unmap (buf, &map);
4404 gst_buffer_unref (buf);
4406 g_slist_free (demux->ext_stream_props);
4407 demux->ext_stream_props = NULL;
4412 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4416 for (i = 0; i < demux->num_streams; ++i) {
4421 stream = &demux->stream[i];
4423 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4425 if (stream->active) {
4426 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4431 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4434 /* check for each mutual exclusion whether it affects this stream */
4435 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4436 if (*mes == stream->id) {
4437 /* if yes, check if we've already added streams that are mutually
4438 * exclusive with the stream we're about to add */
4439 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4440 for (j = 0; j < demux->num_streams; ++j) {
4441 /* if the broadcast flag is set, assume the hidden streams aren't
4442 * actually streamed and hide them (or playbin won't work right),
4443 * otherwise assume their data is available */
4444 if (demux->stream[j].id == *mes && demux->broadcast) {
4446 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4447 "mutually exclusive with already existing stream ID %d, "
4448 "hiding stream", stream->id, demux->stream[j].id);
4460 /* FIXME: we should do stream activation based on preroll data in
4461 * streaming mode too */
4462 if (demux->streaming && !is_hidden)
4463 gst_asf_demux_activate_stream (demux, stream);
4468 static GstFlowReturn
4469 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4472 GstFlowReturn ret = GST_FLOW_OK;
4474 guint64 obj_data_size;
4476 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4477 return ASF_FLOW_NEED_MORE_DATA;
4479 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4481 return GST_FLOW_ERROR;
4482 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4484 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4486 if (*p_size < obj_data_size)
4487 return ASF_FLOW_NEED_MORE_DATA;
4489 gst_asf_demux_push_obj (demux, obj.id);
4491 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4494 case ASF_OBJ_STREAM:
4495 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4499 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4501 case ASF_OBJ_HEADER:
4502 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4504 case ASF_OBJ_COMMENT:
4505 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4508 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4510 case ASF_OBJ_BITRATE_PROPS:
4512 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4515 case ASF_OBJ_EXT_CONTENT_DESC:
4517 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4520 case ASF_OBJ_METADATA_OBJECT:
4521 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4523 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4526 /* process these later, we might not have parsed the corresponding
4527 * stream object yet */
4528 GST_LOG ("%s: queued for later parsing", demux->objpath);
4529 buf = gst_buffer_new_and_alloc (obj_data_size);
4530 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4531 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4535 case ASF_OBJ_LANGUAGE_LIST:
4536 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4538 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4539 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4542 case ASF_OBJ_SIMPLE_INDEX:
4543 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4545 case ASF_OBJ_CONTENT_ENCRYPTION:
4546 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4547 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4548 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4549 goto error_encrypted;
4550 case ASF_OBJ_CONCEAL_NONE:
4552 case ASF_OBJ_UNDEFINED:
4553 case ASF_OBJ_CODEC_COMMENT:
4555 case ASF_OBJ_PADDING:
4556 case ASF_OBJ_BITRATE_MUTEX:
4557 case ASF_OBJ_COMPATIBILITY:
4558 case ASF_OBJ_INDEX_PLACEHOLDER:
4559 case ASF_OBJ_INDEX_PARAMETERS:
4560 case ASF_OBJ_STREAM_PRIORITIZATION:
4561 case ASF_OBJ_SCRIPT_COMMAND:
4562 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4564 /* Unknown/unhandled object, skip it and hope for the best */
4565 GST_INFO ("%s: skipping object", demux->objpath);
4570 /* this can't fail, we checked the number of bytes available before */
4571 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4573 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4575 gst_asf_demux_pop_obj (demux);
4582 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4583 return GST_FLOW_ERROR;
4588 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4589 GstBuffer ** p_buffer)
4591 GstBuffer *descrambled_buffer;
4592 GstBuffer *scrambled_buffer;
4593 GstBuffer *sub_buffer;
4600 /* descrambled_buffer is initialised in the first iteration */
4601 descrambled_buffer = NULL;
4602 scrambled_buffer = *p_buffer;
4604 if (gst_buffer_get_size (scrambled_buffer) <
4605 stream->ds_packet_size * stream->span)
4608 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4609 offset += stream->ds_chunk_size) {
4610 off = offset / stream->ds_chunk_size;
4611 row = off / stream->span;
4612 col = off % stream->span;
4613 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4614 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4615 col, off, stream->ds_chunk_size);
4616 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4617 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4618 stream->span, stream->ds_packet_size);
4619 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4620 gst_buffer_get_size (scrambled_buffer));
4622 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4623 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4625 descrambled_buffer = sub_buffer;
4627 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4631 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4632 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4633 GST_BUFFER_DURATION (descrambled_buffer) =
4634 GST_BUFFER_DURATION (scrambled_buffer);
4635 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4636 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4637 GST_BUFFER_OFFSET_END (scrambled_buffer);
4639 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4641 gst_buffer_unref (scrambled_buffer);
4642 *p_buffer = descrambled_buffer;
4646 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4648 GstASFDemux *demux = GST_ASF_DEMUX (element);
4651 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4653 for (i = 0; i < demux->num_streams; ++i) {
4654 gst_event_ref (event);
4655 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4656 GST_OBJECT_CAST (element), event)) {
4657 gst_event_unref (event);
4662 gst_event_unref (event);
4666 /* takes ownership of the passed event */
4668 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4670 gboolean ret = TRUE;
4673 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4674 GST_EVENT_TYPE_NAME (event));
4676 for (i = 0; i < demux->num_streams; ++i) {
4677 gst_event_ref (event);
4678 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4680 gst_event_unref (event);
4685 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4689 gboolean res = FALSE;
4691 demux = GST_ASF_DEMUX (parent);
4693 GST_DEBUG ("handling %s query",
4694 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4696 switch (GST_QUERY_TYPE (query)) {
4697 case GST_QUERY_DURATION:
4701 gst_query_parse_duration (query, &format, NULL);
4703 if (format != GST_FORMAT_TIME) {
4704 GST_LOG ("only support duration queries in TIME format");
4708 res = gst_pad_query_default (pad, parent, query);
4710 GST_OBJECT_LOCK (demux);
4712 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4713 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4714 GST_TIME_ARGS (demux->segment.duration));
4716 gst_query_set_duration (query, GST_FORMAT_TIME,
4717 demux->segment.duration);
4721 GST_LOG ("duration not known yet");
4724 GST_OBJECT_UNLOCK (demux);
4729 case GST_QUERY_POSITION:{
4732 gst_query_parse_position (query, &format, NULL);
4734 if (format != GST_FORMAT_TIME) {
4735 GST_LOG ("only support position queries in TIME format");
4739 GST_OBJECT_LOCK (demux);
4741 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4742 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4743 GST_TIME_ARGS (demux->segment.position));
4745 gst_query_set_position (query, GST_FORMAT_TIME,
4746 demux->segment.position);
4750 GST_LOG ("position not known yet");
4753 GST_OBJECT_UNLOCK (demux);
4757 case GST_QUERY_SEEKING:{
4760 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4761 if (format == GST_FORMAT_TIME) {
4764 GST_OBJECT_LOCK (demux);
4765 duration = demux->segment.duration;
4766 GST_OBJECT_UNLOCK (demux);
4768 if (!demux->streaming || !demux->seekable) {
4769 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4776 /* try upstream first in TIME */
4777 res = gst_pad_query_default (pad, parent, query);
4779 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4780 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4781 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4782 /* if no luck, maybe in BYTES */
4783 if (!seekable || fmt != GST_FORMAT_TIME) {
4786 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4787 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4788 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4789 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4790 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4791 if (fmt != GST_FORMAT_BYTES)
4794 gst_query_unref (q);
4795 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4801 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4805 case GST_QUERY_LATENCY:
4808 GstClockTime min, max;
4810 /* preroll delay does not matter in non-live pipeline,
4811 * but we might end up in a live (rtsp) one ... */
4814 res = gst_pad_query_default (pad, parent, query);
4818 gst_query_parse_latency (query, &live, &min, &max);
4820 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4821 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4822 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4824 GST_OBJECT_LOCK (demux);
4825 min += demux->latency;
4827 max += demux->latency;
4828 GST_OBJECT_UNLOCK (demux);
4830 gst_query_set_latency (query, live, min, max);
4833 case GST_QUERY_SEGMENT:
4838 format = demux->segment.format;
4841 gst_segment_to_stream_time (&demux->segment, format,
4842 demux->segment.start);
4843 if ((stop = demux->segment.stop) == -1)
4844 stop = demux->segment.duration;
4846 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4848 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4853 res = gst_pad_query_default (pad, parent, query);
4861 gst_asf_demux_finalize (GObject * object)
4863 GstASFDemux *demux = GST_ASF_DEMUX (object);
4865 if (demux->metadata)
4866 gst_caps_unref (demux->metadata);
4867 demux->metadata = NULL;
4869 if (demux->global_metadata)
4870 gst_structure_free (demux->global_metadata);
4871 demux->global_metadata = NULL;
4873 G_OBJECT_CLASS (parent_class)->finalize (object);
4876 static GstStateChangeReturn
4877 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4879 GstASFDemux *demux = GST_ASF_DEMUX (element);
4880 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4882 switch (transition) {
4883 case GST_STATE_CHANGE_NULL_TO_READY:{
4884 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4885 demux->need_newsegment = TRUE;
4886 demux->segment_running = FALSE;
4887 demux->keyunit_sync = FALSE;
4888 demux->accurate = FALSE;
4889 demux->adapter = gst_adapter_new ();
4890 demux->data_size = 0;
4891 demux->data_offset = 0;
4892 demux->index_offset = 0;
4893 demux->base_offset = 0;
4894 demux->flowcombiner = gst_flow_combiner_new ();
4902 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4903 if (ret == GST_STATE_CHANGE_FAILURE)
4906 switch (transition) {
4907 case GST_STATE_CHANGE_PAUSED_TO_READY:
4908 gst_asf_demux_reset (demux, FALSE);
4911 case GST_STATE_CHANGE_READY_TO_NULL:
4912 gst_asf_demux_reset (demux, FALSE);
4913 gst_flow_combiner_free (demux->flowcombiner);
4914 demux->flowcombiner = NULL;