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)
915 /* Callers should have made sure that data_len is big enough */
916 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
918 if (data_len < ASF_OBJECT_HEADER_SIZE)
921 guid.v1 = GST_READ_UINT32_LE (data + 0);
922 guid.v2 = GST_READ_UINT32_LE (data + 4);
923 guid.v3 = GST_READ_UINT32_LE (data + 8);
924 guid.v4 = GST_READ_UINT32_LE (data + 12);
926 tmp_size = GST_READ_UINT64_LE (data + 16);
927 if (tmp_size >= G_MAXUINT) {
928 GST_WARNING_OBJECT (demux,
929 "ASF Object size corrupted (greater than 32bit)");
932 object->size = tmp_size;
934 /* FIXME: make asf_demux_identify_object_guid() */
935 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
936 if (object->id == ASF_OBJ_UNDEFINED && expect) {
937 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
938 guid.v1, guid.v2, guid.v3, guid.v4);
945 gst_asf_demux_release_old_pads (GstASFDemux * demux)
947 GST_DEBUG_OBJECT (demux, "Releasing old pads");
949 while (demux->old_num_streams > 0) {
950 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
951 gst_event_new_eos ());
952 gst_asf_demux_free_stream (demux,
953 &demux->old_stream[demux->old_num_streams - 1]);
954 --demux->old_num_streams;
956 memset (demux->old_stream, 0, sizeof (demux->old_stream));
957 demux->old_num_streams = 0;
961 gst_asf_demux_chain_headers (GstASFDemux * demux)
964 guint8 *header_data, *data = NULL;
965 const guint8 *cdata = NULL;
967 GstFlowReturn flow = GST_FLOW_OK;
969 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
973 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
975 if (obj.id != ASF_OBJ_HEADER)
978 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
980 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
981 if (gst_adapter_available (demux->adapter) < obj.size + 50)
984 data = gst_adapter_take (demux->adapter, obj.size + 50);
987 header_size = obj.size;
988 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
989 if (flow != GST_FLOW_OK)
992 /* calculate where the packet data starts */
993 demux->data_offset = obj.size + 50;
995 /* now parse the beginning of the ASF_OBJ_DATA object */
996 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
999 if (demux->num_streams == 0)
1008 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1015 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1016 ("This doesn't seem to be an ASF file"));
1018 return GST_FLOW_ERROR;
1023 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1024 ("header parsing failed, or no streams found, flow = %s",
1025 gst_flow_get_name (flow)));
1027 return GST_FLOW_ERROR;
1032 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1033 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1038 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1041 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1043 if (G_LIKELY (p_flow))
1046 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1047 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1048 "+%u", gst_flow_get_name (flow), offset, size);
1053 g_assert (*p_buf != NULL);
1055 buffer_size = gst_buffer_get_size (*p_buf);
1056 if (G_UNLIKELY (buffer_size < size)) {
1057 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1058 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1059 gst_buffer_unref (*p_buf);
1060 if (G_LIKELY (p_flow))
1061 *p_flow = GST_FLOW_EOS;
1069 static GstFlowReturn
1070 gst_asf_demux_pull_indices (GstASFDemux * demux)
1072 GstBuffer *buf = NULL;
1075 GstFlowReturn ret = GST_FLOW_OK;
1077 offset = demux->index_offset;
1079 if (G_UNLIKELY (offset == 0)) {
1080 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1085 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1091 gst_buffer_map (buf, &map, GST_MAP_READ);
1092 g_assert (map.size >= 16 + 8);
1093 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1094 gst_buffer_unmap (buf, &map);
1095 gst_buffer_replace (&buf, NULL);
1096 ret = GST_FLOW_ERROR;
1099 gst_buffer_unmap (buf, &map);
1100 gst_buffer_replace (&buf, NULL);
1102 /* check for sanity */
1103 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1104 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1108 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1112 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1113 ", size %u", offset, (guint) obj.size);
1115 offset += obj.size; /* increase before _process_object changes it */
1117 gst_buffer_map (buf, &map, GST_MAP_READ);
1118 g_assert (map.size >= obj.size);
1119 bufdata = (guint8 *) map.data;
1120 obj_size = obj.size;
1121 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1122 gst_buffer_unmap (buf, &map);
1123 gst_buffer_replace (&buf, NULL);
1125 if (G_UNLIKELY (ret != GST_FLOW_OK))
1131 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1136 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1140 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1141 GST_WARNING_OBJECT (demux, "Corrupted data");
1144 if (obj.id != ASF_OBJ_DATA) {
1145 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1149 demux->state = GST_ASF_DEMUX_STATE_DATA;
1151 if (!demux->broadcast && obj.size > 50) {
1152 demux->data_size = obj.size - 50;
1153 /* CHECKME: for at least one file this is off by +158 bytes?! */
1154 demux->index_offset = demux->data_offset + demux->data_size;
1156 demux->data_size = 0;
1157 demux->index_offset = 0;
1162 if (!demux->broadcast) {
1163 /* skip object header (24 bytes) and file GUID (16 bytes) */
1164 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1166 demux->num_packets = 0;
1169 if (demux->num_packets == 0)
1170 demux->seekable = FALSE;
1172 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1173 if (demux->data_size == 0 && demux->num_packets > 0) {
1174 demux->data_size = demux->num_packets * demux->packet_size;
1175 demux->index_offset = demux->data_offset + demux->data_size;
1178 /* process pending stream objects and create pads for those */
1179 gst_asf_demux_process_queued_extended_stream_objects (demux);
1181 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1182 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1183 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1184 demux->data_offset, demux->data_size, demux->index_offset);
1190 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1192 GstFlowReturn flow = GST_FLOW_OK;
1194 GstBuffer *buf = NULL;
1199 GST_LOG_OBJECT (demux, "reading headers");
1201 /* pull HEADER object header, so we know its size */
1202 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1205 gst_buffer_map (buf, &map, GST_MAP_READ);
1206 g_assert (map.size >= 16 + 8);
1207 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1208 gst_buffer_unmap (buf, &map);
1209 gst_buffer_replace (&buf, NULL);
1210 flow = GST_FLOW_ERROR;
1213 gst_buffer_unmap (buf, &map);
1214 gst_buffer_replace (&buf, NULL);
1216 if (obj.id != ASF_OBJ_HEADER)
1219 GST_LOG_OBJECT (demux, "header size = %u", obj.size);
1221 /* pull HEADER object */
1222 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1226 size = obj.size; /* don't want obj.size changed */
1227 gst_buffer_map (buf, &map, GST_MAP_READ);
1228 g_assert (map.size >= size);
1229 bufdata = (guint8 *) map.data;
1230 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1231 gst_buffer_unmap (buf, &map);
1232 gst_buffer_replace (&buf, NULL);
1234 if (flow != GST_FLOW_OK) {
1235 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1239 /* calculate where the packet data starts */
1240 demux->data_offset = demux->base_offset + obj.size + 50;
1242 /* now pull beginning of DATA object before packet data */
1243 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1247 gst_buffer_map (buf, &map, GST_MAP_READ);
1248 g_assert (map.size >= size);
1249 bufdata = (guint8 *) map.data;
1250 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1253 if (demux->num_streams == 0)
1256 gst_buffer_unmap (buf, &map);
1257 gst_buffer_replace (&buf, NULL);
1265 gst_buffer_unmap (buf, &map);
1266 gst_buffer_replace (&buf, NULL);
1268 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1269 ("This doesn't seem to be an ASF file"));
1270 *pflow = GST_FLOW_ERROR;
1275 flow = GST_FLOW_ERROR;
1276 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1277 ("header parsing failed, or no streams found, flow = %s",
1278 gst_flow_get_name (flow)));
1283 gst_buffer_unmap (buf, &map);
1284 gst_buffer_replace (&buf, NULL);
1285 if (flow == ASF_FLOW_NEED_MORE_DATA)
1286 flow = GST_FLOW_ERROR;
1293 all_streams_prerolled (GstASFDemux * demux)
1295 GstClockTime preroll_time;
1296 guint i, num_no_data = 0;
1298 /* Allow at least 500ms of preroll_time */
1299 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1301 /* returns TRUE as long as there isn't a stream which (a) has data queued
1302 * and (b) the timestamp of last piece of data queued is < demux->preroll
1303 * AND there is at least one other stream with data queued */
1304 for (i = 0; i < demux->num_streams; ++i) {
1305 AsfPayload *last_payload = NULL;
1309 stream = &demux->stream[i];
1310 if (G_UNLIKELY (stream->payloads->len == 0)) {
1312 GST_LOG_OBJECT (stream->pad, "no data queued");
1316 /* find last payload with timestamp */
1317 for (last_idx = stream->payloads->len - 1;
1318 last_idx >= 0 && (last_payload == NULL
1319 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1320 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1323 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1324 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1325 GST_TIME_ARGS (preroll_time));
1326 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1327 || last_payload->ts <= preroll_time)) {
1328 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1333 if (G_UNLIKELY (num_no_data > 0))
1341 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1346 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1349 /* check for each mutual exclusion group whether it affects this stream */
1350 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1351 if (*mes == stream->id) {
1352 /* we are in this group; let's check if we've already activated streams
1353 * that are in the same group (and hence mutually exclusive to this
1355 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1358 for (i = 0; i < demux->num_streams; ++i) {
1359 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1360 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1361 "to already active stream with ID %d", stream->id,
1362 demux->stream[i].id);
1367 /* we can only be in this group once, let's break out and move on to
1368 * the next mutual exclusion group */
1379 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1381 /* remember the first queued timestamp for the segment */
1382 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1383 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1384 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1385 GST_TIME_ARGS (demux->first_ts));
1386 demux->segment_ts = payload_ts;
1387 /* always note, but only determines segment when streaming */
1388 if (demux->streaming)
1389 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1390 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1391 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1396 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1398 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1399 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1402 /* go trhough each stream, find smallest timestamp */
1403 for (i = 0; i < demux->num_streams; ++i) {
1406 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1407 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1408 stream = &demux->stream[i];
1410 for (j = 0; j < stream->payloads->len; ++j) {
1411 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1412 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1413 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1414 || stream_min_ts > payload->ts)) {
1415 stream_min_ts = payload->ts;
1417 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1418 payload->ts > stream_min_ts &&
1419 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1420 || stream_min_ts2 > payload->ts)) {
1421 stream_min_ts2 = payload->ts;
1425 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1426 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1427 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1428 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1429 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1431 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1434 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1435 stream_min_ts = stream_min_ts2;
1437 /* if we don't have timestamp for this stream, wait for more data */
1438 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1441 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1442 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1443 first_ts = stream_min_ts;
1446 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1449 demux->first_ts = first_ts;
1451 /* update packets queued before we knew first timestamp */
1452 for (i = 0; i < demux->num_streams; ++i) {
1455 stream = &demux->stream[i];
1457 for (j = 0; j < stream->payloads->len; ++j) {
1458 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1459 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1460 if (payload->ts > first_ts)
1461 payload->ts -= first_ts;
1469 gst_asf_demux_check_segment_ts (demux, 0);
1475 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1477 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1478 and often set wrong, inspecting the data is the only way that seem to be working */
1479 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1480 GstCaps *caps = NULL;
1482 GstAdapter *adapter = gst_adapter_new ();
1484 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1486 AsfPayload *payload;
1489 payload = &g_array_index (stream->payloads, AsfPayload, i);
1490 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1491 len = gst_adapter_available (adapter);
1492 data = gst_adapter_map (adapter, len);
1496 #define MIN_LENGTH 128
1498 /* look for the sync points */
1500 if (len < MIN_LENGTH || /* give typefind something to work on */
1501 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1502 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1508 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1511 if (prob < GST_TYPE_FIND_LIKELY) {
1514 if (len > MIN_LENGTH)
1515 /* this wasn't it, look for another sync point */
1519 gst_adapter_unmap (adapter);
1522 gst_object_unref (adapter);
1525 gst_caps_take (&stream->caps, caps);
1533 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1535 guint i, actual_streams = 0;
1537 if (demux->activated_streams)
1540 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1543 if (!all_streams_prerolled (demux) && !force) {
1544 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1548 for (i = 0; i < demux->num_streams; ++i) {
1549 AsfStream *stream = &demux->stream[i];
1551 if (stream->payloads->len > 0) {
1553 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1554 !stream->active && /* do not inspect active streams (caps were already set) */
1555 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1556 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1557 /* try to gather some more data */
1560 /* we don't check mutual exclusion stuff here; either we have data for
1561 * a stream, then we active it, or we don't, then we'll ignore it */
1562 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1563 gst_asf_demux_activate_stream (demux, stream);
1564 actual_streams += 1;
1566 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1570 if (actual_streams == 0) {
1571 /* We don't have any streams activated ! */
1572 GST_ERROR_OBJECT (demux, "No streams activated!");
1576 gst_asf_demux_release_old_pads (demux);
1578 demux->activated_streams = TRUE;
1579 GST_LOG_OBJECT (demux, "signalling no more pads");
1580 gst_element_no_more_pads (GST_ELEMENT (demux));
1584 /* returns the stream that has a complete payload with the lowest timestamp
1585 * queued, or NULL (we push things by timestamp because during the internal
1586 * prerolling we might accumulate more data then the external queues can take,
1587 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1589 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1591 AsfPayload *best_payload = NULL;
1592 AsfStream *best_stream = NULL;
1595 for (i = 0; i < demux->num_streams; ++i) {
1599 stream = &demux->stream[i];
1601 /* Don't push any data until we have at least one payload that falls within
1602 * the current segment. This way we can remove out-of-segment payloads that
1603 * don't need to be decoded after a seek, sending only data from the
1604 * keyframe directly before our segment start */
1605 if (stream->payloads->len > 0) {
1606 AsfPayload *payload = NULL;
1609 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1610 /* Reverse playback */
1612 if (stream->is_video) {
1613 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1614 if (stream->reverse_kf_ready) {
1616 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1617 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1618 /* TODO : remove payload from the list? */
1625 /* find first complete payload with timestamp */
1626 for (j = stream->payloads->len - 1;
1627 j >= 0 && (payload == NULL
1628 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1629 payload = &g_array_index (stream->payloads, AsfPayload, j);
1632 /* If there's a complete payload queued for this stream */
1633 if (!gst_asf_payload_is_complete (payload))
1639 /* find last payload with timestamp */
1640 for (last_idx = stream->payloads->len - 1;
1641 last_idx >= 0 && (payload == NULL
1642 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1643 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1646 /* if this is first payload after seek we might need to update the segment */
1647 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1648 gst_asf_demux_check_segment_ts (demux, payload->ts);
1650 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1651 (payload->ts < demux->segment.start))) {
1652 if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1653 && payload->keyframe)) {
1654 GST_DEBUG_OBJECT (stream->pad,
1655 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1656 GST_TIME_ARGS (payload->ts));
1657 demux->segment.start = payload->ts;
1658 demux->segment.time = payload->ts;
1660 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1661 GST_TIME_FORMAT " which is before our segment start %"
1662 GST_TIME_FORMAT ", not pushing yet",
1663 GST_TIME_ARGS (payload->ts),
1664 GST_TIME_ARGS (demux->segment.start));
1669 /* find first complete payload with timestamp */
1671 j < stream->payloads->len && (payload == NULL
1672 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1673 payload = &g_array_index (stream->payloads, AsfPayload, j);
1676 /* Now see if there's a complete payload queued for this stream */
1677 if (!gst_asf_payload_is_complete (payload))
1681 /* ... and whether its timestamp is lower than the current best */
1682 if (best_stream == NULL || best_payload->ts > payload->ts) {
1683 best_stream = stream;
1684 best_payload = payload;
1692 static GstFlowReturn
1693 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1696 GstFlowReturn ret = GST_FLOW_OK;
1698 if (G_UNLIKELY (!demux->activated_streams)) {
1699 if (!gst_asf_demux_check_activate_streams (demux, force))
1701 /* streams are now activated */
1704 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1705 AsfPayload *payload;
1706 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1707 GstClockTime duration = GST_CLOCK_TIME_NONE;
1709 /* wait until we had a chance to "lock on" some payload's timestamp */
1710 if (G_UNLIKELY (demux->need_newsegment
1711 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1714 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1715 && stream->payloads->len) {
1716 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1718 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1721 /* do we need to send a newsegment event */
1722 if ((G_UNLIKELY (demux->need_newsegment))) {
1723 GstEvent *segment_event;
1725 /* safe default if insufficient upstream info */
1726 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1729 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1730 demux->segment.duration > 0) {
1731 /* slight HACK; prevent clipping of last bit */
1732 demux->segment.stop = demux->segment.duration + demux->in_gap;
1735 /* FIXME : only if ACCURATE ! */
1736 if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1737 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1738 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1739 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1740 GST_TIME_ARGS (payload->ts));
1741 demux->segment.start = payload->ts;
1742 demux->segment.time = payload->ts;
1745 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1748 /* note: we fix up all timestamps to start from 0, so this should be ok */
1749 segment_event = gst_event_new_segment (&demux->segment);
1750 if (demux->segment_seqnum)
1751 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1752 gst_asf_demux_send_event_unlocked (demux, segment_event);
1754 /* now post any global tags we may have found */
1755 if (demux->taglist == NULL) {
1756 demux->taglist = gst_tag_list_new_empty ();
1757 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1760 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1761 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1763 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1764 gst_asf_demux_send_event_unlocked (demux,
1765 gst_event_new_tag (demux->taglist));
1766 demux->taglist = NULL;
1768 demux->need_newsegment = FALSE;
1769 demux->segment_seqnum = 0;
1770 demux->segment_running = TRUE;
1773 /* Do we have tags pending for this stream? */
1774 if (G_UNLIKELY (stream->pending_tags)) {
1775 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1776 gst_pad_push_event (stream->pad,
1777 gst_event_new_tag (stream->pending_tags));
1778 stream->pending_tags = NULL;
1781 /* We have the whole packet now so we should push the packet to
1782 * the src pad now. First though we should check if we need to do
1784 if (G_UNLIKELY (stream->span > 1)) {
1785 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1788 payload->buf = gst_buffer_make_writable (payload->buf);
1790 if (G_LIKELY (!payload->keyframe)) {
1791 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1794 if (G_UNLIKELY (stream->discont)) {
1795 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1796 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1797 stream->discont = FALSE;
1800 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1801 (payload->par_x != stream->par_x) &&
1802 (payload->par_y != stream->par_y))) {
1803 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1804 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1805 stream->par_x = payload->par_x;
1806 stream->par_y = payload->par_y;
1807 stream->caps = gst_caps_make_writable (stream->caps);
1808 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1809 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1810 gst_pad_set_caps (stream->pad, stream->caps);
1813 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1814 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1815 payload->interlaced);
1816 stream->interlaced = payload->interlaced;
1817 stream->caps = gst_caps_make_writable (stream->caps);
1818 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1819 (stream->interlaced ? "mixed" : "progressive"), NULL);
1820 gst_pad_set_caps (stream->pad, stream->caps);
1823 /* (sort of) interpolate timestamps using upstream "frame of reference",
1824 * typically useful for live src, but might (unavoidably) mess with
1825 * position reporting if a live src is playing not so live content
1826 * (e.g. rtspsrc taking some time to fall back to tcp) */
1827 timestamp = payload->ts;
1828 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1829 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1830 timestamp += demux->in_gap;
1832 /* Check if we're after the segment already, if so no need to push
1834 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1835 GST_DEBUG_OBJECT (stream->pad,
1836 "Payload after segment stop %" GST_TIME_FORMAT,
1837 GST_TIME_ARGS (demux->segment.stop));
1839 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1841 gst_buffer_unref (payload->buf);
1842 payload->buf = NULL;
1843 g_array_remove_index (stream->payloads, 0);
1844 /* Break out as soon as we have an issue */
1845 if (G_UNLIKELY (ret != GST_FLOW_OK))
1852 GST_BUFFER_PTS (payload->buf) = timestamp;
1854 if (payload->duration == GST_CLOCK_TIME_NONE
1855 && stream->ext_props.avg_time_per_frame != 0) {
1856 duration = stream->ext_props.avg_time_per_frame * 100;
1858 duration = payload->duration;
1860 GST_BUFFER_DURATION (payload->buf) = duration;
1862 /* FIXME: we should really set durations on buffers if we can */
1864 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1867 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1868 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1869 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1871 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1872 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1876 if (stream->active) {
1877 if (G_UNLIKELY (stream->first_buffer)) {
1878 if (stream->streamheader != NULL) {
1879 GST_DEBUG_OBJECT (stream->pad,
1880 "Pushing streamheader before first buffer");
1881 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1883 stream->first_buffer = FALSE;
1886 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1887 && timestamp > demux->segment.position) {
1888 demux->segment.position = timestamp;
1889 if (GST_CLOCK_TIME_IS_VALID (duration))
1890 demux->segment.position += timestamp;
1893 ret = gst_pad_push (stream->pad, payload->buf);
1895 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1898 gst_buffer_unref (payload->buf);
1901 payload->buf = NULL;
1902 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1903 && stream->reverse_kf_ready) {
1904 g_array_remove_index (stream->payloads, stream->kf_pos);
1907 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1909 stream->reverse_kf_ready = FALSE;
1912 g_array_remove_index (stream->payloads, 0);
1915 /* Break out as soon as we have an issue */
1916 if (G_UNLIKELY (ret != GST_FLOW_OK))
1924 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1929 g_assert (buf != NULL);
1931 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1933 gst_buffer_map (buf, &map, GST_MAP_READ);
1935 /* we return false on buffer too small */
1936 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1937 gst_buffer_unmap (buf, &map);
1941 /* check if it is a header */
1943 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1945 gst_buffer_unmap (buf, &map);
1946 if (valid && obj.id == ASF_OBJ_HEADER) {
1953 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1955 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1956 GstFlowReturn ret = GST_FLOW_OK;
1957 GstBuffer *buf = NULL;
1958 gboolean header = FALSE;
1960 /* TODO maybe we should skip index objects after the data and look
1961 * further for a new header */
1962 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1963 g_assert (buf != NULL);
1964 /* check if it is a header */
1965 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1966 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1967 demux->base_offset = off;
1971 gst_buffer_unref (buf);
1978 gst_asf_demux_loop (GstASFDemux * demux)
1980 GstFlowReturn flow = GST_FLOW_OK;
1981 GstBuffer *buf = NULL;
1984 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1985 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1989 flow = gst_asf_demux_pull_indices (demux);
1990 if (flow != GST_FLOW_OK)
1994 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1996 if (G_UNLIKELY (demux->num_packets != 0
1997 && demux->packet >= demux->num_packets))
2000 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2001 (guint) demux->num_packets);
2003 off = demux->data_offset + (demux->packet * demux->packet_size);
2005 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2006 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2007 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2008 if (flow == GST_FLOW_EOS) {
2010 } else if (flow == GST_FLOW_FLUSHING) {
2011 GST_DEBUG_OBJECT (demux, "Not fatal");
2018 if (G_LIKELY (demux->speed_packets == 1)) {
2019 GstAsfDemuxParsePacketError err;
2020 err = gst_asf_demux_parse_packet (demux, buf);
2021 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2022 /* when we don't know when the data object ends, we should check
2023 * for a chained asf */
2024 if (demux->num_packets == 0) {
2025 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2026 GST_INFO_OBJECT (demux, "Chained asf found");
2027 demux->base_offset = off;
2028 gst_asf_demux_reset (demux, TRUE);
2029 gst_buffer_unref (buf);
2033 /* FIXME: We should tally up fatal errors and error out only
2034 * after a few broken packets in a row? */
2036 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2037 gst_buffer_unref (buf);
2039 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2040 && !demux->seek_to_cur_pos) {
2042 if (demux->packet < 0) {
2052 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2054 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2055 && !demux->seek_to_cur_pos) {
2057 if (demux->packet < 0) {
2066 for (n = 0; n < demux->speed_packets; n++) {
2068 GstAsfDemuxParsePacketError err;
2071 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2072 n * demux->packet_size, demux->packet_size);
2073 err = gst_asf_demux_parse_packet (demux, sub);
2074 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2075 /* when we don't know when the data object ends, we should check
2076 * for a chained asf */
2077 if (demux->num_packets == 0) {
2078 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2079 GST_INFO_OBJECT (demux, "Chained asf found");
2080 demux->base_offset = off + n * demux->packet_size;
2081 gst_asf_demux_reset (demux, TRUE);
2082 gst_buffer_unref (sub);
2083 gst_buffer_unref (buf);
2087 /* FIXME: We should tally up fatal errors and error out only
2088 * after a few broken packets in a row? */
2090 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2094 gst_buffer_unref (sub);
2096 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2097 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2103 /* reset speed pull */
2104 demux->speed_packets = 1;
2107 gst_buffer_unref (buf);
2109 if (G_UNLIKELY ((demux->num_packets > 0
2110 && demux->packet >= demux->num_packets)
2111 || flow == GST_FLOW_EOS)) {
2112 GST_LOG_OBJECT (demux, "reached EOS");
2116 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2117 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2121 /* check if we're at the end of the configured segment */
2122 /* FIXME: check if segment end reached etc. */
2128 /* if we haven't activated our streams yet, this might be because we have
2129 * less data queued than required for preroll; force stream activation and
2130 * send any pending payloads before sending EOS */
2131 if (!demux->activated_streams)
2132 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2134 /* we want to push an eos or post a segment-done in any case */
2135 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2138 /* for segment playback we need to post when (in stream time)
2139 * we stopped, this is either stop (when set) or the duration. */
2140 if ((stop = demux->segment.stop) == -1)
2141 stop = demux->segment.duration;
2143 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2144 gst_element_post_message (GST_ELEMENT_CAST (demux),
2145 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2147 gst_asf_demux_send_event_unlocked (demux,
2148 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2149 } else if (flow != GST_FLOW_EOS) {
2150 /* check if we have a chained asf, in case, we don't eos yet */
2151 if (gst_asf_demux_check_chained_asf (demux)) {
2152 GST_INFO_OBJECT (demux, "Chained ASF starting");
2153 gst_asf_demux_reset (demux, TRUE);
2158 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2159 if (demux->activated_streams) {
2160 /* normal playback, send EOS to all linked pads */
2161 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2162 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2164 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2165 flow = GST_FLOW_EOS;
2168 /* ... and fall through to pause */
2172 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2173 gst_flow_get_name (flow));
2174 demux->segment_running = FALSE;
2175 gst_pad_pause_task (demux->sinkpad);
2177 /* For the error cases */
2178 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2179 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2180 ("This doesn't seem to be an ASF file"));
2181 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2182 /* Post an error. Hopefully something else already has, but if not... */
2183 GST_ELEMENT_FLOW_ERROR (demux, flow);
2184 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2193 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2194 flow = GST_FLOW_EOS;
2198 /* See FIXMEs above */
2201 gst_buffer_unref (buf);
2202 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2203 ("Error parsing ASF packet %u", (guint) demux->packet));
2204 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2205 flow = GST_FLOW_ERROR;
2211 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2212 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2213 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2216 gst_asf_demux_check_header (GstASFDemux * demux)
2219 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2220 ASF_OBJECT_HEADER_SIZE);
2221 if (cdata == NULL) /* need more data */
2222 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2224 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE
2225 && obj.id == ASF_OBJ_HEADER))
2226 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2228 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2231 static GstFlowReturn
2232 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2234 GstFlowReturn ret = GST_FLOW_OK;
2237 demux = GST_ASF_DEMUX (parent);
2239 GST_LOG_OBJECT (demux,
2240 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2241 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2242 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2244 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2245 GST_DEBUG_OBJECT (demux, "received DISCONT");
2246 gst_asf_demux_mark_discont (demux);
2249 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2250 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2251 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2252 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2253 ", interpolation gap: %" GST_TIME_FORMAT,
2254 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2257 gst_adapter_push (demux->adapter, buf);
2259 switch (demux->state) {
2260 case GST_ASF_DEMUX_STATE_INDEX:{
2261 gint result = gst_asf_demux_check_header (demux);
2262 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2265 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2266 /* we don't care about this, probably an index */
2267 /* TODO maybe would be smarter to skip all the indices
2268 * until we got a new header or EOS to decide */
2269 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2272 GST_INFO_OBJECT (demux, "Chained asf starting");
2273 /* cleanup and get ready for a chained asf */
2274 gst_asf_demux_reset (demux, TRUE);
2278 case GST_ASF_DEMUX_STATE_HEADER:{
2279 ret = gst_asf_demux_chain_headers (demux);
2280 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2282 /* otherwise fall through */
2284 case GST_ASF_DEMUX_STATE_DATA:
2288 data_size = demux->packet_size;
2290 while (gst_adapter_available (demux->adapter) >= data_size) {
2292 GstAsfDemuxParsePacketError err;
2294 /* we don't know the length of the stream
2295 * check for a chained asf everytime */
2296 if (demux->num_packets == 0) {
2297 gint result = gst_asf_demux_check_header (demux);
2299 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2300 GST_INFO_OBJECT (demux, "Chained asf starting");
2301 /* cleanup and get ready for a chained asf */
2302 gst_asf_demux_reset (demux, TRUE);
2305 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2306 && demux->packet >= demux->num_packets)) {
2307 /* do not overshoot data section when streaming */
2311 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2313 /* FIXME: We should tally up fatal errors and error out only
2314 * after a few broken packets in a row? */
2315 err = gst_asf_demux_parse_packet (demux, buf);
2317 gst_buffer_unref (buf);
2319 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2320 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2322 GST_WARNING_OBJECT (demux, "Parse error");
2324 if (demux->packet >= 0)
2327 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2328 && demux->packet >= demux->num_packets)) {
2329 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2334 g_assert_not_reached ();
2338 if (ret != GST_FLOW_OK)
2339 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2345 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2351 static inline gboolean
2352 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2354 if (*p_size < num_bytes)
2357 *p_data += num_bytes;
2358 *p_size -= num_bytes;
2362 static inline guint8
2363 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2367 g_assert (*p_size >= 1);
2368 ret = GST_READ_UINT8 (*p_data);
2369 *p_data += sizeof (guint8);
2370 *p_size -= sizeof (guint8);
2374 static inline guint16
2375 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2379 g_assert (*p_size >= 2);
2380 ret = GST_READ_UINT16_LE (*p_data);
2381 *p_data += sizeof (guint16);
2382 *p_size -= sizeof (guint16);
2386 static inline guint32
2387 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2391 g_assert (*p_size >= 4);
2392 ret = GST_READ_UINT32_LE (*p_data);
2393 *p_data += sizeof (guint32);
2394 *p_size -= sizeof (guint32);
2398 static inline guint64
2399 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2403 g_assert (*p_size >= 8);
2404 ret = GST_READ_UINT64_LE (*p_data);
2405 *p_data += sizeof (guint64);
2406 *p_size -= sizeof (guint64);
2411 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2412 guint8 ** p_data, guint64 * p_size)
2416 if (*p_size < num_bytes_to_read)
2419 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2420 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2422 *p_data += num_bytes_to_read;
2423 *p_size -= num_bytes_to_read;
2429 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2430 guint8 ** p_data, guint64 * p_size)
2434 if (*p_size < num_bytes_to_read)
2437 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2438 *p_data += num_bytes_to_read;
2439 *p_size -= num_bytes_to_read;
2444 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2445 guint8 ** p_data, guint64 * p_size)
2455 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2458 *p_strlen = s_length;
2460 if (s_length == 0) {
2461 GST_WARNING ("zero-length string");
2462 *p_str = g_strdup ("");
2466 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2469 g_assert (s != NULL);
2471 /* just because They don't exist doesn't
2472 * mean They are not out to get you ... */
2473 if (s[s_length - 1] != '\0') {
2474 s = g_realloc (s, s_length + 1);
2478 *p_str = (gchar *) s;
2484 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2486 g_assert (*p_size >= 4 * sizeof (guint32));
2488 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2489 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2490 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2491 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2495 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2498 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2501 /* WAVEFORMATEX Structure */
2502 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2503 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2504 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2505 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2506 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2507 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2508 /* Codec specific data size */
2509 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2514 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2517 if (*p_size < (4 + 4 + 1 + 2))
2520 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2521 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2522 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2523 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2528 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2529 guint8 ** p_data, guint64 * p_size)
2531 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2534 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2536 if (fmt->size < 40) {
2537 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2540 if ((guint64) fmt->size - 4 > *p_size) {
2541 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2544 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2545 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2546 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2547 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2548 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2549 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2550 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2551 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2552 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2553 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2558 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2562 for (i = 0; i < demux->num_streams; i++) {
2563 if (demux->stream[i].id == id)
2564 return &demux->stream[i];
2567 if (gst_asf_demux_is_unknown_stream (demux, id))
2568 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2573 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2574 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2579 gst_pad_use_fixed_caps (src_pad);
2580 gst_pad_set_caps (src_pad, caps);
2582 gst_pad_set_event_function (src_pad,
2583 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2584 gst_pad_set_query_function (src_pad,
2585 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2587 stream = &demux->stream[demux->num_streams];
2588 stream->caps = caps;
2589 stream->pad = src_pad;
2591 stream->fps_known = !is_video; /* bit hacky for audio */
2592 stream->is_video = is_video;
2593 stream->pending_tags = tags;
2594 stream->discont = TRUE;
2595 stream->first_buffer = TRUE;
2596 stream->streamheader = streamheader;
2597 if (stream->streamheader) {
2598 stream->streamheader = gst_buffer_make_writable (streamheader);
2599 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2604 st = gst_caps_get_structure (caps, 0);
2605 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2606 par_x > 0 && par_y > 0) {
2607 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2608 stream->par_x = par_x;
2609 stream->par_y = par_y;
2613 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2615 /* TODO: create this array during reverse play? */
2616 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2618 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2619 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2621 ++demux->num_streams;
2623 stream->active = FALSE;
2629 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2630 GstBuffer * buffer, GstStructure * structure)
2632 GValue arr_val = G_VALUE_INIT;
2633 GValue buf_val = G_VALUE_INIT;
2635 g_value_init (&arr_val, GST_TYPE_ARRAY);
2636 g_value_init (&buf_val, GST_TYPE_BUFFER);
2638 gst_value_set_buffer (&buf_val, buffer);
2639 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2641 gst_structure_take_value (structure, "streamheader", &arr_val);
2645 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2646 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2648 GstTagList *tags = NULL;
2649 GstBuffer *extradata = NULL;
2652 guint16 size_left = 0;
2653 gchar *codec_name = NULL;
2656 size_left = audio->size;
2658 /* Create the audio pad */
2659 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2661 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2664 /* Swallow up any left over data and set up the
2665 * standard properties from the header info */
2667 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2668 "codec specific data", size_left);
2670 g_assert (size_left <= *p_size);
2671 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2674 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2675 * additional two bytes indicating extradata. */
2676 /* FIXME: Handle the channel reorder map here */
2677 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2678 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2681 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2682 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2685 /* Informing about that audio format we just added */
2687 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2688 g_free (codec_name);
2691 if (audio->byte_rate > 0) {
2692 /* Some ASF files have no bitrate props object (often seen with
2693 * ASF files that contain raw audio data). Example files can
2694 * be generated with FFmpeg (tested with v2.8.6), like this:
2696 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2698 * In this case, if audio->byte_rate is nonzero, use that as
2701 guint bitrate = audio->byte_rate * 8;
2704 tags = gst_tag_list_new_empty ();
2706 /* Add bitrate, but only if there is none set already, since
2707 * this is just a fallback in case there is no bitrate tag
2708 * already present */
2709 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2713 gst_buffer_unref (extradata);
2715 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2716 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2717 audio->codec_tag, tags);
2719 ++demux->num_audio_streams;
2721 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2725 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2726 asf_stream_video_format * video, guint16 id,
2727 guint8 ** p_data, guint64 * p_size)
2729 GstTagList *tags = NULL;
2730 GstStructure *caps_s;
2731 GstBuffer *extradata = NULL;
2736 gchar *codec_name = NULL;
2737 guint64 size_left = video->size - 40;
2738 GstBuffer *streamheader = NULL;
2739 guint par_w = 1, par_h = 1;
2741 /* Create the video pad */
2742 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2743 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2746 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2748 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2749 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2751 g_assert (size_left <= *p_size);
2752 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2755 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2757 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2758 caps = gst_riff_create_video_caps (video->tag, NULL,
2759 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2762 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2763 G_TYPE_UINT, video->tag, NULL);
2768 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2769 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2770 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2773 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2777 /* retry with the global metadata */
2778 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2779 demux->global_metadata);
2780 s = demux->global_metadata;
2781 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2782 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2783 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2784 if (ax > 0 && ay > 0) {
2787 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2792 s = gst_caps_get_structure (caps, 0);
2793 gst_structure_remove_field (s, "framerate");
2796 caps_s = gst_caps_get_structure (caps, 0);
2798 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2799 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2800 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2801 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2804 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2805 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2806 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2808 GstBuffer *buf = gst_value_get_buffer (value);
2811 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2812 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2813 /* this looks like a bytestream start */
2814 streamheader = gst_buffer_ref (buf);
2815 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2816 gst_structure_remove_field (caps_s, "codec_data");
2819 gst_buffer_unmap (buf, &mapinfo);
2824 /* For a 3D video, set multiview information into the caps based on
2825 * what was detected during object parsing */
2826 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2827 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2828 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2829 const gchar *mview_mode_str;
2831 switch (demux->asf_3D_mode) {
2832 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2833 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2835 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2836 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2837 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2839 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2840 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2842 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2843 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2844 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2846 case GST_ASF_3D_DUAL_STREAM:{
2847 gboolean is_right_view = FALSE;
2848 /* if Advanced_Mutual_Exclusion object exists, use it
2849 * to figure out which is the left view (lower ID) */
2850 if (demux->mut_ex_streams != NULL) {
2854 length = g_slist_length (demux->mut_ex_streams);
2856 for (i = 0; i < length; i++) {
2859 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2861 GST_DEBUG_OBJECT (demux,
2862 "has Mutual_Exclusion object. stream id in object is %d",
2863 GPOINTER_TO_INT (v_s_id));
2865 if (id > GPOINTER_TO_INT (v_s_id))
2866 is_right_view = TRUE;
2869 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2870 * first video stream encountered has the lower ID */
2871 if (demux->num_video_streams > 0) {
2872 /* This is not the first video stream, assuming right eye view */
2873 is_right_view = TRUE;
2877 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2879 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2886 GST_INFO_OBJECT (demux,
2887 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2890 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2891 if (mview_mode_str != NULL) {
2892 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2893 video->height, par_w, par_h))
2894 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2896 gst_caps_set_simple (caps,
2897 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2898 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2899 GST_FLAG_SET_MASK_EXACT, NULL);
2904 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2905 g_free (codec_name);
2909 gst_buffer_unref (extradata);
2911 GST_INFO ("Adding video stream #%u, id %u, codec %"
2912 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2913 GST_FOURCC_ARGS (video->tag), video->tag);
2915 ++demux->num_video_streams;
2917 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2918 streamheader, tags);
2922 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2924 if (!stream->active) {
2928 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2929 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2930 gst_pad_set_active (stream->pad, TRUE);
2933 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2934 "%03u", stream->id);
2937 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2939 if (gst_event_parse_group_id (event, &demux->group_id))
2940 demux->have_group_id = TRUE;
2942 demux->have_group_id = FALSE;
2943 gst_event_unref (event);
2944 } else if (!demux->have_group_id) {
2945 demux->have_group_id = TRUE;
2946 demux->group_id = gst_util_group_id_next ();
2949 event = gst_event_new_stream_start (stream_id);
2950 if (demux->have_group_id)
2951 gst_event_set_group_id (event, demux->group_id);
2953 gst_pad_push_event (stream->pad, event);
2955 gst_pad_set_caps (stream->pad, stream->caps);
2957 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2958 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2959 stream->active = TRUE;
2964 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2967 AsfCorrectionType correction_type;
2968 AsfStreamType stream_type;
2969 GstClockTime time_offset;
2970 gboolean is_encrypted G_GNUC_UNUSED;
2974 guint stream_specific_size;
2975 guint type_specific_size G_GNUC_UNUSED;
2976 guint unknown G_GNUC_UNUSED;
2977 gboolean inspect_payload = FALSE;
2978 AsfStream *stream = NULL;
2980 /* Get the rest of the header's header */
2981 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2982 goto not_enough_data;
2984 gst_asf_demux_get_guid (&guid, &data, &size);
2985 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2987 gst_asf_demux_get_guid (&guid, &data, &size);
2988 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2990 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2992 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2993 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2995 flags = gst_asf_demux_get_uint16 (&data, &size);
2996 stream_id = flags & 0x7f;
2997 is_encrypted = ! !((flags & 0x8000) << 15);
2998 unknown = gst_asf_demux_get_uint32 (&data, &size);
3000 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3001 stream_id, GST_TIME_ARGS (time_offset));
3003 /* dvr-ms has audio stream declared in stream specific data */
3004 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3005 AsfExtStreamType ext_stream_type;
3006 gst_asf_demux_get_guid (&guid, &data, &size);
3007 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3009 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3010 inspect_payload = TRUE;
3012 gst_asf_demux_get_guid (&guid, &data, &size);
3013 gst_asf_demux_get_uint32 (&data, &size);
3014 gst_asf_demux_get_uint32 (&data, &size);
3015 gst_asf_demux_get_uint32 (&data, &size);
3016 gst_asf_demux_get_guid (&guid, &data, &size);
3017 gst_asf_demux_get_uint32 (&data, &size);
3018 stream_type = ASF_STREAM_AUDIO;
3022 switch (stream_type) {
3023 case ASF_STREAM_AUDIO:{
3024 asf_stream_audio audio_object;
3026 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3027 goto not_enough_data;
3029 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3032 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3035 switch (correction_type) {
3036 case ASF_CORRECTION_ON:{
3037 guint span, packet_size, chunk_size, data_size, silence_data;
3039 GST_INFO ("Using error correction");
3041 if (size < (1 + 2 + 2 + 2 + 1))
3042 goto not_enough_data;
3044 span = gst_asf_demux_get_uint8 (&data, &size);
3045 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3046 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3047 data_size = gst_asf_demux_get_uint16 (&data, &size);
3048 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3050 stream->span = span;
3052 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3053 packet_size, chunk_size, data_size, span, silence_data);
3055 if (stream->span > 1) {
3056 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3057 /* Disable descrambling */
3060 /* FIXME: this else branch was added for
3061 * weird_al_yankovic - the saga begins.asf */
3062 stream->ds_packet_size = packet_size;
3063 stream->ds_chunk_size = chunk_size;
3066 /* Descambling is enabled */
3067 stream->ds_packet_size = packet_size;
3068 stream->ds_chunk_size = chunk_size;
3071 /* Now skip the rest of the silence data */
3073 gst_bytestream_flush (demux->bs, data_size - 1);
3075 /* FIXME: CHECKME. And why -1? */
3076 if (data_size > 1) {
3077 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3078 goto not_enough_data;
3084 case ASF_CORRECTION_OFF:{
3085 GST_INFO ("Error correction off");
3086 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3087 goto not_enough_data;
3091 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3092 ("Audio stream using unknown error correction"));
3099 case ASF_STREAM_VIDEO:{
3100 asf_stream_video_format video_format_object;
3101 asf_stream_video video_object;
3104 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3105 goto not_enough_data;
3107 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3109 GST_INFO ("object is a video stream with %u bytes of "
3110 "additional data", vsize);
3112 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3114 goto not_enough_data;
3117 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3118 stream_id, &data, &size);
3124 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3126 demux->other_streams =
3127 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3132 stream->inspect_payload = inspect_payload;
3137 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3138 /* we'll error out later if we found no streams */
3143 static const gchar *
3144 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3148 const gchar *asf_name;
3149 const gchar *gst_name;
3152 "WM/Genre", GST_TAG_GENRE}, {
3153 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3154 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3155 "WM/Picture", GST_TAG_IMAGE}, {
3156 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3157 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3158 "WM/Year", GST_TAG_DATE_TIME}
3159 /* { "WM/Composer", GST_TAG_COMPOSER } */
3164 if (name_utf8 == NULL) {
3165 GST_WARNING ("Failed to convert name to UTF8, skipping");
3169 out = strlen (name_utf8);
3171 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3172 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3173 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3174 return tags[i].gst_name;
3181 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3183 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3187 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3189 if (taglist == NULL)
3192 if (gst_tag_list_is_empty (taglist)) {
3193 gst_tag_list_unref (taglist);
3197 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3198 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3200 gst_tag_list_unref (demux->taglist);
3201 gst_tag_list_unref (taglist);
3203 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3206 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3207 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3208 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3209 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3212 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3216 const guint8 *img_data = NULL;
3217 guint32 img_data_len = 0;
3218 guint8 pic_type = 0;
3220 gst_byte_reader_init (&r, tag_data, tag_data_len);
3222 /* skip mime type string (we don't trust it and do our own typefinding),
3223 * and also skip the description string, since we don't use it */
3224 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3225 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3226 !gst_byte_reader_skip_string_utf16 (&r) ||
3227 !gst_byte_reader_skip_string_utf16 (&r) ||
3228 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3229 goto not_enough_data;
3233 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3234 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3240 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3241 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3246 /* Extended Content Description Object */
3247 static GstFlowReturn
3248 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3251 /* Other known (and unused) 'text/unicode' metadata available :
3254 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3255 * WMFSDKVersion = 9.00.00.2980
3256 * WMFSDKNeeded = 0.0.0.0000
3257 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3258 * WM/Publisher = 4AD
3260 * WM/ProviderRating = 8
3261 * WM/ProviderStyle = Rock (similar to WM/Genre)
3262 * WM/GenreID (similar to WM/Genre)
3263 * WM/TrackNumber (same as WM/Track but as a string)
3265 * Other known (and unused) 'non-text' metadata available :
3271 * We might want to read WM/TrackNumber and use atoi() if we don't have
3275 GstTagList *taglist;
3276 guint16 blockcount, i;
3277 gboolean content3D = FALSE;
3281 const gchar *interleave_name;
3282 GstASF3DMode interleaving_type;
3283 } stereoscopic_layout_map[] = {
3285 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3286 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3287 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3288 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3289 "DualStream", GST_ASF_3D_DUAL_STREAM}
3291 GST_INFO_OBJECT (demux, "object is an extended content description");
3293 taglist = gst_tag_list_new_empty ();
3295 /* Content Descriptor Count */
3297 goto not_enough_data;
3299 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3301 for (i = 1; i <= blockcount; ++i) {
3302 const gchar *gst_tag_name;
3306 GValue tag_value = { 0, };
3309 gchar *name_utf8 = NULL;
3313 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3314 goto not_enough_data;
3318 goto not_enough_data;
3320 /* Descriptor Value Data Type */
3321 datatype = gst_asf_demux_get_uint16 (&data, &size);
3323 /* Descriptor Value (not really a string, but same thing reading-wise) */
3324 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3326 goto not_enough_data;
3330 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3332 if (name_utf8 != NULL) {
3333 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3335 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3336 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3339 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3342 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3345 /* get rid of tags with empty value */
3346 if (value_utf8 != NULL && *value_utf8 != '\0') {
3347 GST_DEBUG ("string value %s", value_utf8);
3349 value_utf8[out] = '\0';
3351 if (gst_tag_name != NULL) {
3352 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3353 guint year = atoi (value_utf8);
3356 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3357 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3359 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3360 guint id3v1_genre_id;
3361 const gchar *genre_str;
3363 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3364 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3365 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3366 g_free (value_utf8);
3367 value_utf8 = g_strdup (genre_str);
3372 /* convert tag from string to other type if required */
3373 tag_type = gst_tag_get_type (gst_tag_name);
3374 g_value_init (&tag_value, tag_type);
3375 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3376 GValue from_val = { 0, };
3378 g_value_init (&from_val, G_TYPE_STRING);
3379 g_value_set_string (&from_val, value_utf8);
3380 if (!g_value_transform (&from_val, &tag_value)) {
3381 GST_WARNING_OBJECT (demux,
3382 "Could not transform string tag to " "%s tag type %s",
3383 gst_tag_name, g_type_name (tag_type));
3384 g_value_unset (&tag_value);
3386 g_value_unset (&from_val);
3391 GST_DEBUG ("Setting metadata");
3392 g_value_init (&tag_value, G_TYPE_STRING);
3393 g_value_set_string (&tag_value, value_utf8);
3394 /* If we found a stereoscopic marker, look for StereoscopicLayout
3398 if (strncmp ("StereoscopicLayout", name_utf8,
3399 strlen (name_utf8)) == 0) {
3400 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3401 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3403 demux->asf_3D_mode =
3404 stereoscopic_layout_map[i].interleaving_type;
3405 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3409 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3411 demux->asf_3D_mode = GST_ASF_3D_NONE;
3412 GST_INFO_OBJECT (demux, "None 3d type");
3415 } else if (value_utf8 == NULL) {
3416 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3418 GST_DEBUG ("Skipping empty string value for %s",
3419 GST_STR_NULL (gst_tag_name));
3421 g_free (value_utf8);
3424 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3426 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3427 GST_FIXME ("Unhandled byte array tag %s",
3428 GST_STR_NULL (gst_tag_name));
3431 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3437 case ASF_DEMUX_DATA_TYPE_DWORD:{
3438 guint uint_val = GST_READ_UINT32_LE (value);
3440 /* this is the track number */
3441 g_value_init (&tag_value, G_TYPE_UINT);
3443 /* WM/Track counts from 0 */
3444 if (!strcmp (name_utf8, "WM/Track"))
3447 g_value_set_uint (&tag_value, uint_val);
3451 case ASF_DEMUX_DATA_TYPE_BOOL:{
3452 gboolean bool_val = GST_READ_UINT32_LE (value);
3454 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3456 GST_INFO_OBJECT (demux, "This is 3D contents");
3459 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3467 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3472 if (G_IS_VALUE (&tag_value)) {
3474 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3476 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3477 * is supposed to have a 0 base but is often wrongly written to start
3478 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3479 * replace the value added earlier from WM/Track or put it first in
3480 * the list, so that it will get picked up by _get_uint() */
3481 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3482 merge_mode = GST_TAG_MERGE_REPLACE;
3484 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3487 GST_DEBUG ("Setting global metadata %s", name_utf8);
3488 gst_structure_set_value (demux->global_metadata, name_utf8,
3492 g_value_unset (&tag_value);
3501 gst_asf_demux_add_global_tags (demux, taglist);
3508 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3509 gst_tag_list_unref (taglist);
3510 return GST_FLOW_OK; /* not really fatal */
3514 static GstStructure *
3515 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3520 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3522 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3525 s = gst_caps_get_structure (demux->metadata, i);
3526 if (gst_structure_has_name (s, sname))
3530 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3532 /* try lookup again; demux->metadata took ownership of the structure, so we
3533 * can't really make any assumptions about what happened to it, so we can't
3534 * just return it directly after appending it */
3535 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3538 static GstFlowReturn
3539 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3542 guint16 blockcount, i;
3544 GST_INFO_OBJECT (demux, "object is a metadata object");
3546 /* Content Descriptor Count */
3548 goto not_enough_data;
3550 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3552 for (i = 0; i < blockcount; ++i) {
3554 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3555 guint32 data_len, ival;
3558 if (size < (2 + 2 + 2 + 2 + 4))
3559 goto not_enough_data;
3561 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3562 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3563 name_len = gst_asf_demux_get_uint16 (&data, &size);
3564 data_type = gst_asf_demux_get_uint16 (&data, &size);
3565 data_len = gst_asf_demux_get_uint32 (&data, &size);
3567 if (size < name_len + data_len)
3568 goto not_enough_data;
3570 /* convert name to UTF-8 */
3571 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3573 gst_asf_demux_skip_bytes (name_len, &data, &size);
3575 if (name_utf8 == NULL) {
3576 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3577 gst_asf_demux_skip_bytes (data_len, &data, &size);
3581 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3582 gst_asf_demux_skip_bytes (data_len, &data, &size);
3590 goto not_enough_data;
3593 ival = gst_asf_demux_get_uint32 (&data, &size);
3595 /* skip anything else there may be, just in case */
3596 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3598 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3599 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3603 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3609 GST_WARNING ("Unexpected end of data parsing metadata object");
3610 return GST_FLOW_OK; /* not really fatal */
3614 static GstFlowReturn
3615 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3617 GstFlowReturn ret = GST_FLOW_OK;
3618 guint32 i, num_objects;
3619 guint8 unknown G_GNUC_UNUSED;
3621 /* Get the rest of the header's header */
3622 if (size < (4 + 1 + 1))
3623 goto not_enough_data;
3625 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3626 unknown = gst_asf_demux_get_uint8 (&data, &size);
3627 unknown = gst_asf_demux_get_uint8 (&data, &size);
3629 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3630 demux->saw_file_header = FALSE;
3631 /* Loop through the header's objects, processing those */
3632 for (i = 0; i < num_objects; ++i) {
3633 GST_INFO_OBJECT (demux, "reading header part %u", i);
3634 ret = gst_asf_demux_process_object (demux, &data, &size);
3635 if (ret != GST_FLOW_OK) {
3636 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3640 if (!demux->saw_file_header) {
3641 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3642 ("Header does not have mandatory FILE section"));
3643 return GST_FLOW_ERROR;
3650 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3651 ("short read parsing HEADER object"));
3652 return GST_FLOW_ERROR;
3656 static GstFlowReturn
3657 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3659 guint64 creation_time G_GNUC_UNUSED;
3660 guint64 file_size G_GNUC_UNUSED;
3661 guint64 send_time G_GNUC_UNUSED;
3662 guint64 packets_count, play_time, preroll;
3663 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3665 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3666 goto not_enough_data;
3668 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3669 file_size = gst_asf_demux_get_uint64 (&data, &size);
3670 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3671 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3672 play_time = gst_asf_demux_get_uint64 (&data, &size);
3673 send_time = gst_asf_demux_get_uint64 (&data, &size);
3674 preroll = gst_asf_demux_get_uint64 (&data, &size);
3675 flags = gst_asf_demux_get_uint32 (&data, &size);
3676 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3677 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3678 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3680 demux->broadcast = ! !(flags & 0x01);
3681 demux->seekable = ! !(flags & 0x02);
3683 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3684 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3685 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3687 if (demux->broadcast) {
3688 /* these fields are invalid if the broadcast flag is set */
3693 if (min_pktsize != max_pktsize)
3694 goto non_fixed_packet_size;
3696 demux->packet_size = max_pktsize;
3698 /* FIXME: do we need send_time as well? what is it? */
3699 if ((play_time * 100) >= (preroll * GST_MSECOND))
3700 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3702 demux->play_time = 0;
3704 demux->preroll = preroll * GST_MSECOND;
3706 /* initial latency */
3707 demux->latency = demux->preroll;
3709 if (demux->play_time == 0)
3710 demux->seekable = FALSE;
3712 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3713 GST_TIME_ARGS (demux->play_time));
3714 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3715 GST_TIME_ARGS (demux->preroll));
3717 if (demux->play_time > 0) {
3718 demux->segment.duration = demux->play_time;
3721 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3723 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3725 demux->saw_file_header = TRUE;
3730 non_fixed_packet_size:
3732 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3733 ("packet size must be fixed"));
3734 return GST_FLOW_ERROR;
3738 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3739 ("short read parsing FILE object"));
3740 return GST_FLOW_ERROR;
3744 /* Content Description Object */
3745 static GstFlowReturn
3746 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3750 const gchar *gst_tag;
3755 GST_TAG_TITLE, 0, NULL}, {
3756 GST_TAG_ARTIST, 0, NULL}, {
3757 GST_TAG_COPYRIGHT, 0, NULL}, {
3758 GST_TAG_DESCRIPTION, 0, NULL}, {
3759 GST_TAG_COMMENT, 0, NULL}
3761 GstTagList *taglist;
3762 GValue value = { 0 };
3766 GST_INFO_OBJECT (demux, "object is a comment");
3768 if (size < (2 + 2 + 2 + 2 + 2))
3769 goto not_enough_data;
3771 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3772 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3773 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3774 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3775 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3777 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3778 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3779 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3781 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3782 if (size < tags[i].val_length)
3783 goto not_enough_data;
3785 /* might be just '/0', '/0'... */
3786 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3787 /* convert to UTF-8 */
3788 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3789 "UTF-8", "UTF-16LE", &in, &out, NULL);
3791 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3794 /* parse metadata into taglist */
3795 taglist = gst_tag_list_new_empty ();
3796 g_value_init (&value, G_TYPE_STRING);
3797 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3798 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3799 g_value_set_string (&value, tags[i].val_utf8);
3800 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3801 tags[i].gst_tag, &value, NULL);
3804 g_value_unset (&value);
3806 gst_asf_demux_add_global_tags (demux, taglist);
3808 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3809 g_free (tags[i].val_utf8);
3815 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3816 "comment tag section %d, skipping comment object", i);
3817 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3818 g_free (tags[i].val_utf8);
3819 return GST_FLOW_OK; /* not really fatal */
3823 static GstFlowReturn
3824 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3827 guint16 num_streams, i;
3831 goto not_enough_data;
3833 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3835 GST_INFO ("object is a bitrate properties object with %u streams",
3838 if (size < (num_streams * (2 + 4)))
3839 goto not_enough_data;
3841 for (i = 0; i < num_streams; ++i) {
3845 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3846 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3848 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3849 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3850 stream = gst_asf_demux_get_stream (demux, stream_id);
3852 if (stream->pending_tags == NULL)
3853 stream->pending_tags = gst_tag_list_new_empty ();
3854 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3855 GST_TAG_BITRATE, bitrate, NULL);
3857 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3860 GST_WARNING ("stream id %u is too large", stream_id);
3868 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3869 return GST_FLOW_OK; /* not really fatal */
3873 static GstFlowReturn
3874 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3877 GstFlowReturn ret = GST_FLOW_OK;
3880 /* Get the rest of the header's header */
3881 if (size < (16 + 2 + 4))
3882 goto not_enough_data;
3884 /* skip GUID and two other bytes */
3885 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3886 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3888 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3890 /* FIXME: does data_size include the rest of the header that we have read? */
3891 if (hdr_size > size)
3892 goto not_enough_data;
3894 while (hdr_size > 0) {
3895 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3896 if (ret != GST_FLOW_OK)
3904 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3905 ("short read parsing extended header object"));
3906 return GST_FLOW_ERROR;
3910 static GstFlowReturn
3911 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3917 goto not_enough_data;
3919 if (demux->languages) {
3920 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3921 g_strfreev (demux->languages);
3922 demux->languages = NULL;
3923 demux->num_languages = 0;
3926 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3927 GST_LOG ("%u languages:", demux->num_languages);
3929 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3930 for (i = 0; i < demux->num_languages; ++i) {
3931 guint8 len, *lang_data = NULL;
3934 goto not_enough_data;
3935 len = gst_asf_demux_get_uint8 (&data, &size);
3936 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3939 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3942 /* truncate "en-us" etc. to just "en" */
3943 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3946 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3947 demux->languages[i] = utf8;
3950 goto not_enough_data;
3958 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3959 g_free (demux->languages);
3960 demux->languages = NULL;
3961 return GST_FLOW_OK; /* not fatal */
3965 static GstFlowReturn
3966 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3969 GstClockTime interval;
3972 if (size < (16 + 8 + 4 + 4))
3973 goto not_enough_data;
3976 gst_asf_demux_skip_bytes (16, &data, &size);
3977 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3978 gst_asf_demux_skip_bytes (4, &data, &size);
3979 count = gst_asf_demux_get_uint32 (&data, &size);
3981 demux->sidx_interval = interval;
3982 demux->sidx_num_entries = count;
3983 g_free (demux->sidx_entries);
3984 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3986 for (i = 0; i < count; ++i) {
3987 if (G_UNLIKELY (size < 6)) {
3988 /* adjust for broken files, to avoid having entries at the end
3989 * of the parsed index that point to time=0. Resulting in seeking to
3990 * the end of the file leading back to the beginning */
3991 demux->sidx_num_entries -= (count - i);
3994 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3995 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3996 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3997 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3998 demux->sidx_entries[i].count);
4001 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4008 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4009 return GST_FLOW_OK; /* not fatal */
4013 static GstFlowReturn
4014 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4015 guint8 * data, guint64 size)
4020 if (size < 16 + 2 + (2 * 2))
4021 goto not_enough_data;
4023 gst_asf_demux_get_guid (&guid, &data, &size);
4024 num = gst_asf_demux_get_uint16 (&data, &size);
4027 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4031 if (size < (num * sizeof (guint16)))
4032 goto not_enough_data;
4034 /* read mutually exclusive stream numbers */
4035 for (i = 0; i < num; ++i) {
4037 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4038 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4040 demux->mut_ex_streams =
4041 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4050 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4051 return GST_FLOW_OK; /* not absolutely fatal */
4056 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4058 return g_slist_find (demux->other_streams,
4059 GINT_TO_POINTER (stream_num)) == NULL;
4062 static GstFlowReturn
4063 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4066 AsfStreamExtProps esp;
4067 AsfStream *stream = NULL;
4068 AsfObject stream_obj;
4069 guint16 stream_name_count;
4070 guint16 num_payload_ext;
4072 guint8 *stream_obj_data = NULL;
4075 guint i, stream_num;
4078 obj_size = (guint) size;
4081 goto not_enough_data;
4084 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4085 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4086 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4087 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4088 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4089 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4090 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4091 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4092 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4093 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4094 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4095 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4096 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4097 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4098 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4100 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4101 GST_TIME_ARGS (esp.start_time));
4102 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4103 GST_TIME_ARGS (esp.end_time));
4104 GST_INFO ("flags = %08x", esp.flags);
4105 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4106 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4107 GST_INFO ("stream number = %u", stream_num);
4108 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4109 (esp.lang_idx < demux->num_languages) ?
4110 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4111 GST_INFO ("stream name count = %u", stream_name_count);
4113 /* read stream names */
4114 for (i = 0; i < stream_name_count; ++i) {
4115 guint16 stream_lang_idx G_GNUC_UNUSED;
4116 gchar *stream_name = NULL;
4119 goto not_enough_data;
4120 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4121 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4122 goto not_enough_data;
4123 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4124 g_free (stream_name); /* TODO: store names in struct */
4127 /* read payload extension systems stuff */
4128 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4130 if (num_payload_ext > 0)
4131 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4133 esp.payload_extensions = NULL;
4135 for (i = 0; i < num_payload_ext; ++i) {
4136 AsfPayloadExtension ext;
4138 guint32 sys_info_len;
4140 if (size < 16 + 2 + 4)
4141 goto not_enough_data;
4143 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4144 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4145 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4147 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4148 GST_LOG ("payload systems info len = %u", sys_info_len);
4149 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4150 goto not_enough_data;
4152 esp.payload_extensions[i] = ext;
4155 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4157 /* there might be an optional STREAM_INFO object here now; if not, we
4158 * should have parsed the corresponding stream info object already (since
4159 * we are parsing the extended stream properties objects delayed) */
4161 stream = gst_asf_demux_get_stream (demux, stream_num);
4165 if (size < ASF_OBJECT_HEADER_SIZE)
4166 goto not_enough_data;
4168 /* get size of the stream object */
4169 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4170 goto corrupted_stream;
4172 if (stream_obj.id != ASF_OBJ_STREAM)
4173 goto expected_stream_object;
4175 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4176 stream_obj.size > (10 * 1024 * 1024))
4177 goto not_enough_data;
4179 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4181 /* process this stream object later after all the other 'normal' ones
4182 * have been processed (since the others are more important/non-hidden) */
4183 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4184 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4185 goto not_enough_data;
4187 /* parse stream object */
4188 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4189 g_free (stream_obj_data);
4194 stream->ext_props = esp;
4196 /* try to set the framerate */
4197 if (stream->is_video && stream->caps) {
4198 GValue framerate = { 0 };
4202 g_value_init (&framerate, GST_TYPE_FRACTION);
4204 num = GST_SECOND / 100;
4205 denom = esp.avg_time_per_frame;
4207 /* avoid division by 0, assume 25/1 framerate */
4208 denom = GST_SECOND / 2500;
4211 gst_value_set_fraction (&framerate, num, denom);
4213 stream->caps = gst_caps_make_writable (stream->caps);
4214 s = gst_caps_get_structure (stream->caps, 0);
4215 gst_structure_set_value (s, "framerate", &framerate);
4216 g_value_unset (&framerate);
4217 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4218 num, denom, ((gdouble) num) / denom);
4221 /* add language info now if we have it */
4222 if (stream->ext_props.lang_idx < demux->num_languages) {
4223 if (stream->pending_tags == NULL)
4224 stream->pending_tags = gst_tag_list_new_empty ();
4225 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4226 demux->languages[stream->ext_props.lang_idx]);
4227 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4228 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4231 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4232 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4240 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4241 return GST_FLOW_OK; /* not absolutely fatal */
4243 expected_stream_object:
4245 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4246 "object: expected embedded stream object, but got %s object instead!",
4247 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4248 return GST_FLOW_OK; /* not absolutely fatal */
4252 GST_WARNING_OBJECT (demux, "Corrupted stream");
4253 return GST_FLOW_ERROR;
4257 static const gchar *
4258 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4262 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4263 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4264 nick += strlen ("ASF_OBJ_");
4266 if (demux->objpath == NULL) {
4267 demux->objpath = g_strdup (nick);
4271 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4272 g_free (demux->objpath);
4273 demux->objpath = newpath;
4276 return (const gchar *) demux->objpath;
4280 gst_asf_demux_pop_obj (GstASFDemux * demux)
4284 if ((s = g_strrstr (demux->objpath, "/"))) {
4287 g_free (demux->objpath);
4288 demux->objpath = NULL;
4293 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4298 /* Parse the queued extended stream property objects and add the info
4299 * to the existing streams or add the new embedded streams, but without
4300 * activating them yet */
4301 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4302 g_slist_length (demux->ext_stream_props));
4304 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4305 GstBuffer *buf = GST_BUFFER (l->data);
4308 gst_buffer_map (buf, &map, GST_MAP_READ);
4310 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4311 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4312 gst_buffer_unmap (buf, &map);
4313 gst_buffer_unref (buf);
4315 g_slist_free (demux->ext_stream_props);
4316 demux->ext_stream_props = NULL;
4321 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4325 for (i = 0; i < demux->num_streams; ++i) {
4330 stream = &demux->stream[i];
4332 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4334 if (stream->active) {
4335 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4340 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4343 /* check for each mutual exclusion whether it affects this stream */
4344 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4345 if (*mes == stream->id) {
4346 /* if yes, check if we've already added streams that are mutually
4347 * exclusive with the stream we're about to add */
4348 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4349 for (j = 0; j < demux->num_streams; ++j) {
4350 /* if the broadcast flag is set, assume the hidden streams aren't
4351 * actually streamed and hide them (or playbin won't work right),
4352 * otherwise assume their data is available */
4353 if (demux->stream[j].id == *mes && demux->broadcast) {
4355 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4356 "mutually exclusive with already existing stream ID %d, "
4357 "hiding stream", stream->id, demux->stream[j].id);
4369 /* FIXME: we should do stream activation based on preroll data in
4370 * streaming mode too */
4371 if (demux->streaming && !is_hidden)
4372 gst_asf_demux_activate_stream (demux, stream);
4377 static GstFlowReturn
4378 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4381 GstFlowReturn ret = GST_FLOW_OK;
4383 guint64 obj_data_size;
4385 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4386 return ASF_FLOW_NEED_MORE_DATA;
4388 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4390 return GST_FLOW_ERROR;
4391 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4393 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4395 if (*p_size < obj_data_size)
4396 return ASF_FLOW_NEED_MORE_DATA;
4398 gst_asf_demux_push_obj (demux, obj.id);
4400 GST_INFO ("%s: size %u", demux->objpath, obj.size);
4403 case ASF_OBJ_STREAM:
4404 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4408 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4410 case ASF_OBJ_HEADER:
4411 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4413 case ASF_OBJ_COMMENT:
4414 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4417 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4419 case ASF_OBJ_BITRATE_PROPS:
4421 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4424 case ASF_OBJ_EXT_CONTENT_DESC:
4426 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4429 case ASF_OBJ_METADATA_OBJECT:
4430 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4432 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4435 /* process these later, we might not have parsed the corresponding
4436 * stream object yet */
4437 GST_LOG ("%s: queued for later parsing", demux->objpath);
4438 buf = gst_buffer_new_and_alloc (obj_data_size);
4439 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4440 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4444 case ASF_OBJ_LANGUAGE_LIST:
4445 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4447 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4448 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4451 case ASF_OBJ_SIMPLE_INDEX:
4452 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4454 case ASF_OBJ_CONTENT_ENCRYPTION:
4455 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4456 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4457 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4458 goto error_encrypted;
4459 case ASF_OBJ_CONCEAL_NONE:
4461 case ASF_OBJ_UNDEFINED:
4462 case ASF_OBJ_CODEC_COMMENT:
4464 case ASF_OBJ_PADDING:
4465 case ASF_OBJ_BITRATE_MUTEX:
4466 case ASF_OBJ_COMPATIBILITY:
4467 case ASF_OBJ_INDEX_PLACEHOLDER:
4468 case ASF_OBJ_INDEX_PARAMETERS:
4469 case ASF_OBJ_STREAM_PRIORITIZATION:
4470 case ASF_OBJ_SCRIPT_COMMAND:
4471 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4473 /* Unknown/unhandled object, skip it and hope for the best */
4474 GST_INFO ("%s: skipping object", demux->objpath);
4479 /* this can't fail, we checked the number of bytes available before */
4480 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4482 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4484 gst_asf_demux_pop_obj (demux);
4491 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4492 return GST_FLOW_ERROR;
4497 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4498 GstBuffer ** p_buffer)
4500 GstBuffer *descrambled_buffer;
4501 GstBuffer *scrambled_buffer;
4502 GstBuffer *sub_buffer;
4509 /* descrambled_buffer is initialised in the first iteration */
4510 descrambled_buffer = NULL;
4511 scrambled_buffer = *p_buffer;
4513 if (gst_buffer_get_size (scrambled_buffer) <
4514 stream->ds_packet_size * stream->span)
4517 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4518 offset += stream->ds_chunk_size) {
4519 off = offset / stream->ds_chunk_size;
4520 row = off / stream->span;
4521 col = off % stream->span;
4522 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4523 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4524 col, off, stream->ds_chunk_size);
4525 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4526 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4527 stream->span, stream->ds_packet_size);
4528 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4529 gst_buffer_get_size (scrambled_buffer));
4531 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4532 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4534 descrambled_buffer = sub_buffer;
4536 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4540 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4541 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4542 GST_BUFFER_DURATION (descrambled_buffer) =
4543 GST_BUFFER_DURATION (scrambled_buffer);
4544 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4545 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4546 GST_BUFFER_OFFSET_END (scrambled_buffer);
4548 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4550 gst_buffer_unref (scrambled_buffer);
4551 *p_buffer = descrambled_buffer;
4555 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4557 GstASFDemux *demux = GST_ASF_DEMUX (element);
4560 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4562 for (i = 0; i < demux->num_streams; ++i) {
4563 gst_event_ref (event);
4564 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4565 GST_OBJECT_CAST (element), event)) {
4566 gst_event_unref (event);
4571 gst_event_unref (event);
4575 /* takes ownership of the passed event */
4577 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4579 gboolean ret = TRUE;
4582 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4583 GST_EVENT_TYPE_NAME (event));
4585 for (i = 0; i < demux->num_streams; ++i) {
4586 gst_event_ref (event);
4587 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4589 gst_event_unref (event);
4594 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4598 gboolean res = FALSE;
4600 demux = GST_ASF_DEMUX (parent);
4602 GST_DEBUG ("handling %s query",
4603 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4605 switch (GST_QUERY_TYPE (query)) {
4606 case GST_QUERY_DURATION:
4610 gst_query_parse_duration (query, &format, NULL);
4612 if (format != GST_FORMAT_TIME) {
4613 GST_LOG ("only support duration queries in TIME format");
4617 res = gst_pad_query_default (pad, parent, query);
4619 GST_OBJECT_LOCK (demux);
4621 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4622 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4623 GST_TIME_ARGS (demux->segment.duration));
4625 gst_query_set_duration (query, GST_FORMAT_TIME,
4626 demux->segment.duration);
4630 GST_LOG ("duration not known yet");
4633 GST_OBJECT_UNLOCK (demux);
4638 case GST_QUERY_POSITION:{
4641 gst_query_parse_position (query, &format, NULL);
4643 if (format != GST_FORMAT_TIME) {
4644 GST_LOG ("only support position queries in TIME format");
4648 GST_OBJECT_LOCK (demux);
4650 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4651 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4652 GST_TIME_ARGS (demux->segment.position));
4654 gst_query_set_position (query, GST_FORMAT_TIME,
4655 demux->segment.position);
4659 GST_LOG ("position not known yet");
4662 GST_OBJECT_UNLOCK (demux);
4666 case GST_QUERY_SEEKING:{
4669 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4670 if (format == GST_FORMAT_TIME) {
4673 GST_OBJECT_LOCK (demux);
4674 duration = demux->segment.duration;
4675 GST_OBJECT_UNLOCK (demux);
4677 if (!demux->streaming || !demux->seekable) {
4678 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4685 /* try upstream first in TIME */
4686 res = gst_pad_query_default (pad, parent, query);
4688 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4689 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4690 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4691 /* if no luck, maybe in BYTES */
4692 if (!seekable || fmt != GST_FORMAT_TIME) {
4695 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4696 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4697 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4698 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4699 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4700 if (fmt != GST_FORMAT_BYTES)
4703 gst_query_unref (q);
4704 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4710 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4714 case GST_QUERY_LATENCY:
4717 GstClockTime min, max;
4719 /* preroll delay does not matter in non-live pipeline,
4720 * but we might end up in a live (rtsp) one ... */
4723 res = gst_pad_query_default (pad, parent, query);
4727 gst_query_parse_latency (query, &live, &min, &max);
4729 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4730 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4731 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4733 GST_OBJECT_LOCK (demux);
4734 min += demux->latency;
4736 max += demux->latency;
4737 GST_OBJECT_UNLOCK (demux);
4739 gst_query_set_latency (query, live, min, max);
4742 case GST_QUERY_SEGMENT:
4747 format = demux->segment.format;
4750 gst_segment_to_stream_time (&demux->segment, format,
4751 demux->segment.start);
4752 if ((stop = demux->segment.stop) == -1)
4753 stop = demux->segment.duration;
4755 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4757 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4762 res = gst_pad_query_default (pad, parent, query);
4769 static GstStateChangeReturn
4770 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4772 GstASFDemux *demux = GST_ASF_DEMUX (element);
4773 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4775 switch (transition) {
4776 case GST_STATE_CHANGE_NULL_TO_READY:{
4777 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4778 demux->need_newsegment = TRUE;
4779 demux->segment_running = FALSE;
4780 demux->keyunit_sync = FALSE;
4781 demux->accurate = FALSE;
4782 demux->adapter = gst_adapter_new ();
4783 demux->metadata = gst_caps_new_empty ();
4784 demux->global_metadata = gst_structure_new_empty ("metadata");
4785 demux->data_size = 0;
4786 demux->data_offset = 0;
4787 demux->index_offset = 0;
4788 demux->base_offset = 0;
4789 demux->flowcombiner = gst_flow_combiner_new ();
4797 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4798 if (ret == GST_STATE_CHANGE_FAILURE)
4801 switch (transition) {
4802 case GST_STATE_CHANGE_PAUSED_TO_READY:
4803 gst_asf_demux_reset (demux, FALSE);
4806 case GST_STATE_CHANGE_READY_TO_NULL:
4807 gst_asf_demux_reset (demux, FALSE);
4808 gst_flow_combiner_free (demux->flowcombiner);
4809 demux->flowcombiner = NULL;