1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <gst/video/video.h>
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS ("video/x-ms-asf")
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE (16+8)
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA 99
76 #define gst_asf_get_flow_name(flow) \
77 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
78 "need-more-data" : gst_flow_get_name (flow)
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83 GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89 GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98 GstObject * parent, GstPadMode mode, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
103 GstFlowReturn * pflow);
104 static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109 AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
123 GstElementClass *gstelement_class;
125 gstelement_class = (GstElementClass *) klass;
127 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
129 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 gst_element_class_add_static_pad_template (gstelement_class,
132 &audio_src_template);
133 gst_element_class_add_static_pad_template (gstelement_class,
134 &video_src_template);
135 gst_element_class_add_static_pad_template (gstelement_class,
136 &gst_asf_demux_sink_template);
138 gstelement_class->change_state =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140 gstelement_class->send_event =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 gst_caps_replace (&stream->caps, NULL);
148 if (stream->pending_tags) {
149 gst_tag_list_unref (stream->pending_tags);
150 stream->pending_tags = NULL;
152 if (stream->streamheader) {
153 gst_buffer_unref (stream->streamheader);
154 stream->streamheader = NULL;
157 if (stream->active) {
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
161 gst_object_unref (stream->pad);
165 if (stream->payloads) {
166 while (stream->payloads->len > 0) {
170 last = stream->payloads->len - 1;
171 payload = &g_array_index (stream->payloads, AsfPayload, last);
172 gst_buffer_replace (&payload->buf, NULL);
173 g_array_remove_index (stream->payloads, last);
175 g_array_free (stream->payloads, TRUE);
176 stream->payloads = NULL;
179 if (stream->payloads_rev) {
180 while (stream->payloads_rev->len > 0) {
184 last = stream->payloads_rev->len - 1;
185 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186 gst_buffer_replace (&payload->buf, NULL);
187 g_array_remove_index (stream->payloads_rev, last);
189 g_array_free (stream->payloads_rev, TRUE);
190 stream->payloads_rev = NULL;
193 if (stream->ext_props.valid) {
194 g_free (stream->ext_props.payload_extensions);
195 stream->ext_props.payload_extensions = NULL;
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
202 GST_LOG_OBJECT (demux, "resetting");
204 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205 demux->segment_running = FALSE;
206 if (demux->adapter && !chain_reset) {
207 gst_adapter_clear (demux->adapter);
208 g_object_unref (demux->adapter);
209 demux->adapter = NULL;
211 if (demux->taglist) {
212 gst_tag_list_unref (demux->taglist);
213 demux->taglist = NULL;
215 if (demux->metadata) {
216 gst_caps_unref (demux->metadata);
217 demux->metadata = NULL;
219 if (demux->global_metadata) {
220 gst_structure_free (demux->global_metadata);
221 demux->global_metadata = NULL;
223 if (demux->mut_ex_streams) {
224 g_slist_free (demux->mut_ex_streams);
225 demux->mut_ex_streams = NULL;
228 demux->state = GST_ASF_DEMUX_STATE_HEADER;
229 g_free (demux->objpath);
230 demux->objpath = NULL;
231 g_strfreev (demux->languages);
232 demux->languages = NULL;
233 demux->num_languages = 0;
234 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
236 g_slist_free (demux->ext_stream_props);
237 demux->ext_stream_props = NULL;
239 while (demux->old_num_streams > 0) {
240 gst_asf_demux_free_stream (demux,
241 &demux->old_stream[demux->old_num_streams - 1]);
242 --demux->old_num_streams;
244 memset (demux->old_stream, 0, sizeof (demux->old_stream));
245 demux->old_num_streams = 0;
247 /* when resetting for a new chained asf, we don't want to remove the pads
248 * before adding the new ones */
250 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251 demux->old_num_streams = demux->num_streams;
252 demux->num_streams = 0;
255 while (demux->num_streams > 0) {
256 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257 --demux->num_streams;
259 memset (demux->stream, 0, sizeof (demux->stream));
261 /* do not remove those for not adding pads with same name */
262 demux->num_audio_streams = 0;
263 demux->num_video_streams = 0;
264 demux->have_group_id = FALSE;
265 demux->group_id = G_MAXUINT;
267 demux->num_streams = 0;
268 demux->activated_streams = FALSE;
269 demux->first_ts = GST_CLOCK_TIME_NONE;
270 demux->segment_ts = GST_CLOCK_TIME_NONE;
273 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274 demux->state = GST_ASF_DEMUX_STATE_HEADER;
275 demux->seekable = FALSE;
276 demux->broadcast = FALSE;
277 demux->sidx_interval = 0;
278 demux->sidx_num_entries = 0;
279 g_free (demux->sidx_entries);
280 demux->sidx_entries = NULL;
282 demux->speed_packets = 1;
284 demux->asf_3D_mode = GST_ASF_3D_NONE;
287 GST_LOG_OBJECT (demux, "Restarting");
288 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289 demux->need_newsegment = TRUE;
290 demux->segment_seqnum = 0;
291 demux->segment_running = FALSE;
292 demux->keyunit_sync = FALSE;
293 demux->accurate = FALSE;
294 demux->metadata = gst_caps_new_empty ();
295 demux->global_metadata = gst_structure_new_empty ("metadata");
296 demux->data_size = 0;
297 demux->data_offset = 0;
298 demux->index_offset = 0;
300 demux->base_offset = 0;
303 g_slist_free (demux->other_streams);
304 demux->other_streams = NULL;
308 gst_asf_demux_init (GstASFDemux * demux)
311 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312 gst_pad_set_chain_function (demux->sinkpad,
313 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314 gst_pad_set_event_function (demux->sinkpad,
315 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316 gst_pad_set_activate_function (demux->sinkpad,
317 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318 gst_pad_set_activatemode_function (demux->sinkpad,
319 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
322 /* set initial state */
323 gst_asf_demux_reset (demux, FALSE);
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
332 query = gst_query_new_scheduling ();
334 if (!gst_pad_peer_query (sinkpad, query)) {
335 gst_query_unref (query);
339 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341 gst_query_unref (query);
346 GST_DEBUG_OBJECT (sinkpad, "activating pull");
347 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
351 GST_DEBUG_OBJECT (sinkpad, "activating push");
352 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358 GstPadMode mode, gboolean active)
363 demux = GST_ASF_DEMUX (parent);
366 case GST_PAD_MODE_PUSH:
367 demux->state = GST_ASF_DEMUX_STATE_HEADER;
368 demux->streaming = TRUE;
371 case GST_PAD_MODE_PULL:
373 demux->state = GST_ASF_DEMUX_STATE_HEADER;
374 demux->streaming = FALSE;
376 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
379 res = gst_pad_stop_task (sinkpad);
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
395 demux = GST_ASF_DEMUX (parent);
397 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398 switch (GST_EVENT_TYPE (event)) {
399 case GST_EVENT_SEGMENT:{
400 const GstSegment *segment;
402 gst_event_parse_segment (event, &segment);
404 if (segment->format == GST_FORMAT_BYTES) {
405 if (demux->packet_size && segment->start > demux->data_offset)
406 demux->packet = (segment->start - demux->data_offset) /
410 } else if (segment->format == GST_FORMAT_TIME) {
411 /* do not know packet position, not really a problem */
414 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415 gst_event_unref (event);
419 /* record upstream segment for interpolation */
420 if (segment->format != demux->in_segment.format)
421 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422 gst_segment_copy_into (segment, &demux->in_segment);
424 /* in either case, clear some state and generate newsegment later on */
425 GST_OBJECT_LOCK (demux);
426 demux->segment_ts = GST_CLOCK_TIME_NONE;
427 demux->in_gap = GST_CLOCK_TIME_NONE;
428 demux->need_newsegment = TRUE;
429 demux->segment_seqnum = gst_event_get_seqnum (event);
430 gst_asf_demux_reset_stream_state_after_discont (demux);
431 /* if we seek back after reaching EOS, go back to packet reading state */
432 if (demux->data_offset > 0 && segment->start >= demux->data_offset
433 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
434 demux->state = GST_ASF_DEMUX_STATE_DATA;
436 GST_OBJECT_UNLOCK (demux);
438 gst_event_unref (event);
444 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
446 (_("This stream contains no data.")),
447 ("got eos and didn't receive a complete header object"));
450 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
451 if (!demux->activated_streams) {
452 /* If we still haven't got activated streams, the file is most likely corrupt */
453 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
454 (_("This stream contains no data.")),
455 ("got eos and didn't receive a complete header object"));
458 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
459 GST_ELEMENT_FLOW_ERROR (demux, flow);
463 GST_OBJECT_LOCK (demux);
464 gst_adapter_clear (demux->adapter);
465 GST_OBJECT_UNLOCK (demux);
466 gst_asf_demux_send_event_unlocked (demux, event);
470 case GST_EVENT_FLUSH_STOP:
471 GST_OBJECT_LOCK (demux);
472 gst_asf_demux_reset_stream_state_after_discont (demux);
473 GST_OBJECT_UNLOCK (demux);
474 gst_asf_demux_send_event_unlocked (demux, event);
475 /* upon activation, latency is no longer introduced, e.g. after seek */
476 if (demux->activated_streams)
481 ret = gst_pad_event_default (pad, parent, event);
489 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
490 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
491 gboolean next, gboolean * eos)
493 GstClockTime idx_time;
499 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
502 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
505 /* if we want the next keyframe, we have to go forward till we find
506 a different packet number */
508 if (idx >= demux->sidx_num_entries - 1) {
509 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
514 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
515 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
522 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
528 *packet = demux->sidx_entries[idx].packet;
530 *speed = demux->sidx_entries[idx].count;
532 /* so we get closer to the actual time of the packet ... actually, let's not
533 * do this, since we throw away superfluous payloads before the seek position
534 * anyway; this way, our key unit seek 'snap resolution' is a bit better
535 * (ie. same as index resolution) */
537 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
541 idx_time = demux->sidx_interval * idx;
542 if (G_LIKELY (idx_time >= demux->preroll))
543 idx_time -= demux->preroll;
545 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
546 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
547 GST_TIME_ARGS (idx_time));
549 if (G_LIKELY (p_idx_time))
550 *p_idx_time = idx_time;
556 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
560 gst_adapter_clear (demux->adapter);
562 GST_DEBUG_OBJECT (demux, "reset stream state");
564 gst_flow_combiner_reset (demux->flowcombiner);
565 for (n = 0; n < demux->num_streams; n++) {
566 demux->stream[n].discont = TRUE;
567 demux->stream[n].first_buffer = TRUE;
569 while (demux->stream[n].payloads->len > 0) {
573 last = demux->stream[n].payloads->len - 1;
574 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
575 gst_buffer_replace (&payload->buf, NULL);
576 g_array_remove_index (demux->stream[n].payloads, last);
582 gst_asf_demux_mark_discont (GstASFDemux * demux)
586 GST_DEBUG_OBJECT (demux, "Mark stream discont");
588 for (n = 0; n < demux->num_streams; n++)
589 demux->stream[n].discont = TRUE;
592 /* do a seek in push based mode */
594 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
599 GstSeekType cur_type, stop_type;
603 GstEvent *byte_event;
605 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
608 stop_type = GST_SEEK_TYPE_NONE;
611 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
613 /* determine packet, by index or by estimation */
614 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
617 (guint) gst_util_uint64_scale (demux->num_packets, cur,
621 if (packet > demux->num_packets) {
622 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
627 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
629 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
631 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
632 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
633 /* BYTE seek event */
634 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
635 cur, stop_type, stop);
636 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
637 res = gst_pad_push_event (demux->sinkpad, byte_event);
643 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
645 GstClockTime idx_time;
648 GstSeekType cur_type, stop_type;
650 gboolean only_need_update;
651 gboolean after, before, next;
656 guint packet, speed_count = 1;
662 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
665 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
666 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
670 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
671 * so first try to let it handle the seek event. */
672 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
675 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
676 demux->num_packets == 0 || demux->play_time == 0)) {
677 GST_LOG_OBJECT (demux, "stream is not seekable");
681 if (G_UNLIKELY (!demux->activated_streams)) {
682 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
686 if (G_UNLIKELY (rate <= 0.0)) {
687 GST_LOG_OBJECT (demux, "backward playback");
688 demux->seek_to_cur_pos = TRUE;
689 for (i = 0; i < demux->num_streams; i++) {
690 demux->stream[i].reverse_kf_ready = FALSE;
694 seqnum = gst_event_get_seqnum (event);
695 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
697 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
698 demux->keyunit_sync =
699 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
700 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
701 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
702 next = after && !before;
704 if (G_UNLIKELY (demux->streaming)) {
705 /* support it safely needs more segment handling, e.g. closing etc */
707 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
710 /* we can (re)construct the start later on, but not the end */
711 if (stop_type != GST_SEEK_TYPE_NONE &&
712 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
713 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
716 return gst_asf_demux_handle_seek_push (demux, event);
719 /* unlock the streaming thread */
720 if (G_LIKELY (flush)) {
721 fevent = gst_event_new_flush_start ();
723 gst_event_set_seqnum (fevent, seqnum);
724 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
725 gst_asf_demux_send_event_unlocked (demux, fevent);
727 gst_pad_pause_task (demux->sinkpad);
730 /* grab the stream lock so that streaming cannot continue, for
731 * non flushing seeks when the element is in PAUSED this could block
733 GST_PAD_STREAM_LOCK (demux->sinkpad);
735 /* we now can stop flushing, since we have the stream lock now */
736 fevent = gst_event_new_flush_stop (TRUE);
737 gst_event_set_seqnum (fevent, seqnum);
738 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
740 if (G_LIKELY (flush))
741 gst_asf_demux_send_event_unlocked (demux, fevent);
743 gst_event_unref (fevent);
745 /* operating on copy of segment until we know the seek worked */
746 segment = demux->segment;
748 if (G_UNLIKELY (demux->segment_running && !flush)) {
749 GstSegment newsegment;
752 /* create the segment event to close the current segment */
753 gst_segment_copy_into (&segment, &newsegment);
754 newseg = gst_event_new_segment (&newsegment);
755 gst_event_set_seqnum (newseg, seqnum);
757 gst_asf_demux_send_event_unlocked (demux, newseg);
760 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
761 cur, stop_type, stop, &only_need_update);
763 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
764 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
766 if (cur_type != GST_SEEK_TYPE_SET)
767 seek_time = segment.start;
771 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
772 * real start of data and segment_start to indexed time for key unit seek*/
773 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
774 &idx_time, &speed_count, next, &eos))) {
778 demux->packet = demux->num_packets;
782 /* First try to query our source to see if it can convert for us. This is
783 the case when our source is an mms stream, notice that in this case
784 gstmms will do a time based seek to get the byte offset, this is not a
785 problem as the seek to this offset needs to happen anway. */
786 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
787 GST_FORMAT_BYTES, &offset)) {
788 packet = (offset - demux->data_offset) / demux->packet_size;
789 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
790 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
791 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
792 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
793 demux->packet_size, packet);
795 /* FIXME: For streams containing video, seek to an earlier position in
796 * the hope of hitting a keyframe and let the sinks throw away the stuff
797 * before the segment start. For audio-only this is unnecessary as every
799 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
800 && demux->num_video_streams > 0) {
801 seek_time -= 5 * GST_SECOND;
806 packet = (guint) gst_util_uint64_scale (demux->num_packets,
807 seek_time, demux->play_time);
809 if (packet > demux->num_packets)
810 packet = demux->num_packets;
813 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
814 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
815 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
816 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
817 segment.start = idx_time;
818 segment.position = idx_time;
819 segment.time = idx_time;
823 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
825 GST_OBJECT_LOCK (demux);
826 demux->segment = segment;
827 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
828 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
829 stop, demux->play_time);
831 demux->packet = packet;
834 demux->need_newsegment = TRUE;
835 demux->segment_seqnum = seqnum;
836 demux->speed_packets =
837 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
838 gst_asf_demux_reset_stream_state_after_discont (demux);
839 GST_OBJECT_UNLOCK (demux);
842 /* restart our task since it might have been stopped when we did the flush */
843 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
846 /* streaming can continue now */
847 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
853 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 ret = gst_asf_demux_handle_seek_event (demux, event);
865 gst_event_unref (event);
868 case GST_EVENT_NAVIGATION:
869 /* just drop these two silently */
870 gst_event_unref (event);
874 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
875 ret = gst_pad_event_default (pad, parent, event);
882 static inline guint32
883 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
887 ret = gst_asf_identify_guid (guids, guid);
889 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
890 gst_asf_get_guid_nick (guids, ret),
891 guid->v1, guid->v2, guid->v3, guid->v4);
903 /* Peek for an object.
905 * Returns FALSE is the object is corrupted (such as the reported
906 * object size being greater than 2**32bits.
909 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
910 guint data_len, AsfObject * object, gboolean expect)
914 /* Callers should have made sure that data_len is big enough */
915 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
917 if (data_len < ASF_OBJECT_HEADER_SIZE)
920 guid.v1 = GST_READ_UINT32_LE (data + 0);
921 guid.v2 = GST_READ_UINT32_LE (data + 4);
922 guid.v3 = GST_READ_UINT32_LE (data + 8);
923 guid.v4 = GST_READ_UINT32_LE (data + 12);
925 /* FIXME: make asf_demux_identify_object_guid() */
926 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
927 if (object->id == ASF_OBJ_UNDEFINED && expect) {
928 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
929 guid.v1, guid.v2, guid.v3, guid.v4);
932 object->size = GST_READ_UINT64_LE (data + 16);
933 if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
934 GST_WARNING_OBJECT (demux,
935 "ASF Object size corrupted (greater than 32bit)");
944 gst_asf_demux_release_old_pads (GstASFDemux * demux)
946 GST_DEBUG_OBJECT (demux, "Releasing old pads");
948 while (demux->old_num_streams > 0) {
949 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
950 gst_event_new_eos ());
951 gst_asf_demux_free_stream (demux,
952 &demux->old_stream[demux->old_num_streams - 1]);
953 --demux->old_num_streams;
955 memset (demux->old_stream, 0, sizeof (demux->old_stream));
956 demux->old_num_streams = 0;
960 gst_asf_demux_chain_headers (GstASFDemux * demux)
963 guint8 *header_data, *data = NULL;
964 const guint8 *cdata = NULL;
966 GstFlowReturn flow = GST_FLOW_OK;
968 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
972 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
974 if (obj.id != ASF_OBJ_HEADER)
977 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
979 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
980 if (gst_adapter_available (demux->adapter) < obj.size + 50)
983 data = gst_adapter_take (demux->adapter, obj.size + 50);
986 header_size = obj.size;
987 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
988 if (flow != GST_FLOW_OK)
991 /* calculate where the packet data starts */
992 demux->data_offset = obj.size + 50;
994 /* now parse the beginning of the ASF_OBJ_DATA object */
995 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
998 if (demux->num_streams == 0)
1007 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1014 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1015 ("This doesn't seem to be an ASF file"));
1017 return GST_FLOW_ERROR;
1022 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1023 ("header parsing failed, or no streams found, flow = %s",
1024 gst_flow_get_name (flow)));
1026 return GST_FLOW_ERROR;
1031 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1032 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1037 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1040 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1042 if (G_LIKELY (p_flow))
1045 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1046 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1047 "+%u", gst_flow_get_name (flow), offset, size);
1052 g_assert (*p_buf != NULL);
1054 buffer_size = gst_buffer_get_size (*p_buf);
1055 if (G_UNLIKELY (buffer_size < size)) {
1056 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1057 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1058 gst_buffer_unref (*p_buf);
1059 if (G_LIKELY (p_flow))
1060 *p_flow = GST_FLOW_EOS;
1068 static GstFlowReturn
1069 gst_asf_demux_pull_indices (GstASFDemux * demux)
1071 GstBuffer *buf = NULL;
1074 GstFlowReturn ret = GST_FLOW_OK;
1076 offset = demux->index_offset;
1078 if (G_UNLIKELY (offset == 0)) {
1079 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1084 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1090 gst_buffer_map (buf, &map, GST_MAP_READ);
1091 g_assert (map.size >= 16 + 8);
1092 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1093 GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
1094 GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
1096 gst_buffer_unmap (buf, &map);
1097 gst_buffer_replace (&buf, NULL);
1098 /* Non-fatal, return */
1101 gst_buffer_unmap (buf, &map);
1102 gst_buffer_replace (&buf, NULL);
1104 /* check for sanity */
1105 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1106 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1110 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1114 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1115 ", size %u", offset, (guint) obj.size);
1117 offset += obj.size; /* increase before _process_object changes it */
1119 gst_buffer_map (buf, &map, GST_MAP_READ);
1120 g_assert (map.size >= obj.size);
1121 bufdata = (guint8 *) map.data;
1122 obj_size = obj.size;
1123 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1124 gst_buffer_unmap (buf, &map);
1125 gst_buffer_replace (&buf, NULL);
1127 if (ret == ASF_FLOW_NEED_MORE_DATA) {
1128 /* Since indices are at the end of the file, if we need more data,
1129 * we consider it as a non-fatal corrupted index */
1134 if (G_UNLIKELY (ret != GST_FLOW_OK))
1140 GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
1141 gst_flow_get_name (ret));
1146 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1150 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1151 GST_WARNING_OBJECT (demux, "Corrupted data");
1154 if (obj.id != ASF_OBJ_DATA) {
1155 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1159 demux->state = GST_ASF_DEMUX_STATE_DATA;
1161 if (!demux->broadcast && obj.size > 50) {
1162 demux->data_size = obj.size - 50;
1163 /* CHECKME: for at least one file this is off by +158 bytes?! */
1164 demux->index_offset = demux->data_offset + demux->data_size;
1166 demux->data_size = 0;
1167 demux->index_offset = 0;
1172 if (!demux->broadcast) {
1173 /* skip object header (24 bytes) and file GUID (16 bytes) */
1174 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1176 demux->num_packets = 0;
1179 if (demux->num_packets == 0)
1180 demux->seekable = FALSE;
1182 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1183 if (demux->data_size == 0 && demux->num_packets > 0) {
1184 demux->data_size = demux->num_packets * demux->packet_size;
1185 demux->index_offset = demux->data_offset + demux->data_size;
1188 /* process pending stream objects and create pads for those */
1189 gst_asf_demux_process_queued_extended_stream_objects (demux);
1191 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1192 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1193 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1194 demux->data_offset, demux->data_size, demux->index_offset);
1200 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1202 GstFlowReturn flow = GST_FLOW_OK;
1204 GstBuffer *buf = NULL;
1209 GST_LOG_OBJECT (demux, "reading headers");
1211 /* pull HEADER object header, so we know its size */
1212 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1215 gst_buffer_map (buf, &map, GST_MAP_READ);
1216 g_assert (map.size >= 16 + 8);
1217 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1218 gst_buffer_unmap (buf, &map);
1219 gst_buffer_replace (&buf, NULL);
1220 flow = GST_FLOW_ERROR;
1223 gst_buffer_unmap (buf, &map);
1224 gst_buffer_replace (&buf, NULL);
1226 if (obj.id != ASF_OBJ_HEADER)
1229 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1231 /* pull HEADER object */
1232 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1236 size = obj.size; /* don't want obj.size changed */
1237 gst_buffer_map (buf, &map, GST_MAP_READ);
1238 g_assert (map.size >= size);
1239 bufdata = (guint8 *) map.data;
1240 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1241 gst_buffer_unmap (buf, &map);
1242 gst_buffer_replace (&buf, NULL);
1244 if (flow != GST_FLOW_OK) {
1245 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1249 /* calculate where the packet data starts */
1250 demux->data_offset = demux->base_offset + obj.size + 50;
1252 /* now pull beginning of DATA object before packet data */
1253 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1257 gst_buffer_map (buf, &map, GST_MAP_READ);
1258 g_assert (map.size >= size);
1259 bufdata = (guint8 *) map.data;
1260 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1263 if (demux->num_streams == 0)
1266 gst_buffer_unmap (buf, &map);
1267 gst_buffer_replace (&buf, NULL);
1275 gst_buffer_unmap (buf, &map);
1276 gst_buffer_replace (&buf, NULL);
1278 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1279 ("This doesn't seem to be an ASF file"));
1280 *pflow = GST_FLOW_ERROR;
1285 flow = GST_FLOW_ERROR;
1286 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1287 ("header parsing failed, or no streams found, flow = %s",
1288 gst_flow_get_name (flow)));
1293 gst_buffer_unmap (buf, &map);
1294 gst_buffer_replace (&buf, NULL);
1295 if (flow == ASF_FLOW_NEED_MORE_DATA)
1296 flow = GST_FLOW_ERROR;
1303 all_streams_prerolled (GstASFDemux * demux)
1305 GstClockTime preroll_time;
1306 guint i, num_no_data = 0;
1308 /* Allow at least 500ms of preroll_time */
1309 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1311 /* returns TRUE as long as there isn't a stream which (a) has data queued
1312 * and (b) the timestamp of last piece of data queued is < demux->preroll
1313 * AND there is at least one other stream with data queued */
1314 for (i = 0; i < demux->num_streams; ++i) {
1315 AsfPayload *last_payload = NULL;
1319 stream = &demux->stream[i];
1320 if (G_UNLIKELY (stream->payloads->len == 0)) {
1322 GST_LOG_OBJECT (stream->pad, "no data queued");
1326 /* find last payload with timestamp */
1327 for (last_idx = stream->payloads->len - 1;
1328 last_idx >= 0 && (last_payload == NULL
1329 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1330 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1333 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1334 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1335 GST_TIME_ARGS (preroll_time));
1336 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1337 || last_payload->ts <= preroll_time)) {
1338 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1343 if (G_UNLIKELY (num_no_data > 0))
1351 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1356 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1359 /* check for each mutual exclusion group whether it affects this stream */
1360 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1361 if (*mes == stream->id) {
1362 /* we are in this group; let's check if we've already activated streams
1363 * that are in the same group (and hence mutually exclusive to this
1365 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1368 for (i = 0; i < demux->num_streams; ++i) {
1369 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1370 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1371 "to already active stream with ID %d", stream->id,
1372 demux->stream[i].id);
1377 /* we can only be in this group once, let's break out and move on to
1378 * the next mutual exclusion group */
1389 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1391 /* remember the first queued timestamp for the segment */
1392 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1393 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1394 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1395 GST_TIME_ARGS (demux->first_ts));
1396 demux->segment_ts = payload_ts;
1397 /* always note, but only determines segment when streaming */
1398 if (demux->streaming)
1399 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1400 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1401 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1406 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1408 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1409 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1412 /* go trhough each stream, find smallest timestamp */
1413 for (i = 0; i < demux->num_streams; ++i) {
1416 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1417 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1418 stream = &demux->stream[i];
1420 for (j = 0; j < stream->payloads->len; ++j) {
1421 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1422 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1423 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1424 || stream_min_ts > payload->ts)) {
1425 stream_min_ts = payload->ts;
1427 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1428 payload->ts > stream_min_ts &&
1429 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1430 || stream_min_ts2 > payload->ts)) {
1431 stream_min_ts2 = payload->ts;
1435 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1436 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1437 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1438 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1439 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1441 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1444 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1445 stream_min_ts = stream_min_ts2;
1447 /* if we don't have timestamp for this stream, wait for more data */
1448 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1451 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1452 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1453 first_ts = stream_min_ts;
1456 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1459 demux->first_ts = first_ts;
1461 /* update packets queued before we knew first timestamp */
1462 for (i = 0; i < demux->num_streams; ++i) {
1465 stream = &demux->stream[i];
1467 for (j = 0; j < stream->payloads->len; ++j) {
1468 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1469 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1470 if (payload->ts > first_ts)
1471 payload->ts -= first_ts;
1479 gst_asf_demux_check_segment_ts (demux, 0);
1485 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1487 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1488 and often set wrong, inspecting the data is the only way that seem to be working */
1489 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1490 GstCaps *caps = NULL;
1492 GstAdapter *adapter = gst_adapter_new ();
1494 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1496 AsfPayload *payload;
1499 payload = &g_array_index (stream->payloads, AsfPayload, i);
1500 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1501 len = gst_adapter_available (adapter);
1502 data = gst_adapter_map (adapter, len);
1506 #define MIN_LENGTH 128
1508 /* look for the sync points */
1510 if (len < MIN_LENGTH || /* give typefind something to work on */
1511 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1512 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1518 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1521 if (prob < GST_TYPE_FIND_LIKELY) {
1524 if (len > MIN_LENGTH)
1525 /* this wasn't it, look for another sync point */
1529 gst_adapter_unmap (adapter);
1532 gst_object_unref (adapter);
1535 gst_caps_take (&stream->caps, caps);
1543 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1545 guint i, actual_streams = 0;
1547 if (demux->activated_streams)
1550 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1553 if (!all_streams_prerolled (demux) && !force) {
1554 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1558 for (i = 0; i < demux->num_streams; ++i) {
1559 AsfStream *stream = &demux->stream[i];
1561 if (stream->payloads->len > 0) {
1563 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1564 !stream->active && /* do not inspect active streams (caps were already set) */
1565 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1566 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1567 /* try to gather some more data */
1570 /* we don't check mutual exclusion stuff here; either we have data for
1571 * a stream, then we active it, or we don't, then we'll ignore it */
1572 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1573 gst_asf_demux_activate_stream (demux, stream);
1574 actual_streams += 1;
1576 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1580 if (actual_streams == 0) {
1581 /* We don't have any streams activated ! */
1582 GST_ERROR_OBJECT (demux, "No streams activated!");
1586 gst_asf_demux_release_old_pads (demux);
1588 demux->activated_streams = TRUE;
1589 GST_LOG_OBJECT (demux, "signalling no more pads");
1590 gst_element_no_more_pads (GST_ELEMENT (demux));
1594 /* returns the stream that has a complete payload with the lowest timestamp
1595 * queued, or NULL (we push things by timestamp because during the internal
1596 * prerolling we might accumulate more data then the external queues can take,
1597 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1599 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1601 AsfPayload *best_payload = NULL;
1602 AsfStream *best_stream = NULL;
1605 for (i = 0; i < demux->num_streams; ++i) {
1609 stream = &demux->stream[i];
1611 /* Don't push any data until we have at least one payload that falls within
1612 * the current segment. This way we can remove out-of-segment payloads that
1613 * don't need to be decoded after a seek, sending only data from the
1614 * keyframe directly before our segment start */
1615 if (stream->payloads->len > 0) {
1616 AsfPayload *payload = NULL;
1619 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1620 /* Reverse playback */
1622 if (stream->is_video) {
1623 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1624 if (stream->reverse_kf_ready) {
1626 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1627 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1628 /* TODO : remove payload from the list? */
1635 /* find first complete payload with timestamp */
1636 for (j = stream->payloads->len - 1;
1637 j >= 0 && (payload == NULL
1638 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1639 payload = &g_array_index (stream->payloads, AsfPayload, j);
1642 /* If there's a complete payload queued for this stream */
1643 if (!gst_asf_payload_is_complete (payload))
1649 /* find last payload with timestamp */
1650 for (last_idx = stream->payloads->len - 1;
1651 last_idx >= 0 && (payload == NULL
1652 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1653 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1656 /* if this is first payload after seek we might need to update the segment */
1657 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1658 gst_asf_demux_check_segment_ts (demux, payload->ts);
1660 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1661 (payload->ts < demux->segment.start))) {
1662 if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
1663 && payload->keyframe)) {
1664 GST_DEBUG_OBJECT (stream->pad,
1665 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1666 GST_TIME_ARGS (payload->ts));
1667 demux->segment.start = payload->ts;
1668 demux->segment.time = payload->ts;
1670 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1671 GST_TIME_FORMAT " which is before our segment start %"
1672 GST_TIME_FORMAT ", not pushing yet",
1673 GST_TIME_ARGS (payload->ts),
1674 GST_TIME_ARGS (demux->segment.start));
1679 /* find first complete payload with timestamp */
1681 j < stream->payloads->len && (payload == NULL
1682 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1683 payload = &g_array_index (stream->payloads, AsfPayload, j);
1686 /* Now see if there's a complete payload queued for this stream */
1687 if (!gst_asf_payload_is_complete (payload))
1691 /* ... and whether its timestamp is lower than the current best */
1692 if (best_stream == NULL || best_payload->ts > payload->ts) {
1693 best_stream = stream;
1694 best_payload = payload;
1702 static GstFlowReturn
1703 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1706 GstFlowReturn ret = GST_FLOW_OK;
1708 if (G_UNLIKELY (!demux->activated_streams)) {
1709 if (!gst_asf_demux_check_activate_streams (demux, force))
1711 /* streams are now activated */
1714 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1715 AsfPayload *payload;
1716 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1717 GstClockTime duration = GST_CLOCK_TIME_NONE;
1719 /* wait until we had a chance to "lock on" some payload's timestamp */
1720 if (G_UNLIKELY (demux->need_newsegment
1721 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1724 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1725 && stream->payloads->len) {
1726 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1728 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1731 /* do we need to send a newsegment event */
1732 if ((G_UNLIKELY (demux->need_newsegment))) {
1733 GstEvent *segment_event;
1735 /* safe default if insufficient upstream info */
1736 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1739 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1740 demux->segment.duration > 0) {
1741 /* slight HACK; prevent clipping of last bit */
1742 demux->segment.stop = demux->segment.duration + demux->in_gap;
1745 /* FIXME : only if ACCURATE ! */
1746 if (G_LIKELY (demux->keyunit_sync && !demux->accurate
1747 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1748 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1749 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1750 GST_TIME_ARGS (payload->ts));
1751 demux->segment.start = payload->ts;
1752 demux->segment.time = payload->ts;
1755 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1758 /* note: we fix up all timestamps to start from 0, so this should be ok */
1759 segment_event = gst_event_new_segment (&demux->segment);
1760 if (demux->segment_seqnum)
1761 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1762 gst_asf_demux_send_event_unlocked (demux, segment_event);
1764 /* now post any global tags we may have found */
1765 if (demux->taglist == NULL) {
1766 demux->taglist = gst_tag_list_new_empty ();
1767 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1770 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1771 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1773 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1774 gst_asf_demux_send_event_unlocked (demux,
1775 gst_event_new_tag (demux->taglist));
1776 demux->taglist = NULL;
1778 demux->need_newsegment = FALSE;
1779 demux->segment_seqnum = 0;
1780 demux->segment_running = TRUE;
1783 /* Do we have tags pending for this stream? */
1784 if (G_UNLIKELY (stream->pending_tags)) {
1785 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1786 gst_pad_push_event (stream->pad,
1787 gst_event_new_tag (stream->pending_tags));
1788 stream->pending_tags = NULL;
1791 /* We have the whole packet now so we should push the packet to
1792 * the src pad now. First though we should check if we need to do
1794 if (G_UNLIKELY (stream->span > 1)) {
1795 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1798 payload->buf = gst_buffer_make_writable (payload->buf);
1800 if (G_LIKELY (!payload->keyframe)) {
1801 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1804 if (G_UNLIKELY (stream->discont)) {
1805 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1806 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1807 stream->discont = FALSE;
1810 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1811 (payload->par_x != stream->par_x) &&
1812 (payload->par_y != stream->par_y))) {
1813 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1814 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1815 stream->par_x = payload->par_x;
1816 stream->par_y = payload->par_y;
1817 stream->caps = gst_caps_make_writable (stream->caps);
1818 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1819 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1820 gst_pad_set_caps (stream->pad, stream->caps);
1823 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1824 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1825 payload->interlaced);
1826 stream->interlaced = payload->interlaced;
1827 stream->caps = gst_caps_make_writable (stream->caps);
1828 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1829 (stream->interlaced ? "mixed" : "progressive"), NULL);
1830 gst_pad_set_caps (stream->pad, stream->caps);
1833 /* (sort of) interpolate timestamps using upstream "frame of reference",
1834 * typically useful for live src, but might (unavoidably) mess with
1835 * position reporting if a live src is playing not so live content
1836 * (e.g. rtspsrc taking some time to fall back to tcp) */
1837 timestamp = payload->ts;
1838 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1839 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1840 timestamp += demux->in_gap;
1842 /* Check if we're after the segment already, if so no need to push
1844 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1845 GST_DEBUG_OBJECT (stream->pad,
1846 "Payload after segment stop %" GST_TIME_FORMAT,
1847 GST_TIME_ARGS (demux->segment.stop));
1849 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1851 gst_buffer_unref (payload->buf);
1852 payload->buf = NULL;
1853 g_array_remove_index (stream->payloads, 0);
1854 /* Break out as soon as we have an issue */
1855 if (G_UNLIKELY (ret != GST_FLOW_OK))
1862 GST_BUFFER_PTS (payload->buf) = timestamp;
1864 if (payload->duration == GST_CLOCK_TIME_NONE
1865 && stream->ext_props.avg_time_per_frame != 0) {
1866 duration = stream->ext_props.avg_time_per_frame * 100;
1868 duration = payload->duration;
1870 GST_BUFFER_DURATION (payload->buf) = duration;
1872 /* FIXME: we should really set durations on buffers if we can */
1874 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1877 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1878 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1879 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1881 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1882 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1886 if (stream->active) {
1887 if (G_UNLIKELY (stream->first_buffer)) {
1888 if (stream->streamheader != NULL) {
1889 GST_DEBUG_OBJECT (stream->pad,
1890 "Pushing streamheader before first buffer");
1891 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1893 stream->first_buffer = FALSE;
1896 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1897 && timestamp > demux->segment.position) {
1898 demux->segment.position = timestamp;
1899 if (GST_CLOCK_TIME_IS_VALID (duration))
1900 demux->segment.position += timestamp;
1903 ret = gst_pad_push (stream->pad, payload->buf);
1905 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1908 gst_buffer_unref (payload->buf);
1911 payload->buf = NULL;
1912 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1913 && stream->reverse_kf_ready) {
1914 g_array_remove_index (stream->payloads, stream->kf_pos);
1917 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1919 stream->reverse_kf_ready = FALSE;
1922 g_array_remove_index (stream->payloads, 0);
1925 /* Break out as soon as we have an issue */
1926 if (G_UNLIKELY (ret != GST_FLOW_OK))
1934 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1939 g_assert (buf != NULL);
1941 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1943 gst_buffer_map (buf, &map, GST_MAP_READ);
1945 /* we return false on buffer too small */
1946 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1947 gst_buffer_unmap (buf, &map);
1951 /* check if it is a header */
1953 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1955 gst_buffer_unmap (buf, &map);
1956 if (valid && obj.id == ASF_OBJ_HEADER) {
1963 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1965 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1966 GstFlowReturn ret = GST_FLOW_OK;
1967 GstBuffer *buf = NULL;
1968 gboolean header = FALSE;
1970 /* TODO maybe we should skip index objects after the data and look
1971 * further for a new header */
1972 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1973 g_assert (buf != NULL);
1974 /* check if it is a header */
1975 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1976 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1977 demux->base_offset = off;
1981 gst_buffer_unref (buf);
1988 gst_asf_demux_loop (GstASFDemux * demux)
1990 GstFlowReturn flow = GST_FLOW_OK;
1991 GstBuffer *buf = NULL;
1994 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1995 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1999 flow = gst_asf_demux_pull_indices (demux);
2000 if (flow != GST_FLOW_OK)
2004 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
2006 if (G_UNLIKELY (demux->num_packets != 0
2007 && demux->packet >= demux->num_packets))
2010 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2011 (guint) demux->num_packets);
2013 off = demux->data_offset + (demux->packet * demux->packet_size);
2015 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2016 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2017 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2018 if (flow == GST_FLOW_EOS) {
2020 } else if (flow == GST_FLOW_FLUSHING) {
2021 GST_DEBUG_OBJECT (demux, "Not fatal");
2028 if (G_LIKELY (demux->speed_packets == 1)) {
2029 GstAsfDemuxParsePacketError err;
2030 err = gst_asf_demux_parse_packet (demux, buf);
2031 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2032 /* when we don't know when the data object ends, we should check
2033 * for a chained asf */
2034 if (demux->num_packets == 0) {
2035 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2036 GST_INFO_OBJECT (demux, "Chained asf found");
2037 demux->base_offset = off;
2038 gst_asf_demux_reset (demux, TRUE);
2039 gst_buffer_unref (buf);
2043 /* FIXME: We should tally up fatal errors and error out only
2044 * after a few broken packets in a row? */
2046 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2047 gst_buffer_unref (buf);
2049 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2050 && !demux->seek_to_cur_pos) {
2052 if (demux->packet < 0) {
2062 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2064 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2065 && !demux->seek_to_cur_pos) {
2067 if (demux->packet < 0) {
2076 for (n = 0; n < demux->speed_packets; n++) {
2078 GstAsfDemuxParsePacketError err;
2081 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2082 n * demux->packet_size, demux->packet_size);
2083 err = gst_asf_demux_parse_packet (demux, sub);
2084 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2085 /* when we don't know when the data object ends, we should check
2086 * for a chained asf */
2087 if (demux->num_packets == 0) {
2088 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2089 GST_INFO_OBJECT (demux, "Chained asf found");
2090 demux->base_offset = off + n * demux->packet_size;
2091 gst_asf_demux_reset (demux, TRUE);
2092 gst_buffer_unref (sub);
2093 gst_buffer_unref (buf);
2097 /* FIXME: We should tally up fatal errors and error out only
2098 * after a few broken packets in a row? */
2100 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2104 gst_buffer_unref (sub);
2106 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2107 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2113 /* reset speed pull */
2114 demux->speed_packets = 1;
2117 gst_buffer_unref (buf);
2119 if (G_UNLIKELY ((demux->num_packets > 0
2120 && demux->packet >= demux->num_packets)
2121 || flow == GST_FLOW_EOS)) {
2122 GST_LOG_OBJECT (demux, "reached EOS");
2126 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2127 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2131 /* check if we're at the end of the configured segment */
2132 /* FIXME: check if segment end reached etc. */
2138 /* if we haven't activated our streams yet, this might be because we have
2139 * less data queued than required for preroll; force stream activation and
2140 * send any pending payloads before sending EOS */
2141 if (!demux->activated_streams)
2142 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2144 /* we want to push an eos or post a segment-done in any case */
2145 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2148 /* for segment playback we need to post when (in stream time)
2149 * we stopped, this is either stop (when set) or the duration. */
2150 if ((stop = demux->segment.stop) == -1)
2151 stop = demux->segment.duration;
2153 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2154 gst_element_post_message (GST_ELEMENT_CAST (demux),
2155 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2157 gst_asf_demux_send_event_unlocked (demux,
2158 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2159 } else if (flow != GST_FLOW_EOS) {
2160 /* check if we have a chained asf, in case, we don't eos yet */
2161 if (gst_asf_demux_check_chained_asf (demux)) {
2162 GST_INFO_OBJECT (demux, "Chained ASF starting");
2163 gst_asf_demux_reset (demux, TRUE);
2168 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2169 if (demux->activated_streams) {
2170 /* normal playback, send EOS to all linked pads */
2171 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2172 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2174 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2175 flow = GST_FLOW_EOS;
2178 /* ... and fall through to pause */
2182 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2183 gst_flow_get_name (flow));
2184 demux->segment_running = FALSE;
2185 gst_pad_pause_task (demux->sinkpad);
2187 /* For the error cases */
2188 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2189 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2190 ("This doesn't seem to be an ASF file"));
2191 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2192 /* Post an error. Hopefully something else already has, but if not... */
2193 GST_ELEMENT_FLOW_ERROR (demux, flow);
2194 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2203 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2204 flow = GST_FLOW_EOS;
2208 /* See FIXMEs above */
2211 gst_buffer_unref (buf);
2212 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2213 ("Error parsing ASF packet %u", (guint) demux->packet));
2214 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2215 flow = GST_FLOW_ERROR;
2221 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2222 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2223 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2226 gst_asf_demux_check_header (GstASFDemux * demux)
2229 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2230 ASF_OBJECT_HEADER_SIZE);
2231 if (cdata == NULL) /* need more data */
2232 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2234 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
2235 && obj.id == ASF_OBJ_HEADER) {
2236 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2239 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2242 static GstFlowReturn
2243 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2245 GstFlowReturn ret = GST_FLOW_OK;
2248 demux = GST_ASF_DEMUX (parent);
2250 GST_LOG_OBJECT (demux,
2251 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2252 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2253 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2255 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2256 GST_DEBUG_OBJECT (demux, "received DISCONT");
2257 gst_asf_demux_mark_discont (demux);
2260 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2261 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2262 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2263 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2264 ", interpolation gap: %" GST_TIME_FORMAT,
2265 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2268 gst_adapter_push (demux->adapter, buf);
2270 switch (demux->state) {
2271 case GST_ASF_DEMUX_STATE_INDEX:{
2272 gint result = gst_asf_demux_check_header (demux);
2273 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2276 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2277 /* we don't care about this, probably an index */
2278 /* TODO maybe would be smarter to skip all the indices
2279 * until we got a new header or EOS to decide */
2280 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2283 GST_INFO_OBJECT (demux, "Chained asf starting");
2284 /* cleanup and get ready for a chained asf */
2285 gst_asf_demux_reset (demux, TRUE);
2289 case GST_ASF_DEMUX_STATE_HEADER:{
2290 ret = gst_asf_demux_chain_headers (demux);
2291 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2293 /* otherwise fall through */
2295 case GST_ASF_DEMUX_STATE_DATA:
2299 data_size = demux->packet_size;
2301 while (gst_adapter_available (demux->adapter) >= data_size) {
2303 GstAsfDemuxParsePacketError err;
2305 /* we don't know the length of the stream
2306 * check for a chained asf everytime */
2307 if (demux->num_packets == 0) {
2308 gint result = gst_asf_demux_check_header (demux);
2310 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2311 GST_INFO_OBJECT (demux, "Chained asf starting");
2312 /* cleanup and get ready for a chained asf */
2313 gst_asf_demux_reset (demux, TRUE);
2316 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2317 && demux->packet >= demux->num_packets)) {
2318 /* do not overshoot data section when streaming */
2322 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2324 /* FIXME: We should tally up fatal errors and error out only
2325 * after a few broken packets in a row? */
2326 err = gst_asf_demux_parse_packet (demux, buf);
2328 gst_buffer_unref (buf);
2330 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2331 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2333 GST_WARNING_OBJECT (demux, "Parse error");
2335 if (demux->packet >= 0)
2338 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2339 && demux->packet >= demux->num_packets)) {
2340 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2345 g_assert_not_reached ();
2349 if (ret != GST_FLOW_OK)
2350 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2356 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2362 static inline gboolean
2363 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2365 if (*p_size < num_bytes)
2368 *p_data += num_bytes;
2369 *p_size -= num_bytes;
2373 static inline guint8
2374 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2378 g_assert (*p_size >= 1);
2379 ret = GST_READ_UINT8 (*p_data);
2380 *p_data += sizeof (guint8);
2381 *p_size -= sizeof (guint8);
2385 static inline guint16
2386 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2390 g_assert (*p_size >= 2);
2391 ret = GST_READ_UINT16_LE (*p_data);
2392 *p_data += sizeof (guint16);
2393 *p_size -= sizeof (guint16);
2397 static inline guint32
2398 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2402 g_assert (*p_size >= 4);
2403 ret = GST_READ_UINT32_LE (*p_data);
2404 *p_data += sizeof (guint32);
2405 *p_size -= sizeof (guint32);
2409 static inline guint64
2410 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2414 g_assert (*p_size >= 8);
2415 ret = GST_READ_UINT64_LE (*p_data);
2416 *p_data += sizeof (guint64);
2417 *p_size -= sizeof (guint64);
2422 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2423 guint8 ** p_data, guint64 * p_size)
2427 if (*p_size < num_bytes_to_read)
2430 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2431 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2433 *p_data += num_bytes_to_read;
2434 *p_size -= num_bytes_to_read;
2440 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2441 guint8 ** p_data, guint64 * p_size)
2445 if (*p_size < num_bytes_to_read)
2448 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2449 *p_data += num_bytes_to_read;
2450 *p_size -= num_bytes_to_read;
2455 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2456 guint8 ** p_data, guint64 * p_size)
2466 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2469 *p_strlen = s_length;
2471 if (s_length == 0) {
2472 GST_WARNING ("zero-length string");
2473 *p_str = g_strdup ("");
2477 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2480 g_assert (s != NULL);
2482 /* just because They don't exist doesn't
2483 * mean They are not out to get you ... */
2484 if (s[s_length - 1] != '\0') {
2485 s = g_realloc (s, s_length + 1);
2489 *p_str = (gchar *) s;
2495 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2497 g_assert (*p_size >= 4 * sizeof (guint32));
2499 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2500 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2501 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2502 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2506 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2509 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2512 /* WAVEFORMATEX Structure */
2513 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2514 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2515 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2516 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2517 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2518 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2519 /* Codec specific data size */
2520 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2521 if (audio->size > *p_size) {
2522 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2523 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2530 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2533 if (*p_size < (4 + 4 + 1 + 2))
2536 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2537 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2538 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2539 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2544 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2545 guint8 ** p_data, guint64 * p_size)
2547 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2550 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2552 if (fmt->size < 40) {
2553 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2556 if ((guint64) fmt->size - 4 > *p_size) {
2557 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2560 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2561 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2562 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2563 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2564 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2565 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2566 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2567 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2568 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2569 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2574 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2578 for (i = 0; i < demux->num_streams; i++) {
2579 if (demux->stream[i].id == id)
2580 return &demux->stream[i];
2583 if (gst_asf_demux_is_unknown_stream (demux, id))
2584 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2589 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2590 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2595 gst_pad_use_fixed_caps (src_pad);
2596 gst_pad_set_caps (src_pad, caps);
2598 gst_pad_set_event_function (src_pad,
2599 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2600 gst_pad_set_query_function (src_pad,
2601 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2603 stream = &demux->stream[demux->num_streams];
2604 stream->caps = caps;
2605 stream->pad = src_pad;
2607 stream->fps_known = !is_video; /* bit hacky for audio */
2608 stream->is_video = is_video;
2609 stream->pending_tags = tags;
2610 stream->discont = TRUE;
2611 stream->first_buffer = TRUE;
2612 stream->streamheader = streamheader;
2613 if (stream->streamheader) {
2614 stream->streamheader = gst_buffer_make_writable (streamheader);
2615 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2620 st = gst_caps_get_structure (caps, 0);
2621 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2622 par_x > 0 && par_y > 0) {
2623 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2624 stream->par_x = par_x;
2625 stream->par_y = par_y;
2629 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2631 /* TODO: create this array during reverse play? */
2632 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2634 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2635 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2637 ++demux->num_streams;
2639 stream->active = FALSE;
2645 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2646 GstBuffer * buffer, GstStructure * structure)
2648 GValue arr_val = G_VALUE_INIT;
2649 GValue buf_val = G_VALUE_INIT;
2651 g_value_init (&arr_val, GST_TYPE_ARRAY);
2652 g_value_init (&buf_val, GST_TYPE_BUFFER);
2654 gst_value_set_buffer (&buf_val, buffer);
2655 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2657 gst_structure_take_value (structure, "streamheader", &arr_val);
2661 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2662 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2664 GstTagList *tags = NULL;
2665 GstBuffer *extradata = NULL;
2668 guint16 size_left = 0;
2669 gchar *codec_name = NULL;
2672 size_left = audio->size;
2674 /* Create the audio pad */
2675 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2677 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2680 /* Swallow up any left over data and set up the
2681 * standard properties from the header info */
2683 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2684 "codec specific data", size_left);
2686 g_assert (size_left <= *p_size);
2687 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2690 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2691 * additional two bytes indicating extradata. */
2692 /* FIXME: Handle the channel reorder map here */
2693 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2694 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2697 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2698 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2701 /* Informing about that audio format we just added */
2703 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2704 g_free (codec_name);
2707 if (audio->byte_rate > 0) {
2708 /* Some ASF files have no bitrate props object (often seen with
2709 * ASF files that contain raw audio data). Example files can
2710 * be generated with FFmpeg (tested with v2.8.6), like this:
2712 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2714 * In this case, if audio->byte_rate is nonzero, use that as
2717 guint bitrate = audio->byte_rate * 8;
2720 tags = gst_tag_list_new_empty ();
2722 /* Add bitrate, but only if there is none set already, since
2723 * this is just a fallback in case there is no bitrate tag
2724 * already present */
2725 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2729 gst_buffer_unref (extradata);
2731 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2732 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2733 audio->codec_tag, tags);
2735 ++demux->num_audio_streams;
2737 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2741 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2742 asf_stream_video_format * video, guint16 id,
2743 guint8 ** p_data, guint64 * p_size)
2745 GstTagList *tags = NULL;
2746 GstStructure *caps_s;
2747 GstBuffer *extradata = NULL;
2752 gchar *codec_name = NULL;
2753 guint64 size_left = video->size - 40;
2754 GstBuffer *streamheader = NULL;
2755 guint par_w = 1, par_h = 1;
2757 /* Create the video pad */
2758 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2759 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2762 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2764 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2765 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2767 g_assert (size_left <= *p_size);
2768 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2771 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2773 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2774 caps = gst_riff_create_video_caps (video->tag, NULL,
2775 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2778 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2779 G_TYPE_UINT, video->tag, NULL);
2784 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2785 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2786 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2789 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2793 /* retry with the global metadata */
2794 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2795 demux->global_metadata);
2796 s = demux->global_metadata;
2797 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2798 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2799 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2800 if (ax > 0 && ay > 0) {
2803 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2808 s = gst_caps_get_structure (caps, 0);
2809 gst_structure_remove_field (s, "framerate");
2812 caps_s = gst_caps_get_structure (caps, 0);
2814 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2815 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2816 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2817 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2820 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2821 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2822 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2824 GstBuffer *buf = gst_value_get_buffer (value);
2827 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2828 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2829 /* this looks like a bytestream start */
2830 streamheader = gst_buffer_ref (buf);
2831 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2832 gst_structure_remove_field (caps_s, "codec_data");
2835 gst_buffer_unmap (buf, &mapinfo);
2840 /* For a 3D video, set multiview information into the caps based on
2841 * what was detected during object parsing */
2842 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2843 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2844 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2845 const gchar *mview_mode_str;
2847 switch (demux->asf_3D_mode) {
2848 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2849 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2851 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2852 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2853 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2855 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2856 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2858 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2859 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2860 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2862 case GST_ASF_3D_DUAL_STREAM:{
2863 gboolean is_right_view = FALSE;
2864 /* if Advanced_Mutual_Exclusion object exists, use it
2865 * to figure out which is the left view (lower ID) */
2866 if (demux->mut_ex_streams != NULL) {
2870 length = g_slist_length (demux->mut_ex_streams);
2872 for (i = 0; i < length; i++) {
2875 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2877 GST_DEBUG_OBJECT (demux,
2878 "has Mutual_Exclusion object. stream id in object is %d",
2879 GPOINTER_TO_INT (v_s_id));
2881 if (id > GPOINTER_TO_INT (v_s_id))
2882 is_right_view = TRUE;
2885 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2886 * first video stream encountered has the lower ID */
2887 if (demux->num_video_streams > 0) {
2888 /* This is not the first video stream, assuming right eye view */
2889 is_right_view = TRUE;
2893 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2895 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2902 GST_INFO_OBJECT (demux,
2903 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2906 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2907 if (mview_mode_str != NULL) {
2908 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2909 video->height, par_w, par_h))
2910 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2912 gst_caps_set_simple (caps,
2913 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2914 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2915 GST_FLAG_SET_MASK_EXACT, NULL);
2920 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2921 g_free (codec_name);
2925 gst_buffer_unref (extradata);
2927 GST_INFO ("Adding video stream #%u, id %u, codec %"
2928 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2929 GST_FOURCC_ARGS (video->tag), video->tag);
2931 ++demux->num_video_streams;
2933 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2934 streamheader, tags);
2938 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2940 if (!stream->active) {
2944 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2945 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2946 gst_pad_set_active (stream->pad, TRUE);
2949 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2950 "%03u", stream->id);
2953 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2955 if (gst_event_parse_group_id (event, &demux->group_id))
2956 demux->have_group_id = TRUE;
2958 demux->have_group_id = FALSE;
2959 gst_event_unref (event);
2960 } else if (!demux->have_group_id) {
2961 demux->have_group_id = TRUE;
2962 demux->group_id = gst_util_group_id_next ();
2965 event = gst_event_new_stream_start (stream_id);
2966 if (demux->have_group_id)
2967 gst_event_set_group_id (event, demux->group_id);
2969 gst_pad_push_event (stream->pad, event);
2971 gst_pad_set_caps (stream->pad, stream->caps);
2973 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2974 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2975 stream->active = TRUE;
2980 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2983 AsfCorrectionType correction_type;
2984 AsfStreamType stream_type;
2985 GstClockTime time_offset;
2986 gboolean is_encrypted G_GNUC_UNUSED;
2990 guint stream_specific_size;
2991 guint type_specific_size G_GNUC_UNUSED;
2992 guint unknown G_GNUC_UNUSED;
2993 gboolean inspect_payload = FALSE;
2994 AsfStream *stream = NULL;
2996 /* Get the rest of the header's header */
2997 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2998 goto not_enough_data;
3000 gst_asf_demux_get_guid (&guid, &data, &size);
3001 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
3003 gst_asf_demux_get_guid (&guid, &data, &size);
3004 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
3006 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
3008 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3009 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3011 flags = gst_asf_demux_get_uint16 (&data, &size);
3012 stream_id = flags & 0x7f;
3013 is_encrypted = ! !(flags & 0x8000);
3014 unknown = gst_asf_demux_get_uint32 (&data, &size);
3016 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3017 stream_id, GST_TIME_ARGS (time_offset));
3019 /* dvr-ms has audio stream declared in stream specific data */
3020 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3021 AsfExtStreamType ext_stream_type;
3022 gst_asf_demux_get_guid (&guid, &data, &size);
3023 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3025 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3026 inspect_payload = TRUE;
3028 gst_asf_demux_get_guid (&guid, &data, &size);
3029 gst_asf_demux_get_uint32 (&data, &size);
3030 gst_asf_demux_get_uint32 (&data, &size);
3031 gst_asf_demux_get_uint32 (&data, &size);
3032 gst_asf_demux_get_guid (&guid, &data, &size);
3033 gst_asf_demux_get_uint32 (&data, &size);
3034 stream_type = ASF_STREAM_AUDIO;
3038 switch (stream_type) {
3039 case ASF_STREAM_AUDIO:{
3040 asf_stream_audio audio_object;
3042 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3043 goto not_enough_data;
3045 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3048 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3051 switch (correction_type) {
3052 case ASF_CORRECTION_ON:{
3053 guint span, packet_size, chunk_size, data_size, silence_data;
3055 GST_INFO ("Using error correction");
3057 if (size < (1 + 2 + 2 + 2 + 1))
3058 goto not_enough_data;
3060 span = gst_asf_demux_get_uint8 (&data, &size);
3061 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3062 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3063 data_size = gst_asf_demux_get_uint16 (&data, &size);
3064 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3066 stream->span = span;
3068 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3069 packet_size, chunk_size, data_size, span, silence_data);
3071 if (stream->span > 1) {
3072 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3073 /* Disable descrambling */
3076 /* FIXME: this else branch was added for
3077 * weird_al_yankovic - the saga begins.asf */
3078 stream->ds_packet_size = packet_size;
3079 stream->ds_chunk_size = chunk_size;
3082 /* Descambling is enabled */
3083 stream->ds_packet_size = packet_size;
3084 stream->ds_chunk_size = chunk_size;
3087 /* Now skip the rest of the silence data */
3089 gst_bytestream_flush (demux->bs, data_size - 1);
3091 /* FIXME: CHECKME. And why -1? */
3092 if (data_size > 1) {
3093 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3094 goto not_enough_data;
3100 case ASF_CORRECTION_OFF:{
3101 GST_INFO ("Error correction off");
3102 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3103 goto not_enough_data;
3107 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3108 ("Audio stream using unknown error correction"));
3115 case ASF_STREAM_VIDEO:{
3116 asf_stream_video_format video_format_object;
3117 asf_stream_video video_object;
3120 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3121 goto not_enough_data;
3123 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3125 GST_INFO ("object is a video stream with %u bytes of "
3126 "additional data", vsize);
3128 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3130 goto not_enough_data;
3133 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3134 stream_id, &data, &size);
3140 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3142 demux->other_streams =
3143 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3148 stream->inspect_payload = inspect_payload;
3153 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3154 /* we'll error out later if we found no streams */
3159 static const gchar *
3160 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3164 const gchar *asf_name;
3165 const gchar *gst_name;
3168 "WM/Genre", GST_TAG_GENRE}, {
3169 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3170 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3171 "WM/Picture", GST_TAG_IMAGE}, {
3172 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3173 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3174 "WM/Year", GST_TAG_DATE_TIME}
3175 /* { "WM/Composer", GST_TAG_COMPOSER } */
3180 if (name_utf8 == NULL) {
3181 GST_WARNING ("Failed to convert name to UTF8, skipping");
3185 out = strlen (name_utf8);
3187 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3188 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3189 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3190 return tags[i].gst_name;
3197 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3199 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3203 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3205 if (taglist == NULL)
3208 if (gst_tag_list_is_empty (taglist)) {
3209 gst_tag_list_unref (taglist);
3213 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3214 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3216 gst_tag_list_unref (demux->taglist);
3217 gst_tag_list_unref (taglist);
3219 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3222 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3223 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3224 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3225 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3228 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3232 const guint8 *img_data = NULL;
3233 guint32 img_data_len = 0;
3234 guint8 pic_type = 0;
3236 gst_byte_reader_init (&r, tag_data, tag_data_len);
3238 /* skip mime type string (we don't trust it and do our own typefinding),
3239 * and also skip the description string, since we don't use it */
3240 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3241 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3242 !gst_byte_reader_skip_string_utf16 (&r) ||
3243 !gst_byte_reader_skip_string_utf16 (&r) ||
3244 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3245 goto not_enough_data;
3249 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3250 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3256 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3257 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3262 /* Extended Content Description Object */
3263 static GstFlowReturn
3264 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3267 /* Other known (and unused) 'text/unicode' metadata available :
3270 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3271 * WMFSDKVersion = 9.00.00.2980
3272 * WMFSDKNeeded = 0.0.0.0000
3273 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3274 * WM/Publisher = 4AD
3276 * WM/ProviderRating = 8
3277 * WM/ProviderStyle = Rock (similar to WM/Genre)
3278 * WM/GenreID (similar to WM/Genre)
3279 * WM/TrackNumber (same as WM/Track but as a string)
3281 * Other known (and unused) 'non-text' metadata available :
3287 * We might want to read WM/TrackNumber and use atoi() if we don't have
3291 GstTagList *taglist;
3292 guint16 blockcount, i;
3293 gboolean content3D = FALSE;
3297 const gchar *interleave_name;
3298 GstASF3DMode interleaving_type;
3299 } stereoscopic_layout_map[] = {
3301 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3302 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3303 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3304 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3305 "DualStream", GST_ASF_3D_DUAL_STREAM}
3307 GST_INFO_OBJECT (demux, "object is an extended content description");
3309 taglist = gst_tag_list_new_empty ();
3311 /* Content Descriptor Count */
3313 goto not_enough_data;
3315 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3317 for (i = 1; i <= blockcount; ++i) {
3318 const gchar *gst_tag_name;
3322 GValue tag_value = { 0, };
3325 gchar *name_utf8 = NULL;
3329 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3330 goto not_enough_data;
3334 goto not_enough_data;
3336 /* Descriptor Value Data Type */
3337 datatype = gst_asf_demux_get_uint16 (&data, &size);
3339 /* Descriptor Value (not really a string, but same thing reading-wise) */
3340 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3342 goto not_enough_data;
3346 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3348 if (name_utf8 != NULL) {
3349 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3351 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3352 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3355 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3358 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3361 /* get rid of tags with empty value */
3362 if (value_utf8 != NULL && *value_utf8 != '\0') {
3363 GST_DEBUG ("string value %s", value_utf8);
3365 value_utf8[out] = '\0';
3367 if (gst_tag_name != NULL) {
3368 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3369 guint year = atoi (value_utf8);
3372 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3373 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3375 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3376 guint id3v1_genre_id;
3377 const gchar *genre_str;
3379 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3380 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3381 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3382 g_free (value_utf8);
3383 value_utf8 = g_strdup (genre_str);
3388 /* convert tag from string to other type if required */
3389 tag_type = gst_tag_get_type (gst_tag_name);
3390 g_value_init (&tag_value, tag_type);
3391 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3392 GValue from_val = { 0, };
3394 g_value_init (&from_val, G_TYPE_STRING);
3395 g_value_set_string (&from_val, value_utf8);
3396 if (!g_value_transform (&from_val, &tag_value)) {
3397 GST_WARNING_OBJECT (demux,
3398 "Could not transform string tag to " "%s tag type %s",
3399 gst_tag_name, g_type_name (tag_type));
3400 g_value_unset (&tag_value);
3402 g_value_unset (&from_val);
3407 GST_DEBUG ("Setting metadata");
3408 g_value_init (&tag_value, G_TYPE_STRING);
3409 g_value_set_string (&tag_value, value_utf8);
3410 /* If we found a stereoscopic marker, look for StereoscopicLayout
3414 if (strncmp ("StereoscopicLayout", name_utf8,
3415 strlen (name_utf8)) == 0) {
3416 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3417 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3419 demux->asf_3D_mode =
3420 stereoscopic_layout_map[i].interleaving_type;
3421 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3425 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3427 demux->asf_3D_mode = GST_ASF_3D_NONE;
3428 GST_INFO_OBJECT (demux, "None 3d type");
3431 } else if (value_utf8 == NULL) {
3432 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3434 GST_DEBUG ("Skipping empty string value for %s",
3435 GST_STR_NULL (gst_tag_name));
3437 g_free (value_utf8);
3440 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3442 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3443 GST_FIXME ("Unhandled byte array tag %s",
3444 GST_STR_NULL (gst_tag_name));
3447 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3453 case ASF_DEMUX_DATA_TYPE_DWORD:{
3459 uint_val = GST_READ_UINT32_LE (value);
3461 /* this is the track number */
3462 g_value_init (&tag_value, G_TYPE_UINT);
3464 /* WM/Track counts from 0 */
3465 if (!strcmp (name_utf8, "WM/Track"))
3468 g_value_set_uint (&tag_value, uint_val);
3472 case ASF_DEMUX_DATA_TYPE_BOOL:{
3478 bool_val = GST_READ_UINT32_LE (value);
3480 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3482 GST_INFO_OBJECT (demux, "This is 3D contents");
3485 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3493 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3498 if (G_IS_VALUE (&tag_value)) {
3500 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3502 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3503 * is supposed to have a 0 base but is often wrongly written to start
3504 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3505 * replace the value added earlier from WM/Track or put it first in
3506 * the list, so that it will get picked up by _get_uint() */
3507 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3508 merge_mode = GST_TAG_MERGE_REPLACE;
3510 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3513 GST_DEBUG ("Setting global metadata %s", name_utf8);
3514 gst_structure_set_value (demux->global_metadata, name_utf8,
3518 g_value_unset (&tag_value);
3527 gst_asf_demux_add_global_tags (demux, taglist);
3534 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3535 gst_tag_list_unref (taglist);
3536 return GST_FLOW_OK; /* not really fatal */
3540 static GstStructure *
3541 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3546 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3548 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3551 s = gst_caps_get_structure (demux->metadata, i);
3552 if (gst_structure_has_name (s, sname))
3556 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3558 /* try lookup again; demux->metadata took ownership of the structure, so we
3559 * can't really make any assumptions about what happened to it, so we can't
3560 * just return it directly after appending it */
3561 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3564 static GstFlowReturn
3565 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3568 guint16 blockcount, i;
3570 GST_INFO_OBJECT (demux, "object is a metadata object");
3572 /* Content Descriptor Count */
3574 goto not_enough_data;
3576 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3578 for (i = 0; i < blockcount; ++i) {
3580 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3581 guint32 data_len, ival;
3584 if (size < (2 + 2 + 2 + 2 + 4))
3585 goto not_enough_data;
3587 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3588 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3589 name_len = gst_asf_demux_get_uint16 (&data, &size);
3590 data_type = gst_asf_demux_get_uint16 (&data, &size);
3591 data_len = gst_asf_demux_get_uint32 (&data, &size);
3593 if (size < name_len + data_len)
3594 goto not_enough_data;
3596 /* convert name to UTF-8 */
3597 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3599 gst_asf_demux_skip_bytes (name_len, &data, &size);
3601 if (name_utf8 == NULL) {
3602 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3603 gst_asf_demux_skip_bytes (data_len, &data, &size);
3607 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3608 gst_asf_demux_skip_bytes (data_len, &data, &size);
3616 goto not_enough_data;
3619 ival = gst_asf_demux_get_uint32 (&data, &size);
3621 /* skip anything else there may be, just in case */
3622 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3624 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3625 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3629 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3635 GST_WARNING ("Unexpected end of data parsing metadata object");
3636 return GST_FLOW_OK; /* not really fatal */
3640 static GstFlowReturn
3641 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3643 GstFlowReturn ret = GST_FLOW_OK;
3644 guint32 i, num_objects;
3645 guint8 unknown G_GNUC_UNUSED;
3647 /* Get the rest of the header's header */
3648 if (size < (4 + 1 + 1))
3649 goto not_enough_data;
3651 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3652 unknown = gst_asf_demux_get_uint8 (&data, &size);
3653 unknown = gst_asf_demux_get_uint8 (&data, &size);
3655 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3656 demux->saw_file_header = FALSE;
3657 /* Loop through the header's objects, processing those */
3658 for (i = 0; i < num_objects; ++i) {
3659 GST_INFO_OBJECT (demux, "reading header part %u", i);
3660 ret = gst_asf_demux_process_object (demux, &data, &size);
3661 if (ret != GST_FLOW_OK) {
3662 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3666 if (!demux->saw_file_header) {
3667 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3668 ("Header does not have mandatory FILE section"));
3669 return GST_FLOW_ERROR;
3676 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3677 ("short read parsing HEADER object"));
3678 return GST_FLOW_ERROR;
3682 static GstFlowReturn
3683 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3685 guint64 creation_time G_GNUC_UNUSED;
3686 guint64 file_size G_GNUC_UNUSED;
3687 guint64 send_time G_GNUC_UNUSED;
3688 guint64 packets_count, play_time, preroll;
3689 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3691 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3692 goto not_enough_data;
3694 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3695 file_size = gst_asf_demux_get_uint64 (&data, &size);
3696 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3697 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3698 play_time = gst_asf_demux_get_uint64 (&data, &size);
3699 send_time = gst_asf_demux_get_uint64 (&data, &size);
3700 preroll = gst_asf_demux_get_uint64 (&data, &size);
3701 flags = gst_asf_demux_get_uint32 (&data, &size);
3702 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3703 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3704 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3706 demux->broadcast = ! !(flags & 0x01);
3707 demux->seekable = ! !(flags & 0x02);
3709 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3710 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3711 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3713 if (demux->broadcast) {
3714 /* these fields are invalid if the broadcast flag is set */
3719 if (min_pktsize != max_pktsize)
3720 goto non_fixed_packet_size;
3722 demux->packet_size = max_pktsize;
3724 /* FIXME: do we need send_time as well? what is it? */
3725 if ((play_time * 100) >= (preroll * GST_MSECOND))
3726 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3728 demux->play_time = 0;
3730 demux->preroll = preroll * GST_MSECOND;
3732 /* initial latency */
3733 demux->latency = demux->preroll;
3735 if (demux->play_time == 0)
3736 demux->seekable = FALSE;
3738 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3739 GST_TIME_ARGS (demux->play_time));
3740 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3741 GST_TIME_ARGS (demux->preroll));
3743 if (demux->play_time > 0) {
3744 demux->segment.duration = demux->play_time;
3747 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3749 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3751 demux->saw_file_header = TRUE;
3756 non_fixed_packet_size:
3758 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3759 ("packet size must be fixed"));
3760 return GST_FLOW_ERROR;
3764 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3765 ("short read parsing FILE object"));
3766 return GST_FLOW_ERROR;
3770 /* Content Description Object */
3771 static GstFlowReturn
3772 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3776 const gchar *gst_tag;
3781 GST_TAG_TITLE, 0, NULL}, {
3782 GST_TAG_ARTIST, 0, NULL}, {
3783 GST_TAG_COPYRIGHT, 0, NULL}, {
3784 GST_TAG_DESCRIPTION, 0, NULL}, {
3785 GST_TAG_COMMENT, 0, NULL}
3787 GstTagList *taglist;
3788 GValue value = { 0 };
3792 GST_INFO_OBJECT (demux, "object is a comment");
3794 if (size < (2 + 2 + 2 + 2 + 2))
3795 goto not_enough_data;
3797 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3798 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3799 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3800 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3801 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3803 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3804 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3805 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3807 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3808 if (size < tags[i].val_length)
3809 goto not_enough_data;
3811 /* might be just '/0', '/0'... */
3812 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3813 /* convert to UTF-8 */
3814 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3815 "UTF-8", "UTF-16LE", &in, &out, NULL);
3817 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3820 /* parse metadata into taglist */
3821 taglist = gst_tag_list_new_empty ();
3822 g_value_init (&value, G_TYPE_STRING);
3823 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3824 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3825 g_value_set_string (&value, tags[i].val_utf8);
3826 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3827 tags[i].gst_tag, &value, NULL);
3830 g_value_unset (&value);
3832 gst_asf_demux_add_global_tags (demux, taglist);
3834 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3835 g_free (tags[i].val_utf8);
3841 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3842 "comment tag section %d, skipping comment object", i);
3843 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3844 g_free (tags[i].val_utf8);
3845 return GST_FLOW_OK; /* not really fatal */
3849 static GstFlowReturn
3850 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3853 guint16 num_streams, i;
3857 goto not_enough_data;
3859 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3861 GST_INFO ("object is a bitrate properties object with %u streams",
3864 if (size < (num_streams * (2 + 4)))
3865 goto not_enough_data;
3867 for (i = 0; i < num_streams; ++i) {
3871 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3872 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3874 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3875 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3876 stream = gst_asf_demux_get_stream (demux, stream_id);
3878 if (stream->pending_tags == NULL)
3879 stream->pending_tags = gst_tag_list_new_empty ();
3880 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3881 GST_TAG_BITRATE, bitrate, NULL);
3883 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3886 GST_WARNING ("stream id %u is too large", stream_id);
3894 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3895 return GST_FLOW_OK; /* not really fatal */
3899 static GstFlowReturn
3900 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3903 GstFlowReturn ret = GST_FLOW_OK;
3906 /* Get the rest of the header's header */
3907 if (size < (16 + 2 + 4))
3908 goto not_enough_data;
3910 /* skip GUID and two other bytes */
3911 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3912 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3914 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3916 /* FIXME: does data_size include the rest of the header that we have read? */
3917 if (hdr_size > size)
3918 goto not_enough_data;
3920 while (hdr_size > 0) {
3921 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3922 if (ret != GST_FLOW_OK)
3930 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3931 ("short read parsing extended header object"));
3932 return GST_FLOW_ERROR;
3936 static GstFlowReturn
3937 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3943 goto not_enough_data;
3945 if (demux->languages) {
3946 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3947 g_strfreev (demux->languages);
3948 demux->languages = NULL;
3949 demux->num_languages = 0;
3952 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3953 GST_LOG ("%u languages:", demux->num_languages);
3955 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3956 for (i = 0; i < demux->num_languages; ++i) {
3957 guint8 len, *lang_data = NULL;
3960 goto not_enough_data;
3961 len = gst_asf_demux_get_uint8 (&data, &size);
3962 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3965 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3968 /* truncate "en-us" etc. to just "en" */
3969 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3972 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3973 demux->languages[i] = utf8;
3976 goto not_enough_data;
3984 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3985 g_free (demux->languages);
3986 demux->languages = NULL;
3987 demux->num_languages = 0;
3988 return GST_FLOW_OK; /* not fatal */
3992 static GstFlowReturn
3993 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3996 GstClockTime interval;
3999 if (size < (16 + 8 + 4 + 4))
4000 goto not_enough_data;
4003 gst_asf_demux_skip_bytes (16, &data, &size);
4004 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
4005 gst_asf_demux_skip_bytes (4, &data, &size);
4006 count = gst_asf_demux_get_uint32 (&data, &size);
4008 demux->sidx_interval = interval;
4009 demux->sidx_num_entries = count;
4010 g_free (demux->sidx_entries);
4011 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
4013 for (i = 0; i < count; ++i) {
4014 if (G_UNLIKELY (size < 6)) {
4015 /* adjust for broken files, to avoid having entries at the end
4016 * of the parsed index that point to time=0. Resulting in seeking to
4017 * the end of the file leading back to the beginning */
4018 demux->sidx_num_entries -= (count - i);
4021 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4022 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4023 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4024 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4025 demux->sidx_entries[i].count);
4028 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4035 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4036 return GST_FLOW_OK; /* not fatal */
4040 static GstFlowReturn
4041 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4042 guint8 * data, guint64 size)
4047 if (size < 16 + 2 + (2 * 2))
4048 goto not_enough_data;
4050 gst_asf_demux_get_guid (&guid, &data, &size);
4051 num = gst_asf_demux_get_uint16 (&data, &size);
4054 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4058 if (size < (num * sizeof (guint16)))
4059 goto not_enough_data;
4061 /* read mutually exclusive stream numbers */
4062 for (i = 0; i < num; ++i) {
4064 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4065 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4067 demux->mut_ex_streams =
4068 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4077 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4078 return GST_FLOW_OK; /* not absolutely fatal */
4083 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4085 return g_slist_find (demux->other_streams,
4086 GINT_TO_POINTER (stream_num)) == NULL;
4089 static GstFlowReturn
4090 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4093 AsfStreamExtProps esp;
4094 AsfStream *stream = NULL;
4095 AsfObject stream_obj;
4096 guint16 stream_name_count;
4097 guint16 num_payload_ext;
4099 guint8 *stream_obj_data = NULL;
4102 guint i, stream_num;
4105 obj_size = (guint) size;
4107 esp.payload_extensions = NULL;
4110 goto not_enough_data;
4113 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4114 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4115 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4116 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4117 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4118 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4119 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4120 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4121 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4122 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4123 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4124 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4125 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4126 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4127 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4129 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4130 GST_TIME_ARGS (esp.start_time));
4131 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4132 GST_TIME_ARGS (esp.end_time));
4133 GST_INFO ("flags = %08x", esp.flags);
4134 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4135 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4136 GST_INFO ("stream number = %u", stream_num);
4137 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4138 (esp.lang_idx < demux->num_languages) ?
4139 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4140 GST_INFO ("stream name count = %u", stream_name_count);
4142 /* read stream names */
4143 for (i = 0; i < stream_name_count; ++i) {
4144 guint16 stream_lang_idx G_GNUC_UNUSED;
4145 gchar *stream_name = NULL;
4148 goto not_enough_data;
4149 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4150 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4151 goto not_enough_data;
4152 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4153 g_free (stream_name); /* TODO: store names in struct */
4156 /* read payload extension systems stuff */
4157 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4159 if (num_payload_ext > 0)
4160 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4162 for (i = 0; i < num_payload_ext; ++i) {
4163 AsfPayloadExtension ext;
4165 guint32 sys_info_len;
4167 if (size < 16 + 2 + 4)
4168 goto not_enough_data;
4170 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4171 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4172 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4174 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4175 GST_LOG ("payload systems info len = %u", sys_info_len);
4176 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4177 goto not_enough_data;
4179 esp.payload_extensions[i] = ext;
4182 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4184 /* there might be an optional STREAM_INFO object here now; if not, we
4185 * should have parsed the corresponding stream info object already (since
4186 * we are parsing the extended stream properties objects delayed) */
4188 stream = gst_asf_demux_get_stream (demux, stream_num);
4192 if (size < ASF_OBJECT_HEADER_SIZE)
4193 goto not_enough_data;
4195 /* get size of the stream object */
4196 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4197 goto corrupted_stream;
4199 if (stream_obj.id != ASF_OBJ_STREAM)
4200 goto expected_stream_object;
4202 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4203 stream_obj.size > (10 * 1024 * 1024))
4204 goto not_enough_data;
4206 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4208 /* process this stream object later after all the other 'normal' ones
4209 * have been processed (since the others are more important/non-hidden) */
4210 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4211 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4212 goto not_enough_data;
4214 /* parse stream object */
4215 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4216 g_free (stream_obj_data);
4221 stream->ext_props = esp;
4223 /* try to set the framerate */
4224 if (stream->is_video && stream->caps) {
4225 GValue framerate = { 0 };
4229 g_value_init (&framerate, GST_TYPE_FRACTION);
4231 num = GST_SECOND / 100;
4232 denom = esp.avg_time_per_frame;
4234 /* avoid division by 0, assume 25/1 framerate */
4235 denom = GST_SECOND / 2500;
4238 gst_value_set_fraction (&framerate, num, denom);
4240 stream->caps = gst_caps_make_writable (stream->caps);
4241 s = gst_caps_get_structure (stream->caps, 0);
4242 gst_structure_set_value (s, "framerate", &framerate);
4243 g_value_unset (&framerate);
4244 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4245 num, denom, ((gdouble) num) / denom);
4248 /* add language info now if we have it */
4249 if (stream->ext_props.lang_idx < demux->num_languages) {
4250 if (stream->pending_tags == NULL)
4251 stream->pending_tags = gst_tag_list_new_empty ();
4252 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4253 demux->languages[stream->ext_props.lang_idx]);
4254 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4255 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4258 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4259 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4263 g_free (esp.payload_extensions);
4270 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4271 g_free (esp.payload_extensions);
4272 return GST_FLOW_OK; /* not absolutely fatal */
4274 expected_stream_object:
4276 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4277 "object: expected embedded stream object, but got %s object instead!",
4278 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4279 g_free (esp.payload_extensions);
4280 return GST_FLOW_OK; /* not absolutely fatal */
4284 GST_WARNING_OBJECT (demux, "Corrupted stream");
4285 g_free (esp.payload_extensions);
4286 return GST_FLOW_ERROR;
4290 static const gchar *
4291 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4295 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4296 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4297 nick += strlen ("ASF_OBJ_");
4299 if (demux->objpath == NULL) {
4300 demux->objpath = g_strdup (nick);
4304 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4305 g_free (demux->objpath);
4306 demux->objpath = newpath;
4309 return (const gchar *) demux->objpath;
4313 gst_asf_demux_pop_obj (GstASFDemux * demux)
4317 if ((s = g_strrstr (demux->objpath, "/"))) {
4320 g_free (demux->objpath);
4321 demux->objpath = NULL;
4326 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4331 /* Parse the queued extended stream property objects and add the info
4332 * to the existing streams or add the new embedded streams, but without
4333 * activating them yet */
4334 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4335 g_slist_length (demux->ext_stream_props));
4337 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4338 GstBuffer *buf = GST_BUFFER (l->data);
4341 gst_buffer_map (buf, &map, GST_MAP_READ);
4343 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4344 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4345 gst_buffer_unmap (buf, &map);
4346 gst_buffer_unref (buf);
4348 g_slist_free (demux->ext_stream_props);
4349 demux->ext_stream_props = NULL;
4354 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4358 for (i = 0; i < demux->num_streams; ++i) {
4363 stream = &demux->stream[i];
4365 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4367 if (stream->active) {
4368 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4373 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4376 /* check for each mutual exclusion whether it affects this stream */
4377 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4378 if (*mes == stream->id) {
4379 /* if yes, check if we've already added streams that are mutually
4380 * exclusive with the stream we're about to add */
4381 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4382 for (j = 0; j < demux->num_streams; ++j) {
4383 /* if the broadcast flag is set, assume the hidden streams aren't
4384 * actually streamed and hide them (or playbin won't work right),
4385 * otherwise assume their data is available */
4386 if (demux->stream[j].id == *mes && demux->broadcast) {
4388 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4389 "mutually exclusive with already existing stream ID %d, "
4390 "hiding stream", stream->id, demux->stream[j].id);
4402 /* FIXME: we should do stream activation based on preroll data in
4403 * streaming mode too */
4404 if (demux->streaming && !is_hidden)
4405 gst_asf_demux_activate_stream (demux, stream);
4410 static GstFlowReturn
4411 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4414 GstFlowReturn ret = GST_FLOW_OK;
4416 guint64 obj_data_size;
4418 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4419 return ASF_FLOW_NEED_MORE_DATA;
4421 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4423 return GST_FLOW_ERROR;
4424 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4426 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4428 if (*p_size < obj_data_size)
4429 return ASF_FLOW_NEED_MORE_DATA;
4431 gst_asf_demux_push_obj (demux, obj.id);
4433 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4436 case ASF_OBJ_STREAM:
4437 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4441 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4443 case ASF_OBJ_HEADER:
4444 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4446 case ASF_OBJ_COMMENT:
4447 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4450 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4452 case ASF_OBJ_BITRATE_PROPS:
4454 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4457 case ASF_OBJ_EXT_CONTENT_DESC:
4459 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4462 case ASF_OBJ_METADATA_OBJECT:
4463 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4465 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4468 /* process these later, we might not have parsed the corresponding
4469 * stream object yet */
4470 GST_LOG ("%s: queued for later parsing", demux->objpath);
4471 buf = gst_buffer_new_and_alloc (obj_data_size);
4472 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4473 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4477 case ASF_OBJ_LANGUAGE_LIST:
4478 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4480 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4481 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4484 case ASF_OBJ_SIMPLE_INDEX:
4485 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4487 case ASF_OBJ_CONTENT_ENCRYPTION:
4488 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4489 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4490 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4491 goto error_encrypted;
4492 case ASF_OBJ_CONCEAL_NONE:
4494 case ASF_OBJ_UNDEFINED:
4495 case ASF_OBJ_CODEC_COMMENT:
4497 case ASF_OBJ_PADDING:
4498 case ASF_OBJ_BITRATE_MUTEX:
4499 case ASF_OBJ_COMPATIBILITY:
4500 case ASF_OBJ_INDEX_PLACEHOLDER:
4501 case ASF_OBJ_INDEX_PARAMETERS:
4502 case ASF_OBJ_STREAM_PRIORITIZATION:
4503 case ASF_OBJ_SCRIPT_COMMAND:
4504 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4506 /* Unknown/unhandled object, skip it and hope for the best */
4507 GST_INFO ("%s: skipping object", demux->objpath);
4512 /* this can't fail, we checked the number of bytes available before */
4513 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4515 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4517 gst_asf_demux_pop_obj (demux);
4524 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4525 return GST_FLOW_ERROR;
4530 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4531 GstBuffer ** p_buffer)
4533 GstBuffer *descrambled_buffer;
4534 GstBuffer *scrambled_buffer;
4535 GstBuffer *sub_buffer;
4542 /* descrambled_buffer is initialised in the first iteration */
4543 descrambled_buffer = NULL;
4544 scrambled_buffer = *p_buffer;
4546 if (gst_buffer_get_size (scrambled_buffer) <
4547 stream->ds_packet_size * stream->span)
4550 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4551 offset += stream->ds_chunk_size) {
4552 off = offset / stream->ds_chunk_size;
4553 row = off / stream->span;
4554 col = off % stream->span;
4555 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4556 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4557 col, off, stream->ds_chunk_size);
4558 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4559 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4560 stream->span, stream->ds_packet_size);
4561 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4562 gst_buffer_get_size (scrambled_buffer));
4564 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4565 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4567 descrambled_buffer = sub_buffer;
4569 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4573 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4574 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4575 GST_BUFFER_DURATION (descrambled_buffer) =
4576 GST_BUFFER_DURATION (scrambled_buffer);
4577 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4578 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4579 GST_BUFFER_OFFSET_END (scrambled_buffer);
4581 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4583 gst_buffer_unref (scrambled_buffer);
4584 *p_buffer = descrambled_buffer;
4588 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4590 GstASFDemux *demux = GST_ASF_DEMUX (element);
4593 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4595 for (i = 0; i < demux->num_streams; ++i) {
4596 gst_event_ref (event);
4597 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4598 GST_OBJECT_CAST (element), event)) {
4599 gst_event_unref (event);
4604 gst_event_unref (event);
4608 /* takes ownership of the passed event */
4610 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4612 gboolean ret = TRUE;
4615 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4616 GST_EVENT_TYPE_NAME (event));
4618 for (i = 0; i < demux->num_streams; ++i) {
4619 gst_event_ref (event);
4620 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4622 gst_event_unref (event);
4627 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4631 gboolean res = FALSE;
4633 demux = GST_ASF_DEMUX (parent);
4635 GST_DEBUG ("handling %s query",
4636 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4638 switch (GST_QUERY_TYPE (query)) {
4639 case GST_QUERY_DURATION:
4643 gst_query_parse_duration (query, &format, NULL);
4645 if (format != GST_FORMAT_TIME) {
4646 GST_LOG ("only support duration queries in TIME format");
4650 res = gst_pad_query_default (pad, parent, query);
4652 GST_OBJECT_LOCK (demux);
4654 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4655 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4656 GST_TIME_ARGS (demux->segment.duration));
4658 gst_query_set_duration (query, GST_FORMAT_TIME,
4659 demux->segment.duration);
4663 GST_LOG ("duration not known yet");
4666 GST_OBJECT_UNLOCK (demux);
4671 case GST_QUERY_POSITION:{
4674 gst_query_parse_position (query, &format, NULL);
4676 if (format != GST_FORMAT_TIME) {
4677 GST_LOG ("only support position queries in TIME format");
4681 GST_OBJECT_LOCK (demux);
4683 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4684 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4685 GST_TIME_ARGS (demux->segment.position));
4687 gst_query_set_position (query, GST_FORMAT_TIME,
4688 demux->segment.position);
4692 GST_LOG ("position not known yet");
4695 GST_OBJECT_UNLOCK (demux);
4699 case GST_QUERY_SEEKING:{
4702 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4703 if (format == GST_FORMAT_TIME) {
4706 GST_OBJECT_LOCK (demux);
4707 duration = demux->segment.duration;
4708 GST_OBJECT_UNLOCK (demux);
4710 if (!demux->streaming || !demux->seekable) {
4711 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4718 /* try upstream first in TIME */
4719 res = gst_pad_query_default (pad, parent, query);
4721 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4722 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4723 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4724 /* if no luck, maybe in BYTES */
4725 if (!seekable || fmt != GST_FORMAT_TIME) {
4728 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4729 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4730 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4731 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4732 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4733 if (fmt != GST_FORMAT_BYTES)
4736 gst_query_unref (q);
4737 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4743 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4747 case GST_QUERY_LATENCY:
4750 GstClockTime min, max;
4752 /* preroll delay does not matter in non-live pipeline,
4753 * but we might end up in a live (rtsp) one ... */
4756 res = gst_pad_query_default (pad, parent, query);
4760 gst_query_parse_latency (query, &live, &min, &max);
4762 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4763 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4764 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4766 GST_OBJECT_LOCK (demux);
4767 min += demux->latency;
4769 max += demux->latency;
4770 GST_OBJECT_UNLOCK (demux);
4772 gst_query_set_latency (query, live, min, max);
4775 case GST_QUERY_SEGMENT:
4780 format = demux->segment.format;
4783 gst_segment_to_stream_time (&demux->segment, format,
4784 demux->segment.start);
4785 if ((stop = demux->segment.stop) == -1)
4786 stop = demux->segment.duration;
4788 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4790 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4795 res = gst_pad_query_default (pad, parent, query);
4802 static GstStateChangeReturn
4803 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4805 GstASFDemux *demux = GST_ASF_DEMUX (element);
4806 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4808 switch (transition) {
4809 case GST_STATE_CHANGE_NULL_TO_READY:{
4810 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4811 demux->need_newsegment = TRUE;
4812 demux->segment_running = FALSE;
4813 demux->keyunit_sync = FALSE;
4814 demux->accurate = FALSE;
4815 demux->adapter = gst_adapter_new ();
4816 demux->metadata = gst_caps_new_empty ();
4817 demux->global_metadata = gst_structure_new_empty ("metadata");
4818 demux->data_size = 0;
4819 demux->data_offset = 0;
4820 demux->index_offset = 0;
4821 demux->base_offset = 0;
4822 demux->flowcombiner = gst_flow_combiner_new ();
4830 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4831 if (ret == GST_STATE_CHANGE_FAILURE)
4834 switch (transition) {
4835 case GST_STATE_CHANGE_PAUSED_TO_READY:
4836 gst_asf_demux_reset (demux, FALSE);
4839 case GST_STATE_CHANGE_READY_TO_NULL:
4840 gst_asf_demux_reset (demux, FALSE);
4841 gst_flow_combiner_free (demux->flowcombiner);
4842 demux->flowcombiner = NULL;