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 (G_UNLIKELY (ret != GST_FLOW_OK))
1133 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1138 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1142 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1143 GST_WARNING_OBJECT (demux, "Corrupted data");
1146 if (obj.id != ASF_OBJ_DATA) {
1147 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1151 demux->state = GST_ASF_DEMUX_STATE_DATA;
1153 if (!demux->broadcast && obj.size > 50) {
1154 demux->data_size = obj.size - 50;
1155 /* CHECKME: for at least one file this is off by +158 bytes?! */
1156 demux->index_offset = demux->data_offset + demux->data_size;
1158 demux->data_size = 0;
1159 demux->index_offset = 0;
1164 if (!demux->broadcast) {
1165 /* skip object header (24 bytes) and file GUID (16 bytes) */
1166 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1168 demux->num_packets = 0;
1171 if (demux->num_packets == 0)
1172 demux->seekable = FALSE;
1174 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1175 if (demux->data_size == 0 && demux->num_packets > 0) {
1176 demux->data_size = demux->num_packets * demux->packet_size;
1177 demux->index_offset = demux->data_offset + demux->data_size;
1180 /* process pending stream objects and create pads for those */
1181 gst_asf_demux_process_queued_extended_stream_objects (demux);
1183 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1184 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1185 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1186 demux->data_offset, demux->data_size, demux->index_offset);
1192 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1194 GstFlowReturn flow = GST_FLOW_OK;
1196 GstBuffer *buf = NULL;
1201 GST_LOG_OBJECT (demux, "reading headers");
1203 /* pull HEADER object header, so we know its size */
1204 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1207 gst_buffer_map (buf, &map, GST_MAP_READ);
1208 g_assert (map.size >= 16 + 8);
1209 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1210 gst_buffer_unmap (buf, &map);
1211 gst_buffer_replace (&buf, NULL);
1212 flow = GST_FLOW_ERROR;
1215 gst_buffer_unmap (buf, &map);
1216 gst_buffer_replace (&buf, NULL);
1218 if (obj.id != ASF_OBJ_HEADER)
1221 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1223 /* pull HEADER object */
1224 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1228 size = obj.size; /* don't want obj.size changed */
1229 gst_buffer_map (buf, &map, GST_MAP_READ);
1230 g_assert (map.size >= size);
1231 bufdata = (guint8 *) map.data;
1232 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1233 gst_buffer_unmap (buf, &map);
1234 gst_buffer_replace (&buf, NULL);
1236 if (flow != GST_FLOW_OK) {
1237 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1241 /* calculate where the packet data starts */
1242 demux->data_offset = demux->base_offset + obj.size + 50;
1244 /* now pull beginning of DATA object before packet data */
1245 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1249 gst_buffer_map (buf, &map, GST_MAP_READ);
1250 g_assert (map.size >= size);
1251 bufdata = (guint8 *) map.data;
1252 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1255 if (demux->num_streams == 0)
1258 gst_buffer_unmap (buf, &map);
1259 gst_buffer_replace (&buf, NULL);
1267 gst_buffer_unmap (buf, &map);
1268 gst_buffer_replace (&buf, NULL);
1270 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1271 ("This doesn't seem to be an ASF file"));
1272 *pflow = GST_FLOW_ERROR;
1277 flow = GST_FLOW_ERROR;
1278 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1279 ("header parsing failed, or no streams found, flow = %s",
1280 gst_flow_get_name (flow)));
1285 gst_buffer_unmap (buf, &map);
1286 gst_buffer_replace (&buf, NULL);
1287 if (flow == ASF_FLOW_NEED_MORE_DATA)
1288 flow = GST_FLOW_ERROR;
1295 all_streams_prerolled (GstASFDemux * demux)
1297 GstClockTime preroll_time;
1298 guint i, num_no_data = 0;
1300 /* Allow at least 500ms of preroll_time */
1301 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1303 /* returns TRUE as long as there isn't a stream which (a) has data queued
1304 * and (b) the timestamp of last piece of data queued is < demux->preroll
1305 * AND there is at least one other stream with data queued */
1306 for (i = 0; i < demux->num_streams; ++i) {
1307 AsfPayload *last_payload = NULL;
1311 stream = &demux->stream[i];
1312 if (G_UNLIKELY (stream->payloads->len == 0)) {
1314 GST_LOG_OBJECT (stream->pad, "no data queued");
1318 /* find last payload with timestamp */
1319 for (last_idx = stream->payloads->len - 1;
1320 last_idx >= 0 && (last_payload == NULL
1321 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1322 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1325 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1326 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1327 GST_TIME_ARGS (preroll_time));
1328 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1329 || last_payload->ts <= preroll_time)) {
1330 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1335 if (G_UNLIKELY (num_no_data > 0))
1343 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1348 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1351 /* check for each mutual exclusion group whether it affects this stream */
1352 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1353 if (*mes == stream->id) {
1354 /* we are in this group; let's check if we've already activated streams
1355 * that are in the same group (and hence mutually exclusive to this
1357 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1360 for (i = 0; i < demux->num_streams; ++i) {
1361 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1362 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1363 "to already active stream with ID %d", stream->id,
1364 demux->stream[i].id);
1369 /* we can only be in this group once, let's break out and move on to
1370 * the next mutual exclusion group */
1381 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1383 /* remember the first queued timestamp for the segment */
1384 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1385 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1386 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1387 GST_TIME_ARGS (demux->first_ts));
1388 demux->segment_ts = payload_ts;
1389 /* always note, but only determines segment when streaming */
1390 if (demux->streaming)
1391 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1392 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1393 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1398 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1400 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1401 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1404 /* go trhough each stream, find smallest timestamp */
1405 for (i = 0; i < demux->num_streams; ++i) {
1408 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1409 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1410 stream = &demux->stream[i];
1412 for (j = 0; j < stream->payloads->len; ++j) {
1413 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1414 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1415 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1416 || stream_min_ts > payload->ts)) {
1417 stream_min_ts = payload->ts;
1419 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1420 payload->ts > stream_min_ts &&
1421 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1422 || stream_min_ts2 > payload->ts)) {
1423 stream_min_ts2 = payload->ts;
1427 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1428 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1429 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1430 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1431 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1433 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1436 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1437 stream_min_ts = stream_min_ts2;
1439 /* if we don't have timestamp for this stream, wait for more data */
1440 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1443 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1444 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1445 first_ts = stream_min_ts;
1448 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1451 demux->first_ts = first_ts;
1453 /* update packets queued before we knew first timestamp */
1454 for (i = 0; i < demux->num_streams; ++i) {
1457 stream = &demux->stream[i];
1459 for (j = 0; j < stream->payloads->len; ++j) {
1460 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1461 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1462 if (payload->ts > first_ts)
1463 payload->ts -= first_ts;
1471 gst_asf_demux_check_segment_ts (demux, 0);
1477 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1479 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1480 and often set wrong, inspecting the data is the only way that seem to be working */
1481 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1482 GstCaps *caps = NULL;
1484 GstAdapter *adapter = gst_adapter_new ();
1486 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1488 AsfPayload *payload;
1491 payload = &g_array_index (stream->payloads, AsfPayload, i);
1492 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1493 len = gst_adapter_available (adapter);
1494 data = gst_adapter_map (adapter, len);
1498 #define MIN_LENGTH 128
1500 /* look for the sync points */
1502 if (len < MIN_LENGTH || /* give typefind something to work on */
1503 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1504 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1510 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1513 if (prob < GST_TYPE_FIND_LIKELY) {
1516 if (len > MIN_LENGTH)
1517 /* this wasn't it, look for another sync point */
1521 gst_adapter_unmap (adapter);
1524 gst_object_unref (adapter);
1527 gst_caps_take (&stream->caps, caps);
1535 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1537 guint i, actual_streams = 0;
1539 if (demux->activated_streams)
1542 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1545 if (!all_streams_prerolled (demux) && !force) {
1546 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1550 for (i = 0; i < demux->num_streams; ++i) {
1551 AsfStream *stream = &demux->stream[i];
1553 if (stream->payloads->len > 0) {
1555 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1556 !stream->active && /* do not inspect active streams (caps were already set) */
1557 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1558 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1559 /* try to gather some more data */
1562 /* we don't check mutual exclusion stuff here; either we have data for
1563 * a stream, then we active it, or we don't, then we'll ignore it */
1564 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1565 gst_asf_demux_activate_stream (demux, stream);
1566 actual_streams += 1;
1568 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1572 if (actual_streams == 0) {
1573 /* We don't have any streams activated ! */
1574 GST_ERROR_OBJECT (demux, "No streams activated!");
1578 gst_asf_demux_release_old_pads (demux);
1580 demux->activated_streams = TRUE;
1581 GST_LOG_OBJECT (demux, "signalling no more pads");
1582 gst_element_no_more_pads (GST_ELEMENT (demux));
1586 /* returns the stream that has a complete payload with the lowest timestamp
1587 * queued, or NULL (we push things by timestamp because during the internal
1588 * prerolling we might accumulate more data then the external queues can take,
1589 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1591 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1593 AsfPayload *best_payload = NULL;
1594 AsfStream *best_stream = NULL;
1597 for (i = 0; i < demux->num_streams; ++i) {
1601 stream = &demux->stream[i];
1603 /* Don't push any data until we have at least one payload that falls within
1604 * the current segment. This way we can remove out-of-segment payloads that
1605 * don't need to be decoded after a seek, sending only data from the
1606 * keyframe directly before our segment start */
1607 if (stream->payloads->len > 0) {
1608 AsfPayload *payload = NULL;
1611 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1612 /* Reverse playback */
1614 if (stream->is_video) {
1615 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1616 if (stream->reverse_kf_ready) {
1618 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1619 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1620 /* TODO : remove payload from the list? */
1627 /* find first complete payload with timestamp */
1628 for (j = stream->payloads->len - 1;
1629 j >= 0 && (payload == NULL
1630 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1631 payload = &g_array_index (stream->payloads, AsfPayload, j);
1634 /* If there's a complete payload queued for this stream */
1635 if (!gst_asf_payload_is_complete (payload))
1641 /* find last payload with timestamp */
1642 for (last_idx = stream->payloads->len - 1;
1643 last_idx >= 0 && (payload == NULL
1644 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1645 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1648 /* if this is first payload after seek we might need to update the segment */
1649 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1650 gst_asf_demux_check_segment_ts (demux, payload->ts);
1652 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1653 (payload->ts < demux->segment.start))) {
1654 if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
1655 && payload->keyframe)) {
1656 GST_DEBUG_OBJECT (stream->pad,
1657 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1658 GST_TIME_ARGS (payload->ts));
1659 demux->segment.start = payload->ts;
1660 demux->segment.time = payload->ts;
1662 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1663 GST_TIME_FORMAT " which is before our segment start %"
1664 GST_TIME_FORMAT ", not pushing yet",
1665 GST_TIME_ARGS (payload->ts),
1666 GST_TIME_ARGS (demux->segment.start));
1671 /* find first complete payload with timestamp */
1673 j < stream->payloads->len && (payload == NULL
1674 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1675 payload = &g_array_index (stream->payloads, AsfPayload, j);
1678 /* Now see if there's a complete payload queued for this stream */
1679 if (!gst_asf_payload_is_complete (payload))
1683 /* ... and whether its timestamp is lower than the current best */
1684 if (best_stream == NULL || best_payload->ts > payload->ts) {
1685 best_stream = stream;
1686 best_payload = payload;
1694 static GstFlowReturn
1695 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1698 GstFlowReturn ret = GST_FLOW_OK;
1700 if (G_UNLIKELY (!demux->activated_streams)) {
1701 if (!gst_asf_demux_check_activate_streams (demux, force))
1703 /* streams are now activated */
1706 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1707 AsfPayload *payload;
1708 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1709 GstClockTime duration = GST_CLOCK_TIME_NONE;
1711 /* wait until we had a chance to "lock on" some payload's timestamp */
1712 if (G_UNLIKELY (demux->need_newsegment
1713 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1716 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1717 && stream->payloads->len) {
1718 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1720 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1723 /* do we need to send a newsegment event */
1724 if ((G_UNLIKELY (demux->need_newsegment))) {
1725 GstEvent *segment_event;
1727 /* safe default if insufficient upstream info */
1728 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1731 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1732 demux->segment.duration > 0) {
1733 /* slight HACK; prevent clipping of last bit */
1734 demux->segment.stop = demux->segment.duration + demux->in_gap;
1737 /* FIXME : only if ACCURATE ! */
1738 if (G_LIKELY (demux->keyunit_sync && !demux->accurate
1739 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1740 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1741 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1742 GST_TIME_ARGS (payload->ts));
1743 demux->segment.start = payload->ts;
1744 demux->segment.time = payload->ts;
1747 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1750 /* note: we fix up all timestamps to start from 0, so this should be ok */
1751 segment_event = gst_event_new_segment (&demux->segment);
1752 if (demux->segment_seqnum)
1753 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1754 gst_asf_demux_send_event_unlocked (demux, segment_event);
1756 /* now post any global tags we may have found */
1757 if (demux->taglist == NULL) {
1758 demux->taglist = gst_tag_list_new_empty ();
1759 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1762 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1763 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1765 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1766 gst_asf_demux_send_event_unlocked (demux,
1767 gst_event_new_tag (demux->taglist));
1768 demux->taglist = NULL;
1770 demux->need_newsegment = FALSE;
1771 demux->segment_seqnum = 0;
1772 demux->segment_running = TRUE;
1775 /* Do we have tags pending for this stream? */
1776 if (G_UNLIKELY (stream->pending_tags)) {
1777 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1778 gst_pad_push_event (stream->pad,
1779 gst_event_new_tag (stream->pending_tags));
1780 stream->pending_tags = NULL;
1783 /* We have the whole packet now so we should push the packet to
1784 * the src pad now. First though we should check if we need to do
1786 if (G_UNLIKELY (stream->span > 1)) {
1787 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1790 payload->buf = gst_buffer_make_writable (payload->buf);
1792 if (G_LIKELY (!payload->keyframe)) {
1793 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1796 if (G_UNLIKELY (stream->discont)) {
1797 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1798 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1799 stream->discont = FALSE;
1802 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1803 (payload->par_x != stream->par_x) &&
1804 (payload->par_y != stream->par_y))) {
1805 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1806 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1807 stream->par_x = payload->par_x;
1808 stream->par_y = payload->par_y;
1809 stream->caps = gst_caps_make_writable (stream->caps);
1810 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1811 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1812 gst_pad_set_caps (stream->pad, stream->caps);
1815 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1816 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1817 payload->interlaced);
1818 stream->interlaced = payload->interlaced;
1819 stream->caps = gst_caps_make_writable (stream->caps);
1820 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1821 (stream->interlaced ? "mixed" : "progressive"), NULL);
1822 gst_pad_set_caps (stream->pad, stream->caps);
1825 /* (sort of) interpolate timestamps using upstream "frame of reference",
1826 * typically useful for live src, but might (unavoidably) mess with
1827 * position reporting if a live src is playing not so live content
1828 * (e.g. rtspsrc taking some time to fall back to tcp) */
1829 timestamp = payload->ts;
1830 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1831 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1832 timestamp += demux->in_gap;
1834 /* Check if we're after the segment already, if so no need to push
1836 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1837 GST_DEBUG_OBJECT (stream->pad,
1838 "Payload after segment stop %" GST_TIME_FORMAT,
1839 GST_TIME_ARGS (demux->segment.stop));
1841 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1843 gst_buffer_unref (payload->buf);
1844 payload->buf = NULL;
1845 g_array_remove_index (stream->payloads, 0);
1846 /* Break out as soon as we have an issue */
1847 if (G_UNLIKELY (ret != GST_FLOW_OK))
1854 GST_BUFFER_PTS (payload->buf) = timestamp;
1856 if (payload->duration == GST_CLOCK_TIME_NONE
1857 && stream->ext_props.avg_time_per_frame != 0) {
1858 duration = stream->ext_props.avg_time_per_frame * 100;
1860 duration = payload->duration;
1862 GST_BUFFER_DURATION (payload->buf) = duration;
1864 /* FIXME: we should really set durations on buffers if we can */
1866 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1869 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1870 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1871 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1873 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1874 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1878 if (stream->active) {
1879 if (G_UNLIKELY (stream->first_buffer)) {
1880 if (stream->streamheader != NULL) {
1881 GST_DEBUG_OBJECT (stream->pad,
1882 "Pushing streamheader before first buffer");
1883 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1885 stream->first_buffer = FALSE;
1888 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1889 && timestamp > demux->segment.position) {
1890 demux->segment.position = timestamp;
1891 if (GST_CLOCK_TIME_IS_VALID (duration))
1892 demux->segment.position += timestamp;
1895 ret = gst_pad_push (stream->pad, payload->buf);
1897 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1900 gst_buffer_unref (payload->buf);
1903 payload->buf = NULL;
1904 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1905 && stream->reverse_kf_ready) {
1906 g_array_remove_index (stream->payloads, stream->kf_pos);
1909 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1911 stream->reverse_kf_ready = FALSE;
1914 g_array_remove_index (stream->payloads, 0);
1917 /* Break out as soon as we have an issue */
1918 if (G_UNLIKELY (ret != GST_FLOW_OK))
1926 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1931 g_assert (buf != NULL);
1933 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1935 gst_buffer_map (buf, &map, GST_MAP_READ);
1937 /* we return false on buffer too small */
1938 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1939 gst_buffer_unmap (buf, &map);
1943 /* check if it is a header */
1945 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1947 gst_buffer_unmap (buf, &map);
1948 if (valid && obj.id == ASF_OBJ_HEADER) {
1955 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1957 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1958 GstFlowReturn ret = GST_FLOW_OK;
1959 GstBuffer *buf = NULL;
1960 gboolean header = FALSE;
1962 /* TODO maybe we should skip index objects after the data and look
1963 * further for a new header */
1964 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1965 g_assert (buf != NULL);
1966 /* check if it is a header */
1967 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1968 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1969 demux->base_offset = off;
1973 gst_buffer_unref (buf);
1980 gst_asf_demux_loop (GstASFDemux * demux)
1982 GstFlowReturn flow = GST_FLOW_OK;
1983 GstBuffer *buf = NULL;
1986 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1987 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1991 flow = gst_asf_demux_pull_indices (demux);
1992 if (flow != GST_FLOW_OK)
1996 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1998 if (G_UNLIKELY (demux->num_packets != 0
1999 && demux->packet >= demux->num_packets))
2002 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2003 (guint) demux->num_packets);
2005 off = demux->data_offset + (demux->packet * demux->packet_size);
2007 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2008 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2009 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2010 if (flow == GST_FLOW_EOS) {
2012 } else if (flow == GST_FLOW_FLUSHING) {
2013 GST_DEBUG_OBJECT (demux, "Not fatal");
2020 if (G_LIKELY (demux->speed_packets == 1)) {
2021 GstAsfDemuxParsePacketError err;
2022 err = gst_asf_demux_parse_packet (demux, buf);
2023 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2024 /* when we don't know when the data object ends, we should check
2025 * for a chained asf */
2026 if (demux->num_packets == 0) {
2027 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2028 GST_INFO_OBJECT (demux, "Chained asf found");
2029 demux->base_offset = off;
2030 gst_asf_demux_reset (demux, TRUE);
2031 gst_buffer_unref (buf);
2035 /* FIXME: We should tally up fatal errors and error out only
2036 * after a few broken packets in a row? */
2038 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2039 gst_buffer_unref (buf);
2041 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2042 && !demux->seek_to_cur_pos) {
2044 if (demux->packet < 0) {
2054 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2056 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2057 && !demux->seek_to_cur_pos) {
2059 if (demux->packet < 0) {
2068 for (n = 0; n < demux->speed_packets; n++) {
2070 GstAsfDemuxParsePacketError err;
2073 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2074 n * demux->packet_size, demux->packet_size);
2075 err = gst_asf_demux_parse_packet (demux, sub);
2076 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2077 /* when we don't know when the data object ends, we should check
2078 * for a chained asf */
2079 if (demux->num_packets == 0) {
2080 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2081 GST_INFO_OBJECT (demux, "Chained asf found");
2082 demux->base_offset = off + n * demux->packet_size;
2083 gst_asf_demux_reset (demux, TRUE);
2084 gst_buffer_unref (sub);
2085 gst_buffer_unref (buf);
2089 /* FIXME: We should tally up fatal errors and error out only
2090 * after a few broken packets in a row? */
2092 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2096 gst_buffer_unref (sub);
2098 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2099 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2105 /* reset speed pull */
2106 demux->speed_packets = 1;
2109 gst_buffer_unref (buf);
2111 if (G_UNLIKELY ((demux->num_packets > 0
2112 && demux->packet >= demux->num_packets)
2113 || flow == GST_FLOW_EOS)) {
2114 GST_LOG_OBJECT (demux, "reached EOS");
2118 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2119 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2123 /* check if we're at the end of the configured segment */
2124 /* FIXME: check if segment end reached etc. */
2130 /* if we haven't activated our streams yet, this might be because we have
2131 * less data queued than required for preroll; force stream activation and
2132 * send any pending payloads before sending EOS */
2133 if (!demux->activated_streams)
2134 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2136 /* we want to push an eos or post a segment-done in any case */
2137 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2140 /* for segment playback we need to post when (in stream time)
2141 * we stopped, this is either stop (when set) or the duration. */
2142 if ((stop = demux->segment.stop) == -1)
2143 stop = demux->segment.duration;
2145 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2146 gst_element_post_message (GST_ELEMENT_CAST (demux),
2147 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2149 gst_asf_demux_send_event_unlocked (demux,
2150 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2151 } else if (flow != GST_FLOW_EOS) {
2152 /* check if we have a chained asf, in case, we don't eos yet */
2153 if (gst_asf_demux_check_chained_asf (demux)) {
2154 GST_INFO_OBJECT (demux, "Chained ASF starting");
2155 gst_asf_demux_reset (demux, TRUE);
2160 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2161 if (demux->activated_streams) {
2162 /* normal playback, send EOS to all linked pads */
2163 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2164 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2166 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2167 flow = GST_FLOW_EOS;
2170 /* ... and fall through to pause */
2174 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2175 gst_flow_get_name (flow));
2176 demux->segment_running = FALSE;
2177 gst_pad_pause_task (demux->sinkpad);
2179 /* For the error cases */
2180 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2181 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2182 ("This doesn't seem to be an ASF file"));
2183 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2184 /* Post an error. Hopefully something else already has, but if not... */
2185 GST_ELEMENT_FLOW_ERROR (demux, flow);
2186 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2195 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2196 flow = GST_FLOW_EOS;
2200 /* See FIXMEs above */
2203 gst_buffer_unref (buf);
2204 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2205 ("Error parsing ASF packet %u", (guint) demux->packet));
2206 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2207 flow = GST_FLOW_ERROR;
2213 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2214 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2215 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2218 gst_asf_demux_check_header (GstASFDemux * demux)
2221 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2222 ASF_OBJECT_HEADER_SIZE);
2223 if (cdata == NULL) /* need more data */
2224 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2226 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
2227 && obj.id == ASF_OBJ_HEADER) {
2228 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2231 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2234 static GstFlowReturn
2235 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2237 GstFlowReturn ret = GST_FLOW_OK;
2240 demux = GST_ASF_DEMUX (parent);
2242 GST_LOG_OBJECT (demux,
2243 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2244 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2245 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2247 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2248 GST_DEBUG_OBJECT (demux, "received DISCONT");
2249 gst_asf_demux_mark_discont (demux);
2252 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2253 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2254 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2255 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2256 ", interpolation gap: %" GST_TIME_FORMAT,
2257 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2260 gst_adapter_push (demux->adapter, buf);
2262 switch (demux->state) {
2263 case GST_ASF_DEMUX_STATE_INDEX:{
2264 gint result = gst_asf_demux_check_header (demux);
2265 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2268 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2269 /* we don't care about this, probably an index */
2270 /* TODO maybe would be smarter to skip all the indices
2271 * until we got a new header or EOS to decide */
2272 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2275 GST_INFO_OBJECT (demux, "Chained asf starting");
2276 /* cleanup and get ready for a chained asf */
2277 gst_asf_demux_reset (demux, TRUE);
2281 case GST_ASF_DEMUX_STATE_HEADER:{
2282 ret = gst_asf_demux_chain_headers (demux);
2283 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2285 /* otherwise fall through */
2287 case GST_ASF_DEMUX_STATE_DATA:
2291 data_size = demux->packet_size;
2293 while (gst_adapter_available (demux->adapter) >= data_size) {
2295 GstAsfDemuxParsePacketError err;
2297 /* we don't know the length of the stream
2298 * check for a chained asf everytime */
2299 if (demux->num_packets == 0) {
2300 gint result = gst_asf_demux_check_header (demux);
2302 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2303 GST_INFO_OBJECT (demux, "Chained asf starting");
2304 /* cleanup and get ready for a chained asf */
2305 gst_asf_demux_reset (demux, TRUE);
2308 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2309 && demux->packet >= demux->num_packets)) {
2310 /* do not overshoot data section when streaming */
2314 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2316 /* FIXME: We should tally up fatal errors and error out only
2317 * after a few broken packets in a row? */
2318 err = gst_asf_demux_parse_packet (demux, buf);
2320 gst_buffer_unref (buf);
2322 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2323 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2325 GST_WARNING_OBJECT (demux, "Parse error");
2327 if (demux->packet >= 0)
2330 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2331 && demux->packet >= demux->num_packets)) {
2332 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2337 g_assert_not_reached ();
2341 if (ret != GST_FLOW_OK)
2342 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2348 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2354 static inline gboolean
2355 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2357 if (*p_size < num_bytes)
2360 *p_data += num_bytes;
2361 *p_size -= num_bytes;
2365 static inline guint8
2366 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2370 g_assert (*p_size >= 1);
2371 ret = GST_READ_UINT8 (*p_data);
2372 *p_data += sizeof (guint8);
2373 *p_size -= sizeof (guint8);
2377 static inline guint16
2378 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2382 g_assert (*p_size >= 2);
2383 ret = GST_READ_UINT16_LE (*p_data);
2384 *p_data += sizeof (guint16);
2385 *p_size -= sizeof (guint16);
2389 static inline guint32
2390 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2394 g_assert (*p_size >= 4);
2395 ret = GST_READ_UINT32_LE (*p_data);
2396 *p_data += sizeof (guint32);
2397 *p_size -= sizeof (guint32);
2401 static inline guint64
2402 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2406 g_assert (*p_size >= 8);
2407 ret = GST_READ_UINT64_LE (*p_data);
2408 *p_data += sizeof (guint64);
2409 *p_size -= sizeof (guint64);
2414 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2415 guint8 ** p_data, guint64 * p_size)
2419 if (*p_size < num_bytes_to_read)
2422 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2423 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2425 *p_data += num_bytes_to_read;
2426 *p_size -= num_bytes_to_read;
2432 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2433 guint8 ** p_data, guint64 * p_size)
2437 if (*p_size < num_bytes_to_read)
2440 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2441 *p_data += num_bytes_to_read;
2442 *p_size -= num_bytes_to_read;
2447 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2448 guint8 ** p_data, guint64 * p_size)
2458 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2461 *p_strlen = s_length;
2463 if (s_length == 0) {
2464 GST_WARNING ("zero-length string");
2465 *p_str = g_strdup ("");
2469 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2472 g_assert (s != NULL);
2474 /* just because They don't exist doesn't
2475 * mean They are not out to get you ... */
2476 if (s[s_length - 1] != '\0') {
2477 s = g_realloc (s, s_length + 1);
2481 *p_str = (gchar *) s;
2487 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2489 g_assert (*p_size >= 4 * sizeof (guint32));
2491 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2492 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2493 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2494 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2498 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2501 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2504 /* WAVEFORMATEX Structure */
2505 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2506 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2507 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2508 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2509 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2510 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2511 /* Codec specific data size */
2512 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2513 if (audio->size > *p_size) {
2514 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2515 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2522 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2525 if (*p_size < (4 + 4 + 1 + 2))
2528 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2529 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2530 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2531 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2536 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2537 guint8 ** p_data, guint64 * p_size)
2539 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2542 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2544 if (fmt->size < 40) {
2545 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2548 if ((guint64) fmt->size - 4 > *p_size) {
2549 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2552 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2553 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2554 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2555 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2556 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2557 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2558 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2559 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2560 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2561 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2566 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2570 for (i = 0; i < demux->num_streams; i++) {
2571 if (demux->stream[i].id == id)
2572 return &demux->stream[i];
2575 if (gst_asf_demux_is_unknown_stream (demux, id))
2576 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2581 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2582 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2587 gst_pad_use_fixed_caps (src_pad);
2588 gst_pad_set_caps (src_pad, caps);
2590 gst_pad_set_event_function (src_pad,
2591 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2592 gst_pad_set_query_function (src_pad,
2593 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2595 stream = &demux->stream[demux->num_streams];
2596 stream->caps = caps;
2597 stream->pad = src_pad;
2599 stream->fps_known = !is_video; /* bit hacky for audio */
2600 stream->is_video = is_video;
2601 stream->pending_tags = tags;
2602 stream->discont = TRUE;
2603 stream->first_buffer = TRUE;
2604 stream->streamheader = streamheader;
2605 if (stream->streamheader) {
2606 stream->streamheader = gst_buffer_make_writable (streamheader);
2607 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2612 st = gst_caps_get_structure (caps, 0);
2613 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2614 par_x > 0 && par_y > 0) {
2615 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2616 stream->par_x = par_x;
2617 stream->par_y = par_y;
2621 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2623 /* TODO: create this array during reverse play? */
2624 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2626 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2627 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2629 ++demux->num_streams;
2631 stream->active = FALSE;
2637 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2638 GstBuffer * buffer, GstStructure * structure)
2640 GValue arr_val = G_VALUE_INIT;
2641 GValue buf_val = G_VALUE_INIT;
2643 g_value_init (&arr_val, GST_TYPE_ARRAY);
2644 g_value_init (&buf_val, GST_TYPE_BUFFER);
2646 gst_value_set_buffer (&buf_val, buffer);
2647 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2649 gst_structure_take_value (structure, "streamheader", &arr_val);
2653 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2654 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2656 GstTagList *tags = NULL;
2657 GstBuffer *extradata = NULL;
2660 guint16 size_left = 0;
2661 gchar *codec_name = NULL;
2664 size_left = audio->size;
2666 /* Create the audio pad */
2667 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2669 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2672 /* Swallow up any left over data and set up the
2673 * standard properties from the header info */
2675 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2676 "codec specific data", size_left);
2678 g_assert (size_left <= *p_size);
2679 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2682 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2683 * additional two bytes indicating extradata. */
2684 /* FIXME: Handle the channel reorder map here */
2685 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2686 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2689 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2690 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2693 /* Informing about that audio format we just added */
2695 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2696 g_free (codec_name);
2699 if (audio->byte_rate > 0) {
2700 /* Some ASF files have no bitrate props object (often seen with
2701 * ASF files that contain raw audio data). Example files can
2702 * be generated with FFmpeg (tested with v2.8.6), like this:
2704 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2706 * In this case, if audio->byte_rate is nonzero, use that as
2709 guint bitrate = audio->byte_rate * 8;
2712 tags = gst_tag_list_new_empty ();
2714 /* Add bitrate, but only if there is none set already, since
2715 * this is just a fallback in case there is no bitrate tag
2716 * already present */
2717 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2721 gst_buffer_unref (extradata);
2723 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2724 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2725 audio->codec_tag, tags);
2727 ++demux->num_audio_streams;
2729 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2733 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2734 asf_stream_video_format * video, guint16 id,
2735 guint8 ** p_data, guint64 * p_size)
2737 GstTagList *tags = NULL;
2738 GstStructure *caps_s;
2739 GstBuffer *extradata = NULL;
2744 gchar *codec_name = NULL;
2745 guint64 size_left = video->size - 40;
2746 GstBuffer *streamheader = NULL;
2747 guint par_w = 1, par_h = 1;
2749 /* Create the video pad */
2750 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2751 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2754 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2756 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2757 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2759 g_assert (size_left <= *p_size);
2760 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2763 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2765 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2766 caps = gst_riff_create_video_caps (video->tag, NULL,
2767 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2770 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2771 G_TYPE_UINT, video->tag, NULL);
2776 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2777 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2778 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2781 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2785 /* retry with the global metadata */
2786 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2787 demux->global_metadata);
2788 s = demux->global_metadata;
2789 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2790 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2791 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2792 if (ax > 0 && ay > 0) {
2795 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2800 s = gst_caps_get_structure (caps, 0);
2801 gst_structure_remove_field (s, "framerate");
2804 caps_s = gst_caps_get_structure (caps, 0);
2806 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2807 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2808 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2809 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2812 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2813 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2814 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2816 GstBuffer *buf = gst_value_get_buffer (value);
2819 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2820 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2821 /* this looks like a bytestream start */
2822 streamheader = gst_buffer_ref (buf);
2823 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2824 gst_structure_remove_field (caps_s, "codec_data");
2827 gst_buffer_unmap (buf, &mapinfo);
2832 /* For a 3D video, set multiview information into the caps based on
2833 * what was detected during object parsing */
2834 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2835 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2836 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2837 const gchar *mview_mode_str;
2839 switch (demux->asf_3D_mode) {
2840 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2841 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2843 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2844 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2845 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2847 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2848 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2850 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2851 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2852 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2854 case GST_ASF_3D_DUAL_STREAM:{
2855 gboolean is_right_view = FALSE;
2856 /* if Advanced_Mutual_Exclusion object exists, use it
2857 * to figure out which is the left view (lower ID) */
2858 if (demux->mut_ex_streams != NULL) {
2862 length = g_slist_length (demux->mut_ex_streams);
2864 for (i = 0; i < length; i++) {
2867 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2869 GST_DEBUG_OBJECT (demux,
2870 "has Mutual_Exclusion object. stream id in object is %d",
2871 GPOINTER_TO_INT (v_s_id));
2873 if (id > GPOINTER_TO_INT (v_s_id))
2874 is_right_view = TRUE;
2877 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2878 * first video stream encountered has the lower ID */
2879 if (demux->num_video_streams > 0) {
2880 /* This is not the first video stream, assuming right eye view */
2881 is_right_view = TRUE;
2885 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2887 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2894 GST_INFO_OBJECT (demux,
2895 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2898 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2899 if (mview_mode_str != NULL) {
2900 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2901 video->height, par_w, par_h))
2902 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2904 gst_caps_set_simple (caps,
2905 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2906 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2907 GST_FLAG_SET_MASK_EXACT, NULL);
2912 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2913 g_free (codec_name);
2917 gst_buffer_unref (extradata);
2919 GST_INFO ("Adding video stream #%u, id %u, codec %"
2920 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2921 GST_FOURCC_ARGS (video->tag), video->tag);
2923 ++demux->num_video_streams;
2925 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2926 streamheader, tags);
2930 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2932 if (!stream->active) {
2936 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2937 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2938 gst_pad_set_active (stream->pad, TRUE);
2941 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2942 "%03u", stream->id);
2945 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2947 if (gst_event_parse_group_id (event, &demux->group_id))
2948 demux->have_group_id = TRUE;
2950 demux->have_group_id = FALSE;
2951 gst_event_unref (event);
2952 } else if (!demux->have_group_id) {
2953 demux->have_group_id = TRUE;
2954 demux->group_id = gst_util_group_id_next ();
2957 event = gst_event_new_stream_start (stream_id);
2958 if (demux->have_group_id)
2959 gst_event_set_group_id (event, demux->group_id);
2961 gst_pad_push_event (stream->pad, event);
2963 gst_pad_set_caps (stream->pad, stream->caps);
2965 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2966 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2967 stream->active = TRUE;
2972 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2975 AsfCorrectionType correction_type;
2976 AsfStreamType stream_type;
2977 GstClockTime time_offset;
2978 gboolean is_encrypted G_GNUC_UNUSED;
2982 guint stream_specific_size;
2983 guint type_specific_size G_GNUC_UNUSED;
2984 guint unknown G_GNUC_UNUSED;
2985 gboolean inspect_payload = FALSE;
2986 AsfStream *stream = NULL;
2988 /* Get the rest of the header's header */
2989 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2990 goto not_enough_data;
2992 gst_asf_demux_get_guid (&guid, &data, &size);
2993 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2995 gst_asf_demux_get_guid (&guid, &data, &size);
2996 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2998 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
3000 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3001 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3003 flags = gst_asf_demux_get_uint16 (&data, &size);
3004 stream_id = flags & 0x7f;
3005 is_encrypted = ! !(flags & 0x8000);
3006 unknown = gst_asf_demux_get_uint32 (&data, &size);
3008 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3009 stream_id, GST_TIME_ARGS (time_offset));
3011 /* dvr-ms has audio stream declared in stream specific data */
3012 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3013 AsfExtStreamType ext_stream_type;
3014 gst_asf_demux_get_guid (&guid, &data, &size);
3015 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3017 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3018 inspect_payload = TRUE;
3020 gst_asf_demux_get_guid (&guid, &data, &size);
3021 gst_asf_demux_get_uint32 (&data, &size);
3022 gst_asf_demux_get_uint32 (&data, &size);
3023 gst_asf_demux_get_uint32 (&data, &size);
3024 gst_asf_demux_get_guid (&guid, &data, &size);
3025 gst_asf_demux_get_uint32 (&data, &size);
3026 stream_type = ASF_STREAM_AUDIO;
3030 switch (stream_type) {
3031 case ASF_STREAM_AUDIO:{
3032 asf_stream_audio audio_object;
3034 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3035 goto not_enough_data;
3037 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3040 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3043 switch (correction_type) {
3044 case ASF_CORRECTION_ON:{
3045 guint span, packet_size, chunk_size, data_size, silence_data;
3047 GST_INFO ("Using error correction");
3049 if (size < (1 + 2 + 2 + 2 + 1))
3050 goto not_enough_data;
3052 span = gst_asf_demux_get_uint8 (&data, &size);
3053 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3054 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3055 data_size = gst_asf_demux_get_uint16 (&data, &size);
3056 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3058 stream->span = span;
3060 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3061 packet_size, chunk_size, data_size, span, silence_data);
3063 if (stream->span > 1) {
3064 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3065 /* Disable descrambling */
3068 /* FIXME: this else branch was added for
3069 * weird_al_yankovic - the saga begins.asf */
3070 stream->ds_packet_size = packet_size;
3071 stream->ds_chunk_size = chunk_size;
3074 /* Descambling is enabled */
3075 stream->ds_packet_size = packet_size;
3076 stream->ds_chunk_size = chunk_size;
3079 /* Now skip the rest of the silence data */
3081 gst_bytestream_flush (demux->bs, data_size - 1);
3083 /* FIXME: CHECKME. And why -1? */
3084 if (data_size > 1) {
3085 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3086 goto not_enough_data;
3092 case ASF_CORRECTION_OFF:{
3093 GST_INFO ("Error correction off");
3094 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3095 goto not_enough_data;
3099 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3100 ("Audio stream using unknown error correction"));
3107 case ASF_STREAM_VIDEO:{
3108 asf_stream_video_format video_format_object;
3109 asf_stream_video video_object;
3112 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3113 goto not_enough_data;
3115 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3117 GST_INFO ("object is a video stream with %u bytes of "
3118 "additional data", vsize);
3120 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3122 goto not_enough_data;
3125 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3126 stream_id, &data, &size);
3132 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3134 demux->other_streams =
3135 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3140 stream->inspect_payload = inspect_payload;
3145 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3146 /* we'll error out later if we found no streams */
3151 static const gchar *
3152 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3156 const gchar *asf_name;
3157 const gchar *gst_name;
3160 "WM/Genre", GST_TAG_GENRE}, {
3161 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3162 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3163 "WM/Picture", GST_TAG_IMAGE}, {
3164 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3165 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3166 "WM/Year", GST_TAG_DATE_TIME}
3167 /* { "WM/Composer", GST_TAG_COMPOSER } */
3172 if (name_utf8 == NULL) {
3173 GST_WARNING ("Failed to convert name to UTF8, skipping");
3177 out = strlen (name_utf8);
3179 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3180 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3181 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3182 return tags[i].gst_name;
3189 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3191 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3195 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3197 if (taglist == NULL)
3200 if (gst_tag_list_is_empty (taglist)) {
3201 gst_tag_list_unref (taglist);
3205 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3206 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3208 gst_tag_list_unref (demux->taglist);
3209 gst_tag_list_unref (taglist);
3211 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3214 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3215 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3216 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3217 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3220 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3224 const guint8 *img_data = NULL;
3225 guint32 img_data_len = 0;
3226 guint8 pic_type = 0;
3228 gst_byte_reader_init (&r, tag_data, tag_data_len);
3230 /* skip mime type string (we don't trust it and do our own typefinding),
3231 * and also skip the description string, since we don't use it */
3232 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3233 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3234 !gst_byte_reader_skip_string_utf16 (&r) ||
3235 !gst_byte_reader_skip_string_utf16 (&r) ||
3236 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3237 goto not_enough_data;
3241 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3242 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3248 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3249 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3254 /* Extended Content Description Object */
3255 static GstFlowReturn
3256 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3259 /* Other known (and unused) 'text/unicode' metadata available :
3262 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3263 * WMFSDKVersion = 9.00.00.2980
3264 * WMFSDKNeeded = 0.0.0.0000
3265 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3266 * WM/Publisher = 4AD
3268 * WM/ProviderRating = 8
3269 * WM/ProviderStyle = Rock (similar to WM/Genre)
3270 * WM/GenreID (similar to WM/Genre)
3271 * WM/TrackNumber (same as WM/Track but as a string)
3273 * Other known (and unused) 'non-text' metadata available :
3279 * We might want to read WM/TrackNumber and use atoi() if we don't have
3283 GstTagList *taglist;
3284 guint16 blockcount, i;
3285 gboolean content3D = FALSE;
3289 const gchar *interleave_name;
3290 GstASF3DMode interleaving_type;
3291 } stereoscopic_layout_map[] = {
3293 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3294 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3295 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3296 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3297 "DualStream", GST_ASF_3D_DUAL_STREAM}
3299 GST_INFO_OBJECT (demux, "object is an extended content description");
3301 taglist = gst_tag_list_new_empty ();
3303 /* Content Descriptor Count */
3305 goto not_enough_data;
3307 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3309 for (i = 1; i <= blockcount; ++i) {
3310 const gchar *gst_tag_name;
3314 GValue tag_value = { 0, };
3317 gchar *name_utf8 = NULL;
3321 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3322 goto not_enough_data;
3326 goto not_enough_data;
3328 /* Descriptor Value Data Type */
3329 datatype = gst_asf_demux_get_uint16 (&data, &size);
3331 /* Descriptor Value (not really a string, but same thing reading-wise) */
3332 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3334 goto not_enough_data;
3338 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3340 if (name_utf8 != NULL) {
3341 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3343 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3344 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3347 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3350 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3353 /* get rid of tags with empty value */
3354 if (value_utf8 != NULL && *value_utf8 != '\0') {
3355 GST_DEBUG ("string value %s", value_utf8);
3357 value_utf8[out] = '\0';
3359 if (gst_tag_name != NULL) {
3360 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3361 guint year = atoi (value_utf8);
3364 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3365 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3367 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3368 guint id3v1_genre_id;
3369 const gchar *genre_str;
3371 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3372 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3373 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3374 g_free (value_utf8);
3375 value_utf8 = g_strdup (genre_str);
3380 /* convert tag from string to other type if required */
3381 tag_type = gst_tag_get_type (gst_tag_name);
3382 g_value_init (&tag_value, tag_type);
3383 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3384 GValue from_val = { 0, };
3386 g_value_init (&from_val, G_TYPE_STRING);
3387 g_value_set_string (&from_val, value_utf8);
3388 if (!g_value_transform (&from_val, &tag_value)) {
3389 GST_WARNING_OBJECT (demux,
3390 "Could not transform string tag to " "%s tag type %s",
3391 gst_tag_name, g_type_name (tag_type));
3392 g_value_unset (&tag_value);
3394 g_value_unset (&from_val);
3399 GST_DEBUG ("Setting metadata");
3400 g_value_init (&tag_value, G_TYPE_STRING);
3401 g_value_set_string (&tag_value, value_utf8);
3402 /* If we found a stereoscopic marker, look for StereoscopicLayout
3406 if (strncmp ("StereoscopicLayout", name_utf8,
3407 strlen (name_utf8)) == 0) {
3408 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3409 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3411 demux->asf_3D_mode =
3412 stereoscopic_layout_map[i].interleaving_type;
3413 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3417 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3419 demux->asf_3D_mode = GST_ASF_3D_NONE;
3420 GST_INFO_OBJECT (demux, "None 3d type");
3423 } else if (value_utf8 == NULL) {
3424 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3426 GST_DEBUG ("Skipping empty string value for %s",
3427 GST_STR_NULL (gst_tag_name));
3429 g_free (value_utf8);
3432 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3434 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3435 GST_FIXME ("Unhandled byte array tag %s",
3436 GST_STR_NULL (gst_tag_name));
3439 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3445 case ASF_DEMUX_DATA_TYPE_DWORD:{
3451 uint_val = GST_READ_UINT32_LE (value);
3453 /* this is the track number */
3454 g_value_init (&tag_value, G_TYPE_UINT);
3456 /* WM/Track counts from 0 */
3457 if (!strcmp (name_utf8, "WM/Track"))
3460 g_value_set_uint (&tag_value, uint_val);
3464 case ASF_DEMUX_DATA_TYPE_BOOL:{
3470 bool_val = GST_READ_UINT32_LE (value);
3472 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3474 GST_INFO_OBJECT (demux, "This is 3D contents");
3477 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3485 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3490 if (G_IS_VALUE (&tag_value)) {
3492 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3494 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3495 * is supposed to have a 0 base but is often wrongly written to start
3496 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3497 * replace the value added earlier from WM/Track or put it first in
3498 * the list, so that it will get picked up by _get_uint() */
3499 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3500 merge_mode = GST_TAG_MERGE_REPLACE;
3502 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3505 GST_DEBUG ("Setting global metadata %s", name_utf8);
3506 gst_structure_set_value (demux->global_metadata, name_utf8,
3510 g_value_unset (&tag_value);
3519 gst_asf_demux_add_global_tags (demux, taglist);
3526 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3527 gst_tag_list_unref (taglist);
3528 return GST_FLOW_OK; /* not really fatal */
3532 static GstStructure *
3533 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3538 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3540 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3543 s = gst_caps_get_structure (demux->metadata, i);
3544 if (gst_structure_has_name (s, sname))
3548 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3550 /* try lookup again; demux->metadata took ownership of the structure, so we
3551 * can't really make any assumptions about what happened to it, so we can't
3552 * just return it directly after appending it */
3553 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3556 static GstFlowReturn
3557 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3560 guint16 blockcount, i;
3562 GST_INFO_OBJECT (demux, "object is a metadata object");
3564 /* Content Descriptor Count */
3566 goto not_enough_data;
3568 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3570 for (i = 0; i < blockcount; ++i) {
3572 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3573 guint32 data_len, ival;
3576 if (size < (2 + 2 + 2 + 2 + 4))
3577 goto not_enough_data;
3579 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3580 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3581 name_len = gst_asf_demux_get_uint16 (&data, &size);
3582 data_type = gst_asf_demux_get_uint16 (&data, &size);
3583 data_len = gst_asf_demux_get_uint32 (&data, &size);
3585 if (size < name_len + data_len)
3586 goto not_enough_data;
3588 /* convert name to UTF-8 */
3589 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3591 gst_asf_demux_skip_bytes (name_len, &data, &size);
3593 if (name_utf8 == NULL) {
3594 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3595 gst_asf_demux_skip_bytes (data_len, &data, &size);
3599 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3600 gst_asf_demux_skip_bytes (data_len, &data, &size);
3608 goto not_enough_data;
3611 ival = gst_asf_demux_get_uint32 (&data, &size);
3613 /* skip anything else there may be, just in case */
3614 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3616 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3617 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3621 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3627 GST_WARNING ("Unexpected end of data parsing metadata object");
3628 return GST_FLOW_OK; /* not really fatal */
3632 static GstFlowReturn
3633 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3635 GstFlowReturn ret = GST_FLOW_OK;
3636 guint32 i, num_objects;
3637 guint8 unknown G_GNUC_UNUSED;
3639 /* Get the rest of the header's header */
3640 if (size < (4 + 1 + 1))
3641 goto not_enough_data;
3643 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3644 unknown = gst_asf_demux_get_uint8 (&data, &size);
3645 unknown = gst_asf_demux_get_uint8 (&data, &size);
3647 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3648 demux->saw_file_header = FALSE;
3649 /* Loop through the header's objects, processing those */
3650 for (i = 0; i < num_objects; ++i) {
3651 GST_INFO_OBJECT (demux, "reading header part %u", i);
3652 ret = gst_asf_demux_process_object (demux, &data, &size);
3653 if (ret != GST_FLOW_OK) {
3654 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3658 if (!demux->saw_file_header) {
3659 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3660 ("Header does not have mandatory FILE section"));
3661 return GST_FLOW_ERROR;
3668 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3669 ("short read parsing HEADER object"));
3670 return GST_FLOW_ERROR;
3674 static GstFlowReturn
3675 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3677 guint64 creation_time G_GNUC_UNUSED;
3678 guint64 file_size G_GNUC_UNUSED;
3679 guint64 send_time G_GNUC_UNUSED;
3680 guint64 packets_count, play_time, preroll;
3681 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3683 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3684 goto not_enough_data;
3686 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3687 file_size = gst_asf_demux_get_uint64 (&data, &size);
3688 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3689 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3690 play_time = gst_asf_demux_get_uint64 (&data, &size);
3691 send_time = gst_asf_demux_get_uint64 (&data, &size);
3692 preroll = gst_asf_demux_get_uint64 (&data, &size);
3693 flags = gst_asf_demux_get_uint32 (&data, &size);
3694 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3695 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3696 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3698 demux->broadcast = ! !(flags & 0x01);
3699 demux->seekable = ! !(flags & 0x02);
3701 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3702 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3703 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3705 if (demux->broadcast) {
3706 /* these fields are invalid if the broadcast flag is set */
3711 if (min_pktsize != max_pktsize)
3712 goto non_fixed_packet_size;
3714 demux->packet_size = max_pktsize;
3716 /* FIXME: do we need send_time as well? what is it? */
3717 if ((play_time * 100) >= (preroll * GST_MSECOND))
3718 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3720 demux->play_time = 0;
3722 demux->preroll = preroll * GST_MSECOND;
3724 /* initial latency */
3725 demux->latency = demux->preroll;
3727 if (demux->play_time == 0)
3728 demux->seekable = FALSE;
3730 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3731 GST_TIME_ARGS (demux->play_time));
3732 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3733 GST_TIME_ARGS (demux->preroll));
3735 if (demux->play_time > 0) {
3736 demux->segment.duration = demux->play_time;
3739 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3741 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3743 demux->saw_file_header = TRUE;
3748 non_fixed_packet_size:
3750 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3751 ("packet size must be fixed"));
3752 return GST_FLOW_ERROR;
3756 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3757 ("short read parsing FILE object"));
3758 return GST_FLOW_ERROR;
3762 /* Content Description Object */
3763 static GstFlowReturn
3764 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3768 const gchar *gst_tag;
3773 GST_TAG_TITLE, 0, NULL}, {
3774 GST_TAG_ARTIST, 0, NULL}, {
3775 GST_TAG_COPYRIGHT, 0, NULL}, {
3776 GST_TAG_DESCRIPTION, 0, NULL}, {
3777 GST_TAG_COMMENT, 0, NULL}
3779 GstTagList *taglist;
3780 GValue value = { 0 };
3784 GST_INFO_OBJECT (demux, "object is a comment");
3786 if (size < (2 + 2 + 2 + 2 + 2))
3787 goto not_enough_data;
3789 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3790 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3791 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3792 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3793 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3795 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3796 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3797 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3799 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3800 if (size < tags[i].val_length)
3801 goto not_enough_data;
3803 /* might be just '/0', '/0'... */
3804 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3805 /* convert to UTF-8 */
3806 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3807 "UTF-8", "UTF-16LE", &in, &out, NULL);
3809 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3812 /* parse metadata into taglist */
3813 taglist = gst_tag_list_new_empty ();
3814 g_value_init (&value, G_TYPE_STRING);
3815 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3816 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3817 g_value_set_string (&value, tags[i].val_utf8);
3818 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3819 tags[i].gst_tag, &value, NULL);
3822 g_value_unset (&value);
3824 gst_asf_demux_add_global_tags (demux, taglist);
3826 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3827 g_free (tags[i].val_utf8);
3833 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3834 "comment tag section %d, skipping comment object", i);
3835 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3836 g_free (tags[i].val_utf8);
3837 return GST_FLOW_OK; /* not really fatal */
3841 static GstFlowReturn
3842 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3845 guint16 num_streams, i;
3849 goto not_enough_data;
3851 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3853 GST_INFO ("object is a bitrate properties object with %u streams",
3856 if (size < (num_streams * (2 + 4)))
3857 goto not_enough_data;
3859 for (i = 0; i < num_streams; ++i) {
3863 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3864 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3866 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3867 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3868 stream = gst_asf_demux_get_stream (demux, stream_id);
3870 if (stream->pending_tags == NULL)
3871 stream->pending_tags = gst_tag_list_new_empty ();
3872 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3873 GST_TAG_BITRATE, bitrate, NULL);
3875 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3878 GST_WARNING ("stream id %u is too large", stream_id);
3886 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3887 return GST_FLOW_OK; /* not really fatal */
3891 static GstFlowReturn
3892 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3895 GstFlowReturn ret = GST_FLOW_OK;
3898 /* Get the rest of the header's header */
3899 if (size < (16 + 2 + 4))
3900 goto not_enough_data;
3902 /* skip GUID and two other bytes */
3903 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3904 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3906 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3908 /* FIXME: does data_size include the rest of the header that we have read? */
3909 if (hdr_size > size)
3910 goto not_enough_data;
3912 while (hdr_size > 0) {
3913 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3914 if (ret != GST_FLOW_OK)
3922 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3923 ("short read parsing extended header object"));
3924 return GST_FLOW_ERROR;
3928 static GstFlowReturn
3929 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3935 goto not_enough_data;
3937 if (demux->languages) {
3938 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3939 g_strfreev (demux->languages);
3940 demux->languages = NULL;
3941 demux->num_languages = 0;
3944 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3945 GST_LOG ("%u languages:", demux->num_languages);
3947 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3948 for (i = 0; i < demux->num_languages; ++i) {
3949 guint8 len, *lang_data = NULL;
3952 goto not_enough_data;
3953 len = gst_asf_demux_get_uint8 (&data, &size);
3954 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3957 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3960 /* truncate "en-us" etc. to just "en" */
3961 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3964 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3965 demux->languages[i] = utf8;
3968 goto not_enough_data;
3976 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3977 g_free (demux->languages);
3978 demux->languages = NULL;
3979 demux->num_languages = 0;
3980 return GST_FLOW_OK; /* not fatal */
3984 static GstFlowReturn
3985 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3988 GstClockTime interval;
3991 if (size < (16 + 8 + 4 + 4))
3992 goto not_enough_data;
3995 gst_asf_demux_skip_bytes (16, &data, &size);
3996 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3997 gst_asf_demux_skip_bytes (4, &data, &size);
3998 count = gst_asf_demux_get_uint32 (&data, &size);
4000 demux->sidx_interval = interval;
4001 demux->sidx_num_entries = count;
4002 g_free (demux->sidx_entries);
4003 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
4005 for (i = 0; i < count; ++i) {
4006 if (G_UNLIKELY (size < 6)) {
4007 /* adjust for broken files, to avoid having entries at the end
4008 * of the parsed index that point to time=0. Resulting in seeking to
4009 * the end of the file leading back to the beginning */
4010 demux->sidx_num_entries -= (count - i);
4013 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4014 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4015 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4016 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4017 demux->sidx_entries[i].count);
4020 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4027 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4028 return GST_FLOW_OK; /* not fatal */
4032 static GstFlowReturn
4033 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4034 guint8 * data, guint64 size)
4039 if (size < 16 + 2 + (2 * 2))
4040 goto not_enough_data;
4042 gst_asf_demux_get_guid (&guid, &data, &size);
4043 num = gst_asf_demux_get_uint16 (&data, &size);
4046 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4050 if (size < (num * sizeof (guint16)))
4051 goto not_enough_data;
4053 /* read mutually exclusive stream numbers */
4054 for (i = 0; i < num; ++i) {
4056 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4057 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4059 demux->mut_ex_streams =
4060 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4069 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4070 return GST_FLOW_OK; /* not absolutely fatal */
4075 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4077 return g_slist_find (demux->other_streams,
4078 GINT_TO_POINTER (stream_num)) == NULL;
4081 static GstFlowReturn
4082 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4085 AsfStreamExtProps esp;
4086 AsfStream *stream = NULL;
4087 AsfObject stream_obj;
4088 guint16 stream_name_count;
4089 guint16 num_payload_ext;
4091 guint8 *stream_obj_data = NULL;
4094 guint i, stream_num;
4097 obj_size = (guint) size;
4099 esp.payload_extensions = NULL;
4102 goto not_enough_data;
4105 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4106 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4107 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4108 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4109 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4110 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4111 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4112 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4113 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4114 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4115 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4116 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4117 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4118 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4119 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4121 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4122 GST_TIME_ARGS (esp.start_time));
4123 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4124 GST_TIME_ARGS (esp.end_time));
4125 GST_INFO ("flags = %08x", esp.flags);
4126 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4127 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4128 GST_INFO ("stream number = %u", stream_num);
4129 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4130 (esp.lang_idx < demux->num_languages) ?
4131 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4132 GST_INFO ("stream name count = %u", stream_name_count);
4134 /* read stream names */
4135 for (i = 0; i < stream_name_count; ++i) {
4136 guint16 stream_lang_idx G_GNUC_UNUSED;
4137 gchar *stream_name = NULL;
4140 goto not_enough_data;
4141 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4142 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4143 goto not_enough_data;
4144 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4145 g_free (stream_name); /* TODO: store names in struct */
4148 /* read payload extension systems stuff */
4149 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4151 if (num_payload_ext > 0)
4152 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4154 for (i = 0; i < num_payload_ext; ++i) {
4155 AsfPayloadExtension ext;
4157 guint32 sys_info_len;
4159 if (size < 16 + 2 + 4)
4160 goto not_enough_data;
4162 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4163 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4164 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4166 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4167 GST_LOG ("payload systems info len = %u", sys_info_len);
4168 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4169 goto not_enough_data;
4171 esp.payload_extensions[i] = ext;
4174 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4176 /* there might be an optional STREAM_INFO object here now; if not, we
4177 * should have parsed the corresponding stream info object already (since
4178 * we are parsing the extended stream properties objects delayed) */
4180 stream = gst_asf_demux_get_stream (demux, stream_num);
4184 if (size < ASF_OBJECT_HEADER_SIZE)
4185 goto not_enough_data;
4187 /* get size of the stream object */
4188 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4189 goto corrupted_stream;
4191 if (stream_obj.id != ASF_OBJ_STREAM)
4192 goto expected_stream_object;
4194 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4195 stream_obj.size > (10 * 1024 * 1024))
4196 goto not_enough_data;
4198 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4200 /* process this stream object later after all the other 'normal' ones
4201 * have been processed (since the others are more important/non-hidden) */
4202 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4203 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4204 goto not_enough_data;
4206 /* parse stream object */
4207 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4208 g_free (stream_obj_data);
4213 stream->ext_props = esp;
4215 /* try to set the framerate */
4216 if (stream->is_video && stream->caps) {
4217 GValue framerate = { 0 };
4221 g_value_init (&framerate, GST_TYPE_FRACTION);
4223 num = GST_SECOND / 100;
4224 denom = esp.avg_time_per_frame;
4226 /* avoid division by 0, assume 25/1 framerate */
4227 denom = GST_SECOND / 2500;
4230 gst_value_set_fraction (&framerate, num, denom);
4232 stream->caps = gst_caps_make_writable (stream->caps);
4233 s = gst_caps_get_structure (stream->caps, 0);
4234 gst_structure_set_value (s, "framerate", &framerate);
4235 g_value_unset (&framerate);
4236 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4237 num, denom, ((gdouble) num) / denom);
4240 /* add language info now if we have it */
4241 if (stream->ext_props.lang_idx < demux->num_languages) {
4242 if (stream->pending_tags == NULL)
4243 stream->pending_tags = gst_tag_list_new_empty ();
4244 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4245 demux->languages[stream->ext_props.lang_idx]);
4246 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4247 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4250 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4251 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4255 g_free (esp.payload_extensions);
4262 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4263 g_free (esp.payload_extensions);
4264 return GST_FLOW_OK; /* not absolutely fatal */
4266 expected_stream_object:
4268 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4269 "object: expected embedded stream object, but got %s object instead!",
4270 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4271 g_free (esp.payload_extensions);
4272 return GST_FLOW_OK; /* not absolutely fatal */
4276 GST_WARNING_OBJECT (demux, "Corrupted stream");
4277 g_free (esp.payload_extensions);
4278 return GST_FLOW_ERROR;
4282 static const gchar *
4283 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4287 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4288 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4289 nick += strlen ("ASF_OBJ_");
4291 if (demux->objpath == NULL) {
4292 demux->objpath = g_strdup (nick);
4296 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4297 g_free (demux->objpath);
4298 demux->objpath = newpath;
4301 return (const gchar *) demux->objpath;
4305 gst_asf_demux_pop_obj (GstASFDemux * demux)
4309 if ((s = g_strrstr (demux->objpath, "/"))) {
4312 g_free (demux->objpath);
4313 demux->objpath = NULL;
4318 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4323 /* Parse the queued extended stream property objects and add the info
4324 * to the existing streams or add the new embedded streams, but without
4325 * activating them yet */
4326 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4327 g_slist_length (demux->ext_stream_props));
4329 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4330 GstBuffer *buf = GST_BUFFER (l->data);
4333 gst_buffer_map (buf, &map, GST_MAP_READ);
4335 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4336 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4337 gst_buffer_unmap (buf, &map);
4338 gst_buffer_unref (buf);
4340 g_slist_free (demux->ext_stream_props);
4341 demux->ext_stream_props = NULL;
4346 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4350 for (i = 0; i < demux->num_streams; ++i) {
4355 stream = &demux->stream[i];
4357 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4359 if (stream->active) {
4360 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4365 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4368 /* check for each mutual exclusion whether it affects this stream */
4369 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4370 if (*mes == stream->id) {
4371 /* if yes, check if we've already added streams that are mutually
4372 * exclusive with the stream we're about to add */
4373 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4374 for (j = 0; j < demux->num_streams; ++j) {
4375 /* if the broadcast flag is set, assume the hidden streams aren't
4376 * actually streamed and hide them (or playbin won't work right),
4377 * otherwise assume their data is available */
4378 if (demux->stream[j].id == *mes && demux->broadcast) {
4380 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4381 "mutually exclusive with already existing stream ID %d, "
4382 "hiding stream", stream->id, demux->stream[j].id);
4394 /* FIXME: we should do stream activation based on preroll data in
4395 * streaming mode too */
4396 if (demux->streaming && !is_hidden)
4397 gst_asf_demux_activate_stream (demux, stream);
4402 static GstFlowReturn
4403 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4406 GstFlowReturn ret = GST_FLOW_OK;
4408 guint64 obj_data_size;
4410 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4411 return ASF_FLOW_NEED_MORE_DATA;
4413 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4415 return GST_FLOW_ERROR;
4416 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4418 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4420 if (*p_size < obj_data_size)
4421 return ASF_FLOW_NEED_MORE_DATA;
4423 gst_asf_demux_push_obj (demux, obj.id);
4425 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4428 case ASF_OBJ_STREAM:
4429 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4433 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4435 case ASF_OBJ_HEADER:
4436 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4438 case ASF_OBJ_COMMENT:
4439 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4442 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4444 case ASF_OBJ_BITRATE_PROPS:
4446 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4449 case ASF_OBJ_EXT_CONTENT_DESC:
4451 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4454 case ASF_OBJ_METADATA_OBJECT:
4455 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4457 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4460 /* process these later, we might not have parsed the corresponding
4461 * stream object yet */
4462 GST_LOG ("%s: queued for later parsing", demux->objpath);
4463 buf = gst_buffer_new_and_alloc (obj_data_size);
4464 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4465 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4469 case ASF_OBJ_LANGUAGE_LIST:
4470 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4472 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4473 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4476 case ASF_OBJ_SIMPLE_INDEX:
4477 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4479 case ASF_OBJ_CONTENT_ENCRYPTION:
4480 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4481 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4482 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4483 goto error_encrypted;
4484 case ASF_OBJ_CONCEAL_NONE:
4486 case ASF_OBJ_UNDEFINED:
4487 case ASF_OBJ_CODEC_COMMENT:
4489 case ASF_OBJ_PADDING:
4490 case ASF_OBJ_BITRATE_MUTEX:
4491 case ASF_OBJ_COMPATIBILITY:
4492 case ASF_OBJ_INDEX_PLACEHOLDER:
4493 case ASF_OBJ_INDEX_PARAMETERS:
4494 case ASF_OBJ_STREAM_PRIORITIZATION:
4495 case ASF_OBJ_SCRIPT_COMMAND:
4496 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4498 /* Unknown/unhandled object, skip it and hope for the best */
4499 GST_INFO ("%s: skipping object", demux->objpath);
4504 /* this can't fail, we checked the number of bytes available before */
4505 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4507 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4509 gst_asf_demux_pop_obj (demux);
4516 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4517 return GST_FLOW_ERROR;
4522 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4523 GstBuffer ** p_buffer)
4525 GstBuffer *descrambled_buffer;
4526 GstBuffer *scrambled_buffer;
4527 GstBuffer *sub_buffer;
4534 /* descrambled_buffer is initialised in the first iteration */
4535 descrambled_buffer = NULL;
4536 scrambled_buffer = *p_buffer;
4538 if (gst_buffer_get_size (scrambled_buffer) <
4539 stream->ds_packet_size * stream->span)
4542 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4543 offset += stream->ds_chunk_size) {
4544 off = offset / stream->ds_chunk_size;
4545 row = off / stream->span;
4546 col = off % stream->span;
4547 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4548 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4549 col, off, stream->ds_chunk_size);
4550 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4551 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4552 stream->span, stream->ds_packet_size);
4553 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4554 gst_buffer_get_size (scrambled_buffer));
4556 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4557 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4559 descrambled_buffer = sub_buffer;
4561 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4565 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4566 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4567 GST_BUFFER_DURATION (descrambled_buffer) =
4568 GST_BUFFER_DURATION (scrambled_buffer);
4569 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4570 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4571 GST_BUFFER_OFFSET_END (scrambled_buffer);
4573 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4575 gst_buffer_unref (scrambled_buffer);
4576 *p_buffer = descrambled_buffer;
4580 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4582 GstASFDemux *demux = GST_ASF_DEMUX (element);
4585 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4587 for (i = 0; i < demux->num_streams; ++i) {
4588 gst_event_ref (event);
4589 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4590 GST_OBJECT_CAST (element), event)) {
4591 gst_event_unref (event);
4596 gst_event_unref (event);
4600 /* takes ownership of the passed event */
4602 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4604 gboolean ret = TRUE;
4607 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4608 GST_EVENT_TYPE_NAME (event));
4610 for (i = 0; i < demux->num_streams; ++i) {
4611 gst_event_ref (event);
4612 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4614 gst_event_unref (event);
4619 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4623 gboolean res = FALSE;
4625 demux = GST_ASF_DEMUX (parent);
4627 GST_DEBUG ("handling %s query",
4628 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4630 switch (GST_QUERY_TYPE (query)) {
4631 case GST_QUERY_DURATION:
4635 gst_query_parse_duration (query, &format, NULL);
4637 if (format != GST_FORMAT_TIME) {
4638 GST_LOG ("only support duration queries in TIME format");
4642 res = gst_pad_query_default (pad, parent, query);
4644 GST_OBJECT_LOCK (demux);
4646 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4647 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4648 GST_TIME_ARGS (demux->segment.duration));
4650 gst_query_set_duration (query, GST_FORMAT_TIME,
4651 demux->segment.duration);
4655 GST_LOG ("duration not known yet");
4658 GST_OBJECT_UNLOCK (demux);
4663 case GST_QUERY_POSITION:{
4666 gst_query_parse_position (query, &format, NULL);
4668 if (format != GST_FORMAT_TIME) {
4669 GST_LOG ("only support position queries in TIME format");
4673 GST_OBJECT_LOCK (demux);
4675 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4676 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4677 GST_TIME_ARGS (demux->segment.position));
4679 gst_query_set_position (query, GST_FORMAT_TIME,
4680 demux->segment.position);
4684 GST_LOG ("position not known yet");
4687 GST_OBJECT_UNLOCK (demux);
4691 case GST_QUERY_SEEKING:{
4694 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4695 if (format == GST_FORMAT_TIME) {
4698 GST_OBJECT_LOCK (demux);
4699 duration = demux->segment.duration;
4700 GST_OBJECT_UNLOCK (demux);
4702 if (!demux->streaming || !demux->seekable) {
4703 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4710 /* try upstream first in TIME */
4711 res = gst_pad_query_default (pad, parent, query);
4713 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4714 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4715 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4716 /* if no luck, maybe in BYTES */
4717 if (!seekable || fmt != GST_FORMAT_TIME) {
4720 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4721 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4722 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4723 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4724 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4725 if (fmt != GST_FORMAT_BYTES)
4728 gst_query_unref (q);
4729 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4735 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4739 case GST_QUERY_LATENCY:
4742 GstClockTime min, max;
4744 /* preroll delay does not matter in non-live pipeline,
4745 * but we might end up in a live (rtsp) one ... */
4748 res = gst_pad_query_default (pad, parent, query);
4752 gst_query_parse_latency (query, &live, &min, &max);
4754 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4755 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4756 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4758 GST_OBJECT_LOCK (demux);
4759 min += demux->latency;
4761 max += demux->latency;
4762 GST_OBJECT_UNLOCK (demux);
4764 gst_query_set_latency (query, live, min, max);
4767 case GST_QUERY_SEGMENT:
4772 format = demux->segment.format;
4775 gst_segment_to_stream_time (&demux->segment, format,
4776 demux->segment.start);
4777 if ((stop = demux->segment.stop) == -1)
4778 stop = demux->segment.duration;
4780 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4782 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4787 res = gst_pad_query_default (pad, parent, query);
4794 static GstStateChangeReturn
4795 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4797 GstASFDemux *demux = GST_ASF_DEMUX (element);
4798 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4800 switch (transition) {
4801 case GST_STATE_CHANGE_NULL_TO_READY:{
4802 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4803 demux->need_newsegment = TRUE;
4804 demux->segment_running = FALSE;
4805 demux->keyunit_sync = FALSE;
4806 demux->accurate = FALSE;
4807 demux->adapter = gst_adapter_new ();
4808 demux->metadata = gst_caps_new_empty ();
4809 demux->global_metadata = gst_structure_new_empty ("metadata");
4810 demux->data_size = 0;
4811 demux->data_offset = 0;
4812 demux->index_offset = 0;
4813 demux->base_offset = 0;
4814 demux->flowcombiner = gst_flow_combiner_new ();
4822 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4823 if (ret == GST_STATE_CHANGE_FAILURE)
4826 switch (transition) {
4827 case GST_STATE_CHANGE_PAUSED_TO_READY:
4828 gst_asf_demux_reset (demux, FALSE);
4831 case GST_STATE_CHANGE_READY_TO_NULL:
4832 gst_asf_demux_reset (demux, FALSE);
4833 gst_flow_combiner_free (demux->flowcombiner);
4834 demux->flowcombiner = NULL;