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 void 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_pad_template (gstelement_class,
132 gst_static_pad_template_get (&audio_src_template));
133 gst_element_class_add_pad_template (gstelement_class,
134 gst_static_pad_template_get (&video_src_template));
135 gst_element_class_add_pad_template (gstelement_class,
136 gst_static_pad_template_get (&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 GST_OBJECT_UNLOCK (demux);
433 gst_event_unref (event);
439 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
440 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
441 (_("This stream contains no data.")),
442 ("got eos and didn't receive a complete header object"));
445 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
446 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
447 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
448 (_("Internal data stream error.")),
449 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
453 GST_OBJECT_LOCK (demux);
454 gst_adapter_clear (demux->adapter);
455 GST_OBJECT_UNLOCK (demux);
456 gst_asf_demux_send_event_unlocked (demux, event);
460 case GST_EVENT_FLUSH_STOP:
461 GST_OBJECT_LOCK (demux);
462 gst_asf_demux_reset_stream_state_after_discont (demux);
463 GST_OBJECT_UNLOCK (demux);
464 gst_asf_demux_send_event_unlocked (demux, event);
465 /* upon activation, latency is no longer introduced, e.g. after seek */
466 if (demux->activated_streams)
471 ret = gst_pad_event_default (pad, parent, event);
479 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
480 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
481 gboolean next, gboolean * eos)
483 GstClockTime idx_time;
489 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
492 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
495 /* if we want the next keyframe, we have to go forward till we find
496 a different packet number */
498 if (idx >= demux->sidx_num_entries - 1) {
499 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
504 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
505 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
512 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
518 *packet = demux->sidx_entries[idx].packet;
520 *speed = demux->sidx_entries[idx].count;
522 /* so we get closer to the actual time of the packet ... actually, let's not
523 * do this, since we throw away superfluous payloads before the seek position
524 * anyway; this way, our key unit seek 'snap resolution' is a bit better
525 * (ie. same as index resolution) */
527 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
531 idx_time = demux->sidx_interval * idx;
532 if (G_LIKELY (idx_time >= demux->preroll))
533 idx_time -= demux->preroll;
535 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
536 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
537 GST_TIME_ARGS (idx_time));
539 if (G_LIKELY (p_idx_time))
540 *p_idx_time = idx_time;
546 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
550 gst_adapter_clear (demux->adapter);
552 GST_DEBUG_OBJECT (demux, "reset stream state");
554 gst_flow_combiner_reset (demux->flowcombiner);
555 for (n = 0; n < demux->num_streams; n++) {
556 demux->stream[n].discont = TRUE;
557 demux->stream[n].first_buffer = TRUE;
559 while (demux->stream[n].payloads->len > 0) {
563 last = demux->stream[n].payloads->len - 1;
564 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
565 gst_buffer_replace (&payload->buf, NULL);
566 g_array_remove_index (demux->stream[n].payloads, last);
572 gst_asf_demux_mark_discont (GstASFDemux * demux)
576 GST_DEBUG_OBJECT (demux, "Mark stream discont");
578 for (n = 0; n < demux->num_streams; n++)
579 demux->stream[n].discont = TRUE;
582 /* do a seek in push based mode */
584 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
589 GstSeekType cur_type, stop_type;
593 GstEvent *byte_event;
595 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
598 stop_type = GST_SEEK_TYPE_NONE;
601 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
603 /* determine packet, by index or by estimation */
604 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
607 (guint) gst_util_uint64_scale (demux->num_packets, cur,
611 if (packet > demux->num_packets) {
612 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
617 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
619 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
621 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
622 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
623 /* BYTE seek event */
624 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
625 cur, stop_type, stop);
626 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
627 res = gst_pad_push_event (demux->sinkpad, byte_event);
633 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
635 GstClockTime idx_time;
638 GstSeekType cur_type, stop_type;
640 gboolean only_need_update;
641 gboolean after, before, next;
646 guint packet, speed_count = 1;
652 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
655 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
656 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
660 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
661 * so first try to let it handle the seek event. */
662 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
665 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
666 demux->num_packets == 0 || demux->play_time == 0)) {
667 GST_LOG_OBJECT (demux, "stream is not seekable");
671 if (G_UNLIKELY (!demux->activated_streams)) {
672 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
676 if (G_UNLIKELY (rate <= 0.0)) {
677 GST_LOG_OBJECT (demux, "backward playback");
678 demux->seek_to_cur_pos = TRUE;
679 for (i = 0; i < demux->num_streams; i++) {
680 demux->stream[i].reverse_kf_ready = FALSE;
684 seqnum = gst_event_get_seqnum (event);
685 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
687 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
688 demux->keyunit_sync =
689 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
690 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
691 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
692 next = after && !before;
694 if (G_UNLIKELY (demux->streaming)) {
695 /* support it safely needs more segment handling, e.g. closing etc */
697 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
700 /* we can (re)construct the start later on, but not the end */
701 if (stop_type != GST_SEEK_TYPE_NONE &&
702 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
703 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
706 return gst_asf_demux_handle_seek_push (demux, event);
709 /* unlock the streaming thread */
710 if (G_LIKELY (flush)) {
711 fevent = gst_event_new_flush_start ();
713 gst_event_set_seqnum (fevent, seqnum);
714 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
715 gst_asf_demux_send_event_unlocked (demux, fevent);
717 gst_pad_pause_task (demux->sinkpad);
720 /* grab the stream lock so that streaming cannot continue, for
721 * non flushing seeks when the element is in PAUSED this could block
723 GST_PAD_STREAM_LOCK (demux->sinkpad);
725 /* we now can stop flushing, since we have the stream lock now */
726 fevent = gst_event_new_flush_stop (TRUE);
727 gst_event_set_seqnum (fevent, seqnum);
728 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
730 if (G_LIKELY (flush))
731 gst_asf_demux_send_event_unlocked (demux, fevent);
733 gst_event_unref (fevent);
735 /* operating on copy of segment until we know the seek worked */
736 segment = demux->segment;
738 if (G_UNLIKELY (demux->segment_running && !flush)) {
739 GstSegment newsegment;
742 /* create the segment event to close the current segment */
743 gst_segment_copy_into (&segment, &newsegment);
744 newseg = gst_event_new_segment (&newsegment);
745 gst_event_set_seqnum (newseg, seqnum);
747 gst_asf_demux_send_event_unlocked (demux, newseg);
750 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
751 cur, stop_type, stop, &only_need_update);
753 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
754 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
756 if (cur_type != GST_SEEK_TYPE_SET)
757 seek_time = segment.start;
761 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
762 * real start of data and segment_start to indexed time for key unit seek*/
763 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
764 &idx_time, &speed_count, next, &eos))) {
768 demux->packet = demux->num_packets;
772 /* First try to query our source to see if it can convert for us. This is
773 the case when our source is an mms stream, notice that in this case
774 gstmms will do a time based seek to get the byte offset, this is not a
775 problem as the seek to this offset needs to happen anway. */
776 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
777 GST_FORMAT_BYTES, &offset)) {
778 packet = (offset - demux->data_offset) / demux->packet_size;
779 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
780 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
781 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
782 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
783 demux->packet_size, packet);
785 /* FIXME: For streams containing video, seek to an earlier position in
786 * the hope of hitting a keyframe and let the sinks throw away the stuff
787 * before the segment start. For audio-only this is unnecessary as every
789 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
790 && demux->num_video_streams > 0) {
791 seek_time -= 5 * GST_SECOND;
796 packet = (guint) gst_util_uint64_scale (demux->num_packets,
797 seek_time, demux->play_time);
799 if (packet > demux->num_packets)
800 packet = demux->num_packets;
803 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
804 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
805 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
806 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
807 segment.start = idx_time;
808 segment.position = idx_time;
809 segment.time = idx_time;
813 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
815 GST_OBJECT_LOCK (demux);
816 demux->segment = segment;
817 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
818 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
819 stop, demux->play_time);
821 demux->packet = packet;
824 demux->need_newsegment = TRUE;
825 demux->segment_seqnum = seqnum;
826 demux->speed_packets =
827 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
828 gst_asf_demux_reset_stream_state_after_discont (demux);
829 GST_OBJECT_UNLOCK (demux);
832 /* restart our task since it might have been stopped when we did the flush */
833 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
836 /* streaming can continue now */
837 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
843 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
849 demux = GST_ASF_DEMUX (parent);
851 switch (GST_EVENT_TYPE (event)) {
853 GST_LOG_OBJECT (pad, "seek event");
854 ret = gst_asf_demux_handle_seek_event (demux, event);
855 gst_event_unref (event);
858 case GST_EVENT_NAVIGATION:
859 /* just drop these two silently */
860 gst_event_unref (event);
864 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
865 ret = gst_pad_event_default (pad, parent, event);
872 static inline guint32
873 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
877 ret = gst_asf_identify_guid (guids, guid);
879 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
880 gst_asf_get_guid_nick (guids, ret),
881 guid->v1, guid->v2, guid->v3, guid->v4);
893 /* expect is true when the user is expeting an object,
894 * when false, it will give no warnings if the object
898 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
899 guint data_len, AsfObject * object, gboolean expect)
903 if (data_len < ASF_OBJECT_HEADER_SIZE)
906 guid.v1 = GST_READ_UINT32_LE (data + 0);
907 guid.v2 = GST_READ_UINT32_LE (data + 4);
908 guid.v3 = GST_READ_UINT32_LE (data + 8);
909 guid.v4 = GST_READ_UINT32_LE (data + 12);
911 object->size = GST_READ_UINT64_LE (data + 16);
913 /* FIXME: make asf_demux_identify_object_guid() */
914 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
915 if (object->id == ASF_OBJ_UNDEFINED && expect) {
916 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
917 guid.v1, guid.v2, guid.v3, guid.v4);
924 gst_asf_demux_release_old_pads (GstASFDemux * demux)
926 GST_DEBUG_OBJECT (demux, "Releasing old pads");
928 while (demux->old_num_streams > 0) {
929 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
930 gst_event_new_eos ());
931 gst_asf_demux_free_stream (demux,
932 &demux->old_stream[demux->old_num_streams - 1]);
933 --demux->old_num_streams;
935 memset (demux->old_stream, 0, sizeof (demux->old_stream));
936 demux->old_num_streams = 0;
940 gst_asf_demux_chain_headers (GstASFDemux * demux)
944 guint8 *header_data, *data = NULL;
945 const guint8 *cdata = NULL;
948 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
952 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
953 if (obj.id != ASF_OBJ_HEADER)
956 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
958 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
959 if (gst_adapter_available (demux->adapter) < obj.size + 50)
962 data = gst_adapter_take (demux->adapter, obj.size + 50);
965 header_size = obj.size;
966 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
967 if (flow != GST_FLOW_OK)
970 /* calculate where the packet data starts */
971 demux->data_offset = obj.size + 50;
973 /* now parse the beginning of the ASF_OBJ_DATA object */
974 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
977 if (demux->num_streams == 0)
986 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
993 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
994 ("This doesn't seem to be an ASF file"));
996 return GST_FLOW_ERROR;
1001 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1002 ("header parsing failed, or no streams found, flow = %s",
1003 gst_flow_get_name (flow)));
1005 return GST_FLOW_ERROR;
1010 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1011 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1016 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1019 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1021 if (G_LIKELY (p_flow))
1024 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1025 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1026 "+%u", gst_flow_get_name (flow), offset, size);
1031 g_assert (*p_buf != NULL);
1033 buffer_size = gst_buffer_get_size (*p_buf);
1034 if (G_UNLIKELY (buffer_size < size)) {
1035 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1036 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1037 gst_buffer_unref (*p_buf);
1038 if (G_LIKELY (p_flow))
1039 *p_flow = GST_FLOW_EOS;
1048 gst_asf_demux_pull_indices (GstASFDemux * demux)
1050 GstBuffer *buf = NULL;
1054 offset = demux->index_offset;
1056 if (G_UNLIKELY (offset == 0)) {
1057 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1061 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1067 gst_buffer_map (buf, &map, GST_MAP_READ);
1068 g_assert (map.size >= 16 + 8);
1069 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1070 gst_buffer_unmap (buf, &map);
1071 gst_buffer_replace (&buf, NULL);
1073 /* check for sanity */
1074 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1075 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1079 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1083 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1084 ", size %u", offset, (guint) obj.size);
1086 offset += obj.size; /* increase before _process_object changes it */
1088 gst_buffer_map (buf, &map, GST_MAP_READ);
1089 g_assert (map.size >= obj.size);
1090 bufdata = (guint8 *) map.data;
1091 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1092 gst_buffer_unmap (buf, &map);
1093 gst_buffer_replace (&buf, NULL);
1095 if (G_UNLIKELY (flow != GST_FLOW_OK))
1100 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1104 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1108 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1109 if (obj.id != ASF_OBJ_DATA) {
1110 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1114 demux->state = GST_ASF_DEMUX_STATE_DATA;
1116 if (!demux->broadcast && obj.size > 50) {
1117 demux->data_size = obj.size - 50;
1118 /* CHECKME: for at least one file this is off by +158 bytes?! */
1119 demux->index_offset = demux->data_offset + demux->data_size;
1121 demux->data_size = 0;
1122 demux->index_offset = 0;
1127 if (!demux->broadcast) {
1128 /* skip object header (24 bytes) and file GUID (16 bytes) */
1129 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1131 demux->num_packets = 0;
1134 if (demux->num_packets == 0)
1135 demux->seekable = FALSE;
1137 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1138 if (demux->data_size == 0 && demux->num_packets > 0) {
1139 demux->data_size = demux->num_packets * demux->packet_size;
1140 demux->index_offset = demux->data_offset + demux->data_size;
1143 /* process pending stream objects and create pads for those */
1144 gst_asf_demux_process_queued_extended_stream_objects (demux);
1146 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1147 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1148 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1149 demux->data_offset, demux->data_size, demux->index_offset);
1155 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1157 GstFlowReturn flow = GST_FLOW_OK;
1159 GstBuffer *buf = NULL;
1164 GST_LOG_OBJECT (demux, "reading headers");
1166 /* pull HEADER object header, so we know its size */
1167 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1170 gst_buffer_map (buf, &map, GST_MAP_READ);
1171 g_assert (map.size >= 16 + 8);
1172 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1173 gst_buffer_unmap (buf, &map);
1174 gst_buffer_replace (&buf, NULL);
1176 if (obj.id != ASF_OBJ_HEADER)
1179 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1181 /* pull HEADER object */
1182 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1186 size = obj.size; /* don't want obj.size changed */
1187 gst_buffer_map (buf, &map, GST_MAP_READ);
1188 g_assert (map.size >= size);
1189 bufdata = (guint8 *) map.data;
1190 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1191 gst_buffer_unmap (buf, &map);
1192 gst_buffer_replace (&buf, NULL);
1194 if (flow != GST_FLOW_OK) {
1195 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1199 /* calculate where the packet data starts */
1200 demux->data_offset = demux->base_offset + obj.size + 50;
1202 /* now pull beginning of DATA object before packet data */
1203 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1207 gst_buffer_map (buf, &map, GST_MAP_READ);
1208 g_assert (map.size >= size);
1209 bufdata = (guint8 *) map.data;
1210 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1213 if (demux->num_streams == 0)
1216 gst_buffer_unmap (buf, &map);
1217 gst_buffer_replace (&buf, NULL);
1225 gst_buffer_unmap (buf, &map);
1226 gst_buffer_replace (&buf, NULL);
1228 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1229 ("This doesn't seem to be an ASF file"));
1230 *pflow = GST_FLOW_ERROR;
1235 flow = GST_FLOW_ERROR;
1236 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1237 ("header parsing failed, or no streams found, flow = %s",
1238 gst_flow_get_name (flow)));
1243 gst_buffer_unmap (buf, &map);
1244 gst_buffer_replace (&buf, NULL);
1251 all_streams_prerolled (GstASFDemux * demux)
1253 GstClockTime preroll_time;
1254 guint i, num_no_data = 0;
1256 /* Allow at least 500ms of preroll_time */
1257 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1259 /* returns TRUE as long as there isn't a stream which (a) has data queued
1260 * and (b) the timestamp of last piece of data queued is < demux->preroll
1261 * AND there is at least one other stream with data queued */
1262 for (i = 0; i < demux->num_streams; ++i) {
1263 AsfPayload *last_payload = NULL;
1267 stream = &demux->stream[i];
1268 if (G_UNLIKELY (stream->payloads->len == 0)) {
1270 GST_LOG_OBJECT (stream->pad, "no data queued");
1274 /* find last payload with timestamp */
1275 for (last_idx = stream->payloads->len - 1;
1276 last_idx >= 0 && (last_payload == NULL
1277 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1278 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1281 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1282 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1283 GST_TIME_ARGS (preroll_time));
1284 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1285 || last_payload->ts <= preroll_time)) {
1286 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1291 if (G_UNLIKELY (num_no_data > 0))
1299 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1304 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1307 /* check for each mutual exclusion group whether it affects this stream */
1308 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1309 if (*mes == stream->id) {
1310 /* we are in this group; let's check if we've already activated streams
1311 * that are in the same group (and hence mutually exclusive to this
1313 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1316 for (i = 0; i < demux->num_streams; ++i) {
1317 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1318 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1319 "to already active stream with ID %d", stream->id,
1320 demux->stream[i].id);
1325 /* we can only be in this group once, let's break out and move on to
1326 * the next mutual exclusion group */
1337 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1339 /* remember the first queued timestamp for the segment */
1340 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1341 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1342 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1343 GST_TIME_ARGS (demux->first_ts));
1344 demux->segment_ts = payload_ts;
1345 /* always note, but only determines segment when streaming */
1346 if (demux->streaming)
1347 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1348 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1349 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1354 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1356 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1357 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1360 /* go trhough each stream, find smallest timestamp */
1361 for (i = 0; i < demux->num_streams; ++i) {
1364 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1365 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1366 stream = &demux->stream[i];
1368 for (j = 0; j < stream->payloads->len; ++j) {
1369 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1370 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1371 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1372 || stream_min_ts > payload->ts)) {
1373 stream_min_ts = payload->ts;
1375 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1376 payload->ts > stream_min_ts &&
1377 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1378 || stream_min_ts2 > payload->ts)) {
1379 stream_min_ts2 = payload->ts;
1383 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1384 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1385 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1386 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1387 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1389 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1392 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1393 stream_min_ts = stream_min_ts2;
1395 /* if we don't have timestamp for this stream, wait for more data */
1396 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1399 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1400 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1401 first_ts = stream_min_ts;
1404 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1407 demux->first_ts = first_ts;
1409 /* update packets queued before we knew first timestamp */
1410 for (i = 0; i < demux->num_streams; ++i) {
1413 stream = &demux->stream[i];
1415 for (j = 0; j < stream->payloads->len; ++j) {
1416 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1417 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1418 if (payload->ts > first_ts)
1419 payload->ts -= first_ts;
1427 gst_asf_demux_check_segment_ts (demux, 0);
1433 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1435 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1436 and often set wrong, inspecting the data is the only way that seem to be working */
1437 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1438 GstCaps *caps = NULL;
1440 GstAdapter *adapter = gst_adapter_new ();
1442 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1444 AsfPayload *payload;
1447 payload = &g_array_index (stream->payloads, AsfPayload, i);
1448 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1449 len = gst_adapter_available (adapter);
1450 data = gst_adapter_map (adapter, len);
1454 #define MIN_LENGTH 128
1456 /* look for the sync points */
1458 if (len < MIN_LENGTH || /* give typefind something to work on */
1459 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1460 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1466 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1469 if (prob < GST_TYPE_FIND_LIKELY) {
1472 if (len > MIN_LENGTH)
1473 /* this wasn't it, look for another sync point */
1477 gst_adapter_unmap (adapter);
1480 gst_object_unref (adapter);
1483 gst_caps_take (&stream->caps, caps);
1491 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1495 if (demux->activated_streams)
1498 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1501 if (!all_streams_prerolled (demux) && !force) {
1502 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1506 for (i = 0; i < demux->num_streams; ++i) {
1507 AsfStream *stream = &demux->stream[i];
1509 if (stream->payloads->len > 0) {
1511 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1512 !stream->active && /* do not inspect active streams (caps were already set) */
1513 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1514 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1515 /* try to gather some more data */
1518 /* we don't check mutual exclusion stuff here; either we have data for
1519 * a stream, then we active it, or we don't, then we'll ignore it */
1520 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1521 gst_asf_demux_activate_stream (demux, stream);
1523 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1527 gst_asf_demux_release_old_pads (demux);
1529 demux->activated_streams = TRUE;
1530 GST_LOG_OBJECT (demux, "signalling no more pads");
1531 gst_element_no_more_pads (GST_ELEMENT (demux));
1535 /* returns the stream that has a complete payload with the lowest timestamp
1536 * queued, or NULL (we push things by timestamp because during the internal
1537 * prerolling we might accumulate more data then the external queues can take,
1538 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1540 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1542 AsfPayload *best_payload = NULL;
1543 AsfStream *best_stream = NULL;
1546 for (i = 0; i < demux->num_streams; ++i) {
1550 stream = &demux->stream[i];
1552 /* Don't push any data until we have at least one payload that falls within
1553 * the current segment. This way we can remove out-of-segment payloads that
1554 * don't need to be decoded after a seek, sending only data from the
1555 * keyframe directly before our segment start */
1556 if (stream->payloads->len > 0) {
1557 AsfPayload *payload = NULL;
1560 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1561 /* Reverse playback */
1563 if (stream->is_video) {
1564 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1565 if (stream->reverse_kf_ready) {
1567 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1568 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1569 /* TODO : remove payload from the list? */
1576 /* find first complete payload with timestamp */
1577 for (j = stream->payloads->len - 1;
1578 j >= 0 && (payload == NULL
1579 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1580 payload = &g_array_index (stream->payloads, AsfPayload, j);
1583 /* If there's a complete payload queued for this stream */
1584 if (!gst_asf_payload_is_complete (payload))
1590 /* find last payload with timestamp */
1591 for (last_idx = stream->payloads->len - 1;
1592 last_idx >= 0 && (payload == NULL
1593 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1594 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1597 /* if this is first payload after seek we might need to update the segment */
1598 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1599 gst_asf_demux_check_segment_ts (demux, payload->ts);
1601 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1602 (payload->ts < demux->segment.start))) {
1603 if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1604 && payload->keyframe)) {
1605 GST_DEBUG_OBJECT (stream->pad,
1606 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1607 GST_TIME_ARGS (payload->ts));
1608 demux->segment.start = payload->ts;
1609 demux->segment.time = payload->ts;
1611 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1612 GST_TIME_FORMAT " which is before our segment start %"
1613 GST_TIME_FORMAT ", not pushing yet",
1614 GST_TIME_ARGS (payload->ts),
1615 GST_TIME_ARGS (demux->segment.start));
1620 /* find first complete payload with timestamp */
1622 j < stream->payloads->len && (payload == NULL
1623 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1624 payload = &g_array_index (stream->payloads, AsfPayload, j);
1627 /* Now see if there's a complete payload queued for this stream */
1628 if (!gst_asf_payload_is_complete (payload))
1632 /* ... and whether its timestamp is lower than the current best */
1633 if (best_stream == NULL || best_payload->ts > payload->ts) {
1634 best_stream = stream;
1635 best_payload = payload;
1643 static GstFlowReturn
1644 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1647 GstFlowReturn ret = GST_FLOW_OK;
1649 if (G_UNLIKELY (!demux->activated_streams)) {
1650 if (!gst_asf_demux_check_activate_streams (demux, force))
1652 /* streams are now activated */
1655 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1656 AsfPayload *payload;
1657 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1658 GstClockTime duration = GST_CLOCK_TIME_NONE;
1660 /* wait until we had a chance to "lock on" some payload's timestamp */
1661 if (G_UNLIKELY (demux->need_newsegment
1662 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1665 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1666 && stream->payloads->len) {
1667 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1669 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1672 /* do we need to send a newsegment event */
1673 if ((G_UNLIKELY (demux->need_newsegment))) {
1674 GstEvent *segment_event;
1676 /* safe default if insufficient upstream info */
1677 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1680 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1681 demux->segment.duration > 0) {
1682 /* slight HACK; prevent clipping of last bit */
1683 demux->segment.stop = demux->segment.duration + demux->in_gap;
1686 /* FIXME : only if ACCURATE ! */
1687 if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1688 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1689 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1690 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1691 GST_TIME_ARGS (payload->ts));
1692 demux->segment.start = payload->ts;
1693 demux->segment.time = payload->ts;
1696 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1699 /* note: we fix up all timestamps to start from 0, so this should be ok */
1700 segment_event = gst_event_new_segment (&demux->segment);
1701 if (demux->segment_seqnum)
1702 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1703 gst_asf_demux_send_event_unlocked (demux, segment_event);
1705 /* now post any global tags we may have found */
1706 if (demux->taglist == NULL) {
1707 demux->taglist = gst_tag_list_new_empty ();
1708 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1711 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1712 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1714 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1715 gst_asf_demux_send_event_unlocked (demux,
1716 gst_event_new_tag (demux->taglist));
1717 demux->taglist = NULL;
1719 demux->need_newsegment = FALSE;
1720 demux->segment_seqnum = 0;
1721 demux->segment_running = TRUE;
1724 /* Do we have tags pending for this stream? */
1725 if (G_UNLIKELY (stream->pending_tags)) {
1726 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1727 gst_pad_push_event (stream->pad,
1728 gst_event_new_tag (stream->pending_tags));
1729 stream->pending_tags = NULL;
1732 /* We have the whole packet now so we should push the packet to
1733 * the src pad now. First though we should check if we need to do
1735 if (G_UNLIKELY (stream->span > 1)) {
1736 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1739 payload->buf = gst_buffer_make_writable (payload->buf);
1741 if (G_LIKELY (!payload->keyframe)) {
1742 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1745 if (G_UNLIKELY (stream->discont)) {
1746 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1747 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1748 stream->discont = FALSE;
1751 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1752 (payload->par_x != stream->par_x) &&
1753 (payload->par_y != stream->par_y))) {
1754 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1755 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1756 stream->par_x = payload->par_x;
1757 stream->par_y = payload->par_y;
1758 stream->caps = gst_caps_make_writable (stream->caps);
1759 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1760 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1761 gst_pad_set_caps (stream->pad, stream->caps);
1764 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1765 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1766 payload->interlaced);
1767 stream->interlaced = payload->interlaced;
1768 stream->caps = gst_caps_make_writable (stream->caps);
1769 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1770 (stream->interlaced ? "mixed" : "progressive"), NULL);
1771 gst_pad_set_caps (stream->pad, stream->caps);
1774 /* (sort of) interpolate timestamps using upstream "frame of reference",
1775 * typically useful for live src, but might (unavoidably) mess with
1776 * position reporting if a live src is playing not so live content
1777 * (e.g. rtspsrc taking some time to fall back to tcp) */
1778 timestamp = payload->ts;
1779 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1780 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1781 timestamp += demux->in_gap;
1783 /* Check if we're after the segment already, if so no need to push
1785 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1786 GST_DEBUG_OBJECT (stream->pad,
1787 "Payload after segment stop %" GST_TIME_FORMAT,
1788 GST_TIME_ARGS (demux->segment.stop));
1790 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1792 gst_buffer_unref (payload->buf);
1793 payload->buf = NULL;
1794 g_array_remove_index (stream->payloads, 0);
1795 /* Break out as soon as we have an issue */
1796 if (G_UNLIKELY (ret != GST_FLOW_OK))
1803 GST_BUFFER_PTS (payload->buf) = timestamp;
1805 if (payload->duration == GST_CLOCK_TIME_NONE
1806 && stream->ext_props.avg_time_per_frame != 0) {
1807 duration = stream->ext_props.avg_time_per_frame * 100;
1809 duration = payload->duration;
1811 GST_BUFFER_DURATION (payload->buf) = duration;
1813 /* FIXME: we should really set durations on buffers if we can */
1815 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1818 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1819 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1820 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1822 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1823 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1827 if (stream->active) {
1828 if (G_UNLIKELY (stream->first_buffer)) {
1829 if (stream->streamheader != NULL) {
1830 GST_DEBUG_OBJECT (stream->pad,
1831 "Pushing streamheader before first buffer");
1832 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1834 stream->first_buffer = FALSE;
1837 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1838 && timestamp > demux->segment.position) {
1839 demux->segment.position = timestamp;
1840 if (GST_CLOCK_TIME_IS_VALID (duration))
1841 demux->segment.position += timestamp;
1844 ret = gst_pad_push (stream->pad, payload->buf);
1846 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1849 gst_buffer_unref (payload->buf);
1852 payload->buf = NULL;
1853 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1854 && stream->reverse_kf_ready) {
1855 g_array_remove_index (stream->payloads, stream->kf_pos);
1858 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1860 stream->reverse_kf_ready = FALSE;
1863 g_array_remove_index (stream->payloads, 0);
1866 /* Break out as soon as we have an issue */
1867 if (G_UNLIKELY (ret != GST_FLOW_OK))
1875 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1879 g_assert (buf != NULL);
1881 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1883 gst_buffer_map (buf, &map, GST_MAP_READ);
1885 /* we return false on buffer too small */
1886 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1887 gst_buffer_unmap (buf, &map);
1891 /* check if it is a header */
1892 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1893 gst_buffer_unmap (buf, &map);
1894 if (obj.id == ASF_OBJ_HEADER) {
1901 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1903 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1904 GstFlowReturn ret = GST_FLOW_OK;
1905 GstBuffer *buf = NULL;
1906 gboolean header = FALSE;
1908 /* TODO maybe we should skip index objects after the data and look
1909 * further for a new header */
1910 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1911 g_assert (buf != NULL);
1912 /* check if it is a header */
1913 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1914 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1915 demux->base_offset = off;
1919 gst_buffer_unref (buf);
1926 gst_asf_demux_loop (GstASFDemux * demux)
1928 GstFlowReturn flow = GST_FLOW_OK;
1929 GstBuffer *buf = NULL;
1932 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1933 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1937 gst_asf_demux_pull_indices (demux);
1940 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1942 if (G_UNLIKELY (demux->num_packets != 0
1943 && demux->packet >= demux->num_packets))
1946 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1947 (guint) demux->num_packets);
1949 off = demux->data_offset + (demux->packet * demux->packet_size);
1951 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1952 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1953 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1954 if (flow == GST_FLOW_EOS) {
1956 } else if (flow == GST_FLOW_FLUSHING) {
1957 GST_DEBUG_OBJECT (demux, "Not fatal");
1964 if (G_LIKELY (demux->speed_packets == 1)) {
1965 GstAsfDemuxParsePacketError err;
1966 err = gst_asf_demux_parse_packet (demux, buf);
1967 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1968 /* when we don't know when the data object ends, we should check
1969 * for a chained asf */
1970 if (demux->num_packets == 0) {
1971 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1972 GST_INFO_OBJECT (demux, "Chained asf found");
1973 demux->base_offset = off;
1974 gst_asf_demux_reset (demux, TRUE);
1975 gst_buffer_unref (buf);
1979 /* FIXME: We should tally up fatal errors and error out only
1980 * after a few broken packets in a row? */
1982 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1983 gst_buffer_unref (buf);
1985 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
1986 && !demux->seek_to_cur_pos) {
1988 if (demux->packet < 0) {
1998 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2000 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2001 && !demux->seek_to_cur_pos) {
2003 if (demux->packet < 0) {
2012 for (n = 0; n < demux->speed_packets; n++) {
2014 GstAsfDemuxParsePacketError err;
2017 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2018 n * demux->packet_size, demux->packet_size);
2019 err = gst_asf_demux_parse_packet (demux, sub);
2020 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2021 /* when we don't know when the data object ends, we should check
2022 * for a chained asf */
2023 if (demux->num_packets == 0) {
2024 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2025 GST_INFO_OBJECT (demux, "Chained asf found");
2026 demux->base_offset = off + n * demux->packet_size;
2027 gst_asf_demux_reset (demux, TRUE);
2028 gst_buffer_unref (sub);
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");
2040 gst_buffer_unref (sub);
2042 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2043 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2049 /* reset speed pull */
2050 demux->speed_packets = 1;
2053 gst_buffer_unref (buf);
2055 if (G_UNLIKELY ((demux->num_packets > 0
2056 && demux->packet >= demux->num_packets)
2057 || flow == GST_FLOW_EOS)) {
2058 GST_LOG_OBJECT (demux, "reached EOS");
2062 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2063 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2067 /* check if we're at the end of the configured segment */
2068 /* FIXME: check if segment end reached etc. */
2074 /* if we haven't activated our streams yet, this might be because we have
2075 * less data queued than required for preroll; force stream activation and
2076 * send any pending payloads before sending EOS */
2077 if (!demux->activated_streams)
2078 gst_asf_demux_push_complete_payloads (demux, TRUE);
2080 /* we want to push an eos or post a segment-done in any case */
2081 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2084 /* for segment playback we need to post when (in stream time)
2085 * we stopped, this is either stop (when set) or the duration. */
2086 if ((stop = demux->segment.stop) == -1)
2087 stop = demux->segment.duration;
2089 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2090 gst_element_post_message (GST_ELEMENT_CAST (demux),
2091 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2093 gst_asf_demux_send_event_unlocked (demux,
2094 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2095 } else if (flow != GST_FLOW_EOS) {
2096 /* check if we have a chained asf, in case, we don't eos yet */
2097 if (gst_asf_demux_check_chained_asf (demux)) {
2098 GST_INFO_OBJECT (demux, "Chained ASF starting");
2099 gst_asf_demux_reset (demux, TRUE);
2104 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2105 /* normal playback, send EOS to all linked pads */
2106 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2107 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2109 /* ... and fall through to pause */
2113 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2114 gst_flow_get_name (flow));
2115 demux->segment_running = FALSE;
2116 gst_pad_pause_task (demux->sinkpad);
2118 /* For the error cases */
2119 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2120 /* Post an error. Hopefully something else already has, but if not... */
2121 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2122 (_("Internal data stream error.")),
2123 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
2124 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2133 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2134 flow = GST_FLOW_EOS;
2138 /* See FIXMEs above */
2141 gst_buffer_unref (buf);
2142 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2143 ("Error parsing ASF packet %u", (guint) demux->packet));
2144 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2145 flow = GST_FLOW_ERROR;
2151 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2152 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2153 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2156 gst_asf_demux_check_header (GstASFDemux * demux)
2159 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2160 ASF_OBJECT_HEADER_SIZE);
2161 if (cdata == NULL) /* need more data */
2162 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2164 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2165 if (obj.id != ASF_OBJ_HEADER) {
2166 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2168 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2172 static GstFlowReturn
2173 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2175 GstFlowReturn ret = GST_FLOW_OK;
2178 demux = GST_ASF_DEMUX (parent);
2180 GST_LOG_OBJECT (demux,
2181 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2182 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2183 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2185 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2186 GST_DEBUG_OBJECT (demux, "received DISCONT");
2187 gst_asf_demux_mark_discont (demux);
2190 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2191 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2192 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2193 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2194 ", interpolation gap: %" GST_TIME_FORMAT,
2195 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2198 gst_adapter_push (demux->adapter, buf);
2200 switch (demux->state) {
2201 case GST_ASF_DEMUX_STATE_INDEX:{
2202 gint result = gst_asf_demux_check_header (demux);
2203 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2206 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2207 /* we don't care about this, probably an index */
2208 /* TODO maybe would be smarter to skip all the indices
2209 * until we got a new header or EOS to decide */
2210 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2213 GST_INFO_OBJECT (demux, "Chained asf starting");
2214 /* cleanup and get ready for a chained asf */
2215 gst_asf_demux_reset (demux, TRUE);
2219 case GST_ASF_DEMUX_STATE_HEADER:{
2220 ret = gst_asf_demux_chain_headers (demux);
2221 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2223 /* otherwise fall through */
2225 case GST_ASF_DEMUX_STATE_DATA:
2229 data_size = demux->packet_size;
2231 while (gst_adapter_available (demux->adapter) >= data_size) {
2233 GstAsfDemuxParsePacketError err;
2235 /* we don't know the length of the stream
2236 * check for a chained asf everytime */
2237 if (demux->num_packets == 0) {
2238 gint result = gst_asf_demux_check_header (demux);
2240 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2241 GST_INFO_OBJECT (demux, "Chained asf starting");
2242 /* cleanup and get ready for a chained asf */
2243 gst_asf_demux_reset (demux, TRUE);
2246 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2247 && demux->packet >= demux->num_packets)) {
2248 /* do not overshoot data section when streaming */
2252 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2254 /* FIXME: We should tally up fatal errors and error out only
2255 * after a few broken packets in a row? */
2256 err = gst_asf_demux_parse_packet (demux, buf);
2258 gst_buffer_unref (buf);
2260 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2261 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2263 GST_WARNING_OBJECT (demux, "Parse error");
2265 if (demux->packet >= 0)
2268 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2269 && demux->packet >= demux->num_packets)) {
2270 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2275 g_assert_not_reached ();
2279 if (ret != GST_FLOW_OK)
2280 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2286 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2292 static inline gboolean
2293 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2295 if (*p_size < num_bytes)
2298 *p_data += num_bytes;
2299 *p_size -= num_bytes;
2303 static inline guint8
2304 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2308 g_assert (*p_size >= 1);
2309 ret = GST_READ_UINT8 (*p_data);
2310 *p_data += sizeof (guint8);
2311 *p_size -= sizeof (guint8);
2315 static inline guint16
2316 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2320 g_assert (*p_size >= 2);
2321 ret = GST_READ_UINT16_LE (*p_data);
2322 *p_data += sizeof (guint16);
2323 *p_size -= sizeof (guint16);
2327 static inline guint32
2328 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2332 g_assert (*p_size >= 4);
2333 ret = GST_READ_UINT32_LE (*p_data);
2334 *p_data += sizeof (guint32);
2335 *p_size -= sizeof (guint32);
2339 static inline guint64
2340 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2344 g_assert (*p_size >= 8);
2345 ret = GST_READ_UINT64_LE (*p_data);
2346 *p_data += sizeof (guint64);
2347 *p_size -= sizeof (guint64);
2352 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2353 guint8 ** p_data, guint64 * p_size)
2357 if (*p_size < num_bytes_to_read)
2360 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2361 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2363 *p_data += num_bytes_to_read;
2364 *p_size -= num_bytes_to_read;
2370 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2371 guint8 ** p_data, guint64 * p_size)
2375 if (*p_size < num_bytes_to_read)
2378 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2379 *p_data += num_bytes_to_read;
2380 *p_size -= num_bytes_to_read;
2385 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2386 guint8 ** p_data, guint64 * p_size)
2396 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2399 *p_strlen = s_length;
2401 if (s_length == 0) {
2402 GST_WARNING ("zero-length string");
2403 *p_str = g_strdup ("");
2407 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2410 g_assert (s != NULL);
2412 /* just because They don't exist doesn't
2413 * mean They are not out to get you ... */
2414 if (s[s_length - 1] != '\0') {
2415 s = g_realloc (s, s_length + 1);
2419 *p_str = (gchar *) s;
2425 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2427 g_assert (*p_size >= 4 * sizeof (guint32));
2429 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2430 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2431 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2432 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2436 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2439 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2442 /* WAVEFORMATEX Structure */
2443 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2444 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2445 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2446 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2447 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2448 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2449 /* Codec specific data size */
2450 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2455 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2458 if (*p_size < (4 + 4 + 1 + 2))
2461 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2462 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2463 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2464 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2469 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2470 guint8 ** p_data, guint64 * p_size)
2472 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2475 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2476 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2477 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2478 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2479 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2480 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2481 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2482 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2483 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2484 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2485 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2490 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2494 for (i = 0; i < demux->num_streams; i++) {
2495 if (demux->stream[i].id == id)
2496 return &demux->stream[i];
2499 if (gst_asf_demux_is_unknown_stream (demux, id))
2500 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2505 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2506 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2511 gst_pad_use_fixed_caps (src_pad);
2512 gst_pad_set_caps (src_pad, caps);
2514 gst_pad_set_event_function (src_pad,
2515 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2516 gst_pad_set_query_function (src_pad,
2517 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2519 stream = &demux->stream[demux->num_streams];
2520 stream->caps = caps;
2521 stream->pad = src_pad;
2523 stream->fps_known = !is_video; /* bit hacky for audio */
2524 stream->is_video = is_video;
2525 stream->pending_tags = tags;
2526 stream->discont = TRUE;
2527 stream->first_buffer = TRUE;
2528 stream->streamheader = streamheader;
2529 if (stream->streamheader) {
2530 stream->streamheader = gst_buffer_make_writable (streamheader);
2531 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2536 st = gst_caps_get_structure (caps, 0);
2537 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2538 par_x > 0 && par_y > 0) {
2539 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2540 stream->par_x = par_x;
2541 stream->par_y = par_y;
2545 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2547 /* TODO: create this array during reverse play? */
2548 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2550 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2551 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2553 ++demux->num_streams;
2555 stream->active = FALSE;
2561 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2562 GstBuffer * buffer, GstStructure * structure)
2564 GValue arr_val = G_VALUE_INIT;
2565 GValue buf_val = G_VALUE_INIT;
2567 g_value_init (&arr_val, GST_TYPE_ARRAY);
2568 g_value_init (&buf_val, GST_TYPE_BUFFER);
2570 gst_value_set_buffer (&buf_val, buffer);
2571 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2573 gst_structure_take_value (structure, "streamheader", &arr_val);
2577 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2578 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2580 GstTagList *tags = NULL;
2581 GstBuffer *extradata = NULL;
2584 guint16 size_left = 0;
2585 gchar *codec_name = NULL;
2588 size_left = audio->size;
2590 /* Create the audio pad */
2591 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2593 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2596 /* Swallow up any left over data and set up the
2597 * standard properties from the header info */
2599 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2600 "codec specific data", size_left);
2602 g_assert (size_left <= *p_size);
2603 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2606 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2607 * additional two bytes indicating extradata. */
2608 /* FIXME: Handle the channel reorder map here */
2609 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2610 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2613 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2614 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2617 /* Informing about that audio format we just added */
2619 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2620 g_free (codec_name);
2624 gst_buffer_unref (extradata);
2626 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2627 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2628 audio->codec_tag, tags);
2630 ++demux->num_audio_streams;
2632 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2636 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2637 asf_stream_video_format * video, guint16 id,
2638 guint8 ** p_data, guint64 * p_size)
2640 GstTagList *tags = NULL;
2641 GstStructure *caps_s;
2642 GstBuffer *extradata = NULL;
2647 gchar *codec_name = NULL;
2648 gint size_left = video->size - 40;
2649 GstBuffer *streamheader = NULL;
2650 guint par_w = 1, par_h = 1;
2652 /* Create the video pad */
2653 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2654 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2657 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2659 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2660 g_assert (size_left <= *p_size);
2661 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2664 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2666 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2667 caps = gst_riff_create_video_caps (video->tag, NULL,
2668 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2671 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2672 G_TYPE_UINT, video->tag, NULL);
2677 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2678 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2679 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2682 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2686 /* retry with the global metadata */
2687 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2688 demux->global_metadata);
2689 s = demux->global_metadata;
2690 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2691 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2692 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2693 if (ax > 0 && ay > 0) {
2696 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2701 s = gst_caps_get_structure (caps, 0);
2702 gst_structure_remove_field (s, "framerate");
2705 caps_s = gst_caps_get_structure (caps, 0);
2707 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2708 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2709 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2710 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2713 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2714 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2715 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2717 GstBuffer *buf = gst_value_get_buffer (value);
2720 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2721 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2722 /* this looks like a bytestream start */
2723 streamheader = gst_buffer_ref (buf);
2724 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2725 gst_structure_remove_field (caps_s, "codec_data");
2728 gst_buffer_unmap (buf, &mapinfo);
2733 /* For a 3D video, set multiview information into the caps based on
2734 * what was detected during object parsing */
2735 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2736 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2737 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2738 const gchar *mview_mode_str;
2740 switch (demux->asf_3D_mode) {
2741 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2742 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2744 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2745 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2746 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2748 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2749 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2751 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2752 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2753 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2755 case GST_ASF_3D_DUAL_STREAM:{
2756 gboolean is_right_view = FALSE;
2757 /* if Advanced_Mutual_Exclusion object exists, use it
2758 * to figure out which is the left view (lower ID) */
2759 if (demux->mut_ex_streams != NULL) {
2763 length = g_slist_length (demux->mut_ex_streams);
2765 for (i = 0; i < length; i++) {
2768 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2770 GST_DEBUG_OBJECT (demux,
2771 "has Mutual_Exclusion object. stream id in object is %d",
2772 GPOINTER_TO_INT (v_s_id));
2774 if (id > GPOINTER_TO_INT (v_s_id))
2775 is_right_view = TRUE;
2778 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2779 * first video stream encountered has the lower ID */
2780 if (demux->num_video_streams > 0) {
2781 /* This is not the first video stream, assuming right eye view */
2782 is_right_view = TRUE;
2786 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2788 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2795 GST_INFO_OBJECT (demux,
2796 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2799 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2800 if (mview_mode_str != NULL) {
2801 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2802 video->height, par_w, par_h))
2803 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2805 gst_caps_set_simple (caps,
2806 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2807 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2808 GST_FLAG_SET_MASK_EXACT, NULL);
2813 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2814 g_free (codec_name);
2818 gst_buffer_unref (extradata);
2820 GST_INFO ("Adding video stream #%u, id %u, codec %"
2821 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2822 GST_FOURCC_ARGS (video->tag), video->tag);
2824 ++demux->num_video_streams;
2826 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2827 streamheader, tags);
2831 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2833 if (!stream->active) {
2837 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2838 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2839 gst_pad_set_active (stream->pad, TRUE);
2842 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2843 "%03u", stream->id);
2846 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2848 if (gst_event_parse_group_id (event, &demux->group_id))
2849 demux->have_group_id = TRUE;
2851 demux->have_group_id = FALSE;
2852 gst_event_unref (event);
2853 } else if (!demux->have_group_id) {
2854 demux->have_group_id = TRUE;
2855 demux->group_id = gst_util_group_id_next ();
2858 event = gst_event_new_stream_start (stream_id);
2859 if (demux->have_group_id)
2860 gst_event_set_group_id (event, demux->group_id);
2862 gst_pad_push_event (stream->pad, event);
2864 gst_pad_set_caps (stream->pad, stream->caps);
2866 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2867 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2868 stream->active = TRUE;
2873 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2876 AsfCorrectionType correction_type;
2877 AsfStreamType stream_type;
2878 GstClockTime time_offset;
2879 gboolean is_encrypted G_GNUC_UNUSED;
2883 guint stream_specific_size;
2884 guint type_specific_size G_GNUC_UNUSED;
2885 guint unknown G_GNUC_UNUSED;
2886 gboolean inspect_payload = FALSE;
2887 AsfStream *stream = NULL;
2889 /* Get the rest of the header's header */
2890 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2891 goto not_enough_data;
2893 gst_asf_demux_get_guid (&guid, &data, &size);
2894 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2896 gst_asf_demux_get_guid (&guid, &data, &size);
2897 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2899 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2901 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2902 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2904 flags = gst_asf_demux_get_uint16 (&data, &size);
2905 stream_id = flags & 0x7f;
2906 is_encrypted = ! !((flags & 0x8000) << 15);
2907 unknown = gst_asf_demux_get_uint32 (&data, &size);
2909 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2910 stream_id, GST_TIME_ARGS (time_offset));
2912 /* dvr-ms has audio stream declared in stream specific data */
2913 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2914 AsfExtStreamType ext_stream_type;
2915 gst_asf_demux_get_guid (&guid, &data, &size);
2916 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2918 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2919 inspect_payload = TRUE;
2921 gst_asf_demux_get_guid (&guid, &data, &size);
2922 gst_asf_demux_get_uint32 (&data, &size);
2923 gst_asf_demux_get_uint32 (&data, &size);
2924 gst_asf_demux_get_uint32 (&data, &size);
2925 gst_asf_demux_get_guid (&guid, &data, &size);
2926 gst_asf_demux_get_uint32 (&data, &size);
2927 stream_type = ASF_STREAM_AUDIO;
2931 switch (stream_type) {
2932 case ASF_STREAM_AUDIO:{
2933 asf_stream_audio audio_object;
2935 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2936 goto not_enough_data;
2938 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2941 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2944 switch (correction_type) {
2945 case ASF_CORRECTION_ON:{
2946 guint span, packet_size, chunk_size, data_size, silence_data;
2948 GST_INFO ("Using error correction");
2950 if (size < (1 + 2 + 2 + 2 + 1))
2951 goto not_enough_data;
2953 span = gst_asf_demux_get_uint8 (&data, &size);
2954 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2955 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2956 data_size = gst_asf_demux_get_uint16 (&data, &size);
2957 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2959 stream->span = span;
2961 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2962 packet_size, chunk_size, data_size, span, silence_data);
2964 if (stream->span > 1) {
2965 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2966 /* Disable descrambling */
2969 /* FIXME: this else branch was added for
2970 * weird_al_yankovic - the saga begins.asf */
2971 stream->ds_packet_size = packet_size;
2972 stream->ds_chunk_size = chunk_size;
2975 /* Descambling is enabled */
2976 stream->ds_packet_size = packet_size;
2977 stream->ds_chunk_size = chunk_size;
2980 /* Now skip the rest of the silence data */
2982 gst_bytestream_flush (demux->bs, data_size - 1);
2984 /* FIXME: CHECKME. And why -1? */
2985 if (data_size > 1) {
2986 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2987 goto not_enough_data;
2993 case ASF_CORRECTION_OFF:{
2994 GST_INFO ("Error correction off");
2995 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2996 goto not_enough_data;
3000 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3001 ("Audio stream using unknown error correction"));
3008 case ASF_STREAM_VIDEO:{
3009 asf_stream_video_format video_format_object;
3010 asf_stream_video video_object;
3013 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3014 goto not_enough_data;
3016 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3018 GST_INFO ("object is a video stream with %u bytes of "
3019 "additional data", vsize);
3021 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3023 goto not_enough_data;
3026 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3027 stream_id, &data, &size);
3033 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3035 demux->other_streams =
3036 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3041 stream->inspect_payload = inspect_payload;
3046 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3047 /* we'll error out later if we found no streams */
3052 static const gchar *
3053 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3057 const gchar *asf_name;
3058 const gchar *gst_name;
3061 "WM/Genre", GST_TAG_GENRE}, {
3062 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3063 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3064 "WM/Picture", GST_TAG_IMAGE}, {
3065 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3066 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3067 "WM/Year", GST_TAG_DATE_TIME}
3068 /* { "WM/Composer", GST_TAG_COMPOSER } */
3073 if (name_utf8 == NULL) {
3074 GST_WARNING ("Failed to convert name to UTF8, skipping");
3078 out = strlen (name_utf8);
3080 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3081 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3082 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3083 return tags[i].gst_name;
3090 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3092 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3096 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3098 if (taglist == NULL)
3101 if (gst_tag_list_is_empty (taglist)) {
3102 gst_tag_list_unref (taglist);
3106 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3107 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3109 gst_tag_list_unref (demux->taglist);
3110 gst_tag_list_unref (taglist);
3112 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3115 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3116 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3117 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3118 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3121 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3125 const guint8 *img_data = NULL;
3126 guint32 img_data_len = 0;
3127 guint8 pic_type = 0;
3129 gst_byte_reader_init (&r, tag_data, tag_data_len);
3131 /* skip mime type string (we don't trust it and do our own typefinding),
3132 * and also skip the description string, since we don't use it */
3133 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3134 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3135 !gst_byte_reader_skip_string_utf16 (&r) ||
3136 !gst_byte_reader_skip_string_utf16 (&r) ||
3137 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3138 goto not_enough_data;
3142 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3143 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3149 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3150 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3155 /* Extended Content Description Object */
3156 static GstFlowReturn
3157 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3160 /* Other known (and unused) 'text/unicode' metadata available :
3163 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3164 * WMFSDKVersion = 9.00.00.2980
3165 * WMFSDKNeeded = 0.0.0.0000
3166 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3167 * WM/Publisher = 4AD
3169 * WM/ProviderRating = 8
3170 * WM/ProviderStyle = Rock (similar to WM/Genre)
3171 * WM/GenreID (similar to WM/Genre)
3172 * WM/TrackNumber (same as WM/Track but as a string)
3174 * Other known (and unused) 'non-text' metadata available :
3180 * We might want to read WM/TrackNumber and use atoi() if we don't have
3184 GstTagList *taglist;
3185 guint16 blockcount, i;
3186 gboolean content3D = FALSE;
3190 const gchar *interleave_name;
3191 GstASF3DMode interleaving_type;
3192 } stereoscopic_layout_map[] = {
3194 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3195 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3196 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3197 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3198 "DualStream", GST_ASF_3D_DUAL_STREAM}
3200 GST_INFO_OBJECT (demux, "object is an extended content description");
3202 taglist = gst_tag_list_new_empty ();
3204 /* Content Descriptor Count */
3206 goto not_enough_data;
3208 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3210 for (i = 1; i <= blockcount; ++i) {
3211 const gchar *gst_tag_name;
3215 GValue tag_value = { 0, };
3218 gchar *name_utf8 = NULL;
3222 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3223 goto not_enough_data;
3227 goto not_enough_data;
3229 /* Descriptor Value Data Type */
3230 datatype = gst_asf_demux_get_uint16 (&data, &size);
3232 /* Descriptor Value (not really a string, but same thing reading-wise) */
3233 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3235 goto not_enough_data;
3239 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3241 if (name_utf8 != NULL) {
3242 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3244 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3245 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3248 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3251 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3254 /* get rid of tags with empty value */
3255 if (value_utf8 != NULL && *value_utf8 != '\0') {
3256 GST_DEBUG ("string value %s", value_utf8);
3258 value_utf8[out] = '\0';
3260 if (gst_tag_name != NULL) {
3261 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3262 guint year = atoi (value_utf8);
3265 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3266 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3268 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3269 guint id3v1_genre_id;
3270 const gchar *genre_str;
3272 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3273 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3274 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3275 g_free (value_utf8);
3276 value_utf8 = g_strdup (genre_str);
3281 /* convert tag from string to other type if required */
3282 tag_type = gst_tag_get_type (gst_tag_name);
3283 g_value_init (&tag_value, tag_type);
3284 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3285 GValue from_val = { 0, };
3287 g_value_init (&from_val, G_TYPE_STRING);
3288 g_value_set_string (&from_val, value_utf8);
3289 if (!g_value_transform (&from_val, &tag_value)) {
3290 GST_WARNING_OBJECT (demux,
3291 "Could not transform string tag to " "%s tag type %s",
3292 gst_tag_name, g_type_name (tag_type));
3293 g_value_unset (&tag_value);
3295 g_value_unset (&from_val);
3300 GST_DEBUG ("Setting metadata");
3301 g_value_init (&tag_value, G_TYPE_STRING);
3302 g_value_set_string (&tag_value, value_utf8);
3303 /* If we found a stereoscopic marker, look for StereoscopicLayout
3307 if (strncmp ("StereoscopicLayout", name_utf8,
3308 strlen (name_utf8)) == 0) {
3309 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3310 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3312 demux->asf_3D_mode =
3313 stereoscopic_layout_map[i].interleaving_type;
3314 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3318 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3320 demux->asf_3D_mode = GST_ASF_3D_NONE;
3321 GST_INFO_OBJECT (demux, "None 3d type");
3324 } else if (value_utf8 == NULL) {
3325 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3327 GST_DEBUG ("Skipping empty string value for %s",
3328 GST_STR_NULL (gst_tag_name));
3330 g_free (value_utf8);
3333 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3335 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3336 GST_FIXME ("Unhandled byte array tag %s",
3337 GST_STR_NULL (gst_tag_name));
3340 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3346 case ASF_DEMUX_DATA_TYPE_DWORD:{
3347 guint uint_val = GST_READ_UINT32_LE (value);
3349 /* this is the track number */
3350 g_value_init (&tag_value, G_TYPE_UINT);
3352 /* WM/Track counts from 0 */
3353 if (!strcmp (name_utf8, "WM/Track"))
3356 g_value_set_uint (&tag_value, uint_val);
3360 case ASF_DEMUX_DATA_TYPE_BOOL:{
3361 gboolean bool_val = GST_READ_UINT32_LE (value);
3363 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3365 GST_INFO_OBJECT (demux, "This is 3D contents");
3368 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3376 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3381 if (G_IS_VALUE (&tag_value)) {
3383 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3385 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3386 * is supposed to have a 0 base but is often wrongly written to start
3387 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3388 * replace the value added earlier from WM/Track or put it first in
3389 * the list, so that it will get picked up by _get_uint() */
3390 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3391 merge_mode = GST_TAG_MERGE_REPLACE;
3393 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3396 GST_DEBUG ("Setting global metadata %s", name_utf8);
3397 gst_structure_set_value (demux->global_metadata, name_utf8,
3401 g_value_unset (&tag_value);
3410 gst_asf_demux_add_global_tags (demux, taglist);
3417 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3418 gst_tag_list_unref (taglist);
3419 return GST_FLOW_OK; /* not really fatal */
3423 static GstStructure *
3424 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3429 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3431 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3434 s = gst_caps_get_structure (demux->metadata, i);
3435 if (gst_structure_has_name (s, sname))
3439 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3441 /* try lookup again; demux->metadata took ownership of the structure, so we
3442 * can't really make any assumptions about what happened to it, so we can't
3443 * just return it directly after appending it */
3444 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3447 static GstFlowReturn
3448 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3451 guint16 blockcount, i;
3453 GST_INFO_OBJECT (demux, "object is a metadata object");
3455 /* Content Descriptor Count */
3457 goto not_enough_data;
3459 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3461 for (i = 0; i < blockcount; ++i) {
3463 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3464 guint32 data_len, ival;
3467 if (size < (2 + 2 + 2 + 2 + 4))
3468 goto not_enough_data;
3470 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3471 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3472 name_len = gst_asf_demux_get_uint16 (&data, &size);
3473 data_type = gst_asf_demux_get_uint16 (&data, &size);
3474 data_len = gst_asf_demux_get_uint32 (&data, &size);
3476 if (size < name_len + data_len)
3477 goto not_enough_data;
3479 /* convert name to UTF-8 */
3480 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3482 gst_asf_demux_skip_bytes (name_len, &data, &size);
3484 if (name_utf8 == NULL) {
3485 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3486 gst_asf_demux_skip_bytes (data_len, &data, &size);
3490 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3491 gst_asf_demux_skip_bytes (data_len, &data, &size);
3499 goto not_enough_data;
3502 ival = gst_asf_demux_get_uint32 (&data, &size);
3504 /* skip anything else there may be, just in case */
3505 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3507 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3508 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3512 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3518 GST_WARNING ("Unexpected end of data parsing metadata object");
3519 return GST_FLOW_OK; /* not really fatal */
3523 static GstFlowReturn
3524 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3526 GstFlowReturn ret = GST_FLOW_OK;
3527 guint32 i, num_objects;
3528 guint8 unknown G_GNUC_UNUSED;
3530 /* Get the rest of the header's header */
3531 if (size < (4 + 1 + 1))
3532 goto not_enough_data;
3534 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3535 unknown = gst_asf_demux_get_uint8 (&data, &size);
3536 unknown = gst_asf_demux_get_uint8 (&data, &size);
3538 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3540 /* Loop through the header's objects, processing those */
3541 for (i = 0; i < num_objects; ++i) {
3542 GST_INFO_OBJECT (demux, "reading header part %u", i);
3543 ret = gst_asf_demux_process_object (demux, &data, &size);
3544 if (ret != GST_FLOW_OK) {
3545 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3554 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3555 ("short read parsing HEADER object"));
3556 return GST_FLOW_ERROR;
3560 static GstFlowReturn
3561 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3563 guint64 creation_time G_GNUC_UNUSED;
3564 guint64 file_size G_GNUC_UNUSED;
3565 guint64 send_time G_GNUC_UNUSED;
3566 guint64 packets_count, play_time, preroll;
3567 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3569 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3570 goto not_enough_data;
3572 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3573 file_size = gst_asf_demux_get_uint64 (&data, &size);
3574 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3575 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3576 play_time = gst_asf_demux_get_uint64 (&data, &size);
3577 send_time = gst_asf_demux_get_uint64 (&data, &size);
3578 preroll = gst_asf_demux_get_uint64 (&data, &size);
3579 flags = gst_asf_demux_get_uint32 (&data, &size);
3580 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3581 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3582 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3584 demux->broadcast = ! !(flags & 0x01);
3585 demux->seekable = ! !(flags & 0x02);
3587 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3588 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3589 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3591 if (demux->broadcast) {
3592 /* these fields are invalid if the broadcast flag is set */
3597 if (min_pktsize != max_pktsize)
3598 goto non_fixed_packet_size;
3600 demux->packet_size = max_pktsize;
3602 /* FIXME: do we need send_time as well? what is it? */
3603 if ((play_time * 100) >= (preroll * GST_MSECOND))
3604 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3606 demux->play_time = 0;
3608 demux->preroll = preroll * GST_MSECOND;
3610 /* initial latency */
3611 demux->latency = demux->preroll;
3613 if (demux->play_time == 0)
3614 demux->seekable = FALSE;
3616 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3617 GST_TIME_ARGS (demux->play_time));
3618 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3619 GST_TIME_ARGS (demux->preroll));
3621 if (demux->play_time > 0) {
3622 demux->segment.duration = demux->play_time;
3625 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3627 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3632 non_fixed_packet_size:
3634 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3635 ("packet size must be fixed"));
3636 return GST_FLOW_ERROR;
3640 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3641 ("short read parsing FILE object"));
3642 return GST_FLOW_ERROR;
3646 /* Content Description Object */
3647 static GstFlowReturn
3648 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3652 const gchar *gst_tag;
3657 GST_TAG_TITLE, 0, NULL}, {
3658 GST_TAG_ARTIST, 0, NULL}, {
3659 GST_TAG_COPYRIGHT, 0, NULL}, {
3660 GST_TAG_DESCRIPTION, 0, NULL}, {
3661 GST_TAG_COMMENT, 0, NULL}
3663 GstTagList *taglist;
3664 GValue value = { 0 };
3668 GST_INFO_OBJECT (demux, "object is a comment");
3670 if (size < (2 + 2 + 2 + 2 + 2))
3671 goto not_enough_data;
3673 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3674 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3675 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3676 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3677 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3679 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3680 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3681 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3683 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3684 if (size < tags[i].val_length)
3685 goto not_enough_data;
3687 /* might be just '/0', '/0'... */
3688 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3689 /* convert to UTF-8 */
3690 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3691 "UTF-8", "UTF-16LE", &in, &out, NULL);
3693 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3696 /* parse metadata into taglist */
3697 taglist = gst_tag_list_new_empty ();
3698 g_value_init (&value, G_TYPE_STRING);
3699 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3700 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3701 g_value_set_string (&value, tags[i].val_utf8);
3702 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3703 tags[i].gst_tag, &value, NULL);
3706 g_value_unset (&value);
3708 gst_asf_demux_add_global_tags (demux, taglist);
3710 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3711 g_free (tags[i].val_utf8);
3717 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3718 "comment tag section %d, skipping comment object", i);
3719 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3720 g_free (tags[i].val_utf8);
3721 return GST_FLOW_OK; /* not really fatal */
3725 static GstFlowReturn
3726 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3729 guint16 num_streams, i;
3733 goto not_enough_data;
3735 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3737 GST_INFO ("object is a bitrate properties object with %u streams",
3740 if (size < (num_streams * (2 + 4)))
3741 goto not_enough_data;
3743 for (i = 0; i < num_streams; ++i) {
3747 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3748 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3750 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3751 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3752 stream = gst_asf_demux_get_stream (demux, stream_id);
3754 if (stream->pending_tags == NULL)
3755 stream->pending_tags = gst_tag_list_new_empty ();
3756 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3757 GST_TAG_BITRATE, bitrate, NULL);
3759 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3762 GST_WARNING ("stream id %u is too large", stream_id);
3770 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3771 return GST_FLOW_OK; /* not really fatal */
3775 static GstFlowReturn
3776 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3779 GstFlowReturn ret = GST_FLOW_OK;
3782 /* Get the rest of the header's header */
3783 if (size < (16 + 2 + 4))
3784 goto not_enough_data;
3786 /* skip GUID and two other bytes */
3787 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3788 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3790 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3792 /* FIXME: does data_size include the rest of the header that we have read? */
3793 if (hdr_size > size)
3794 goto not_enough_data;
3796 while (hdr_size > 0) {
3797 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3798 if (ret != GST_FLOW_OK)
3806 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3807 ("short read parsing extended header object"));
3808 return GST_FLOW_ERROR;
3812 static GstFlowReturn
3813 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3819 goto not_enough_data;
3821 if (demux->languages) {
3822 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3823 g_strfreev (demux->languages);
3824 demux->languages = NULL;
3825 demux->num_languages = 0;
3828 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3829 GST_LOG ("%u languages:", demux->num_languages);
3831 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3832 for (i = 0; i < demux->num_languages; ++i) {
3833 guint8 len, *lang_data = NULL;
3836 goto not_enough_data;
3837 len = gst_asf_demux_get_uint8 (&data, &size);
3838 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3841 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3844 /* truncate "en-us" etc. to just "en" */
3845 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3848 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3849 demux->languages[i] = utf8;
3852 goto not_enough_data;
3860 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3861 g_free (demux->languages);
3862 demux->languages = NULL;
3863 return GST_FLOW_OK; /* not fatal */
3867 static GstFlowReturn
3868 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3871 GstClockTime interval;
3874 if (size < (16 + 8 + 4 + 4))
3875 goto not_enough_data;
3878 gst_asf_demux_skip_bytes (16, &data, &size);
3879 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3880 gst_asf_demux_skip_bytes (4, &data, &size);
3881 count = gst_asf_demux_get_uint32 (&data, &size);
3883 demux->sidx_interval = interval;
3884 demux->sidx_num_entries = count;
3885 g_free (demux->sidx_entries);
3886 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3888 for (i = 0; i < count; ++i) {
3889 if (G_UNLIKELY (size < 6)) {
3890 /* adjust for broken files, to avoid having entries at the end
3891 * of the parsed index that point to time=0. Resulting in seeking to
3892 * the end of the file leading back to the beginning */
3893 demux->sidx_num_entries -= (count - i);
3896 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3897 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3898 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3899 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3900 demux->sidx_entries[i].count);
3903 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3910 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3911 return GST_FLOW_OK; /* not fatal */
3915 static GstFlowReturn
3916 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3917 guint8 * data, guint64 size)
3922 if (size < 16 + 2 + (2 * 2))
3923 goto not_enough_data;
3925 gst_asf_demux_get_guid (&guid, &data, &size);
3926 num = gst_asf_demux_get_uint16 (&data, &size);
3929 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3933 if (size < (num * sizeof (guint16)))
3934 goto not_enough_data;
3936 /* read mutually exclusive stream numbers */
3937 for (i = 0; i < num; ++i) {
3939 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3940 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3942 demux->mut_ex_streams =
3943 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
3952 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3953 return GST_FLOW_OK; /* not absolutely fatal */
3958 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3960 return g_slist_find (demux->other_streams,
3961 GINT_TO_POINTER (stream_num)) == NULL;
3964 static GstFlowReturn
3965 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3968 AsfStreamExtProps esp;
3969 AsfStream *stream = NULL;
3970 AsfObject stream_obj;
3971 guint16 stream_name_count;
3972 guint16 num_payload_ext;
3974 guint8 *stream_obj_data = NULL;
3977 guint i, stream_num;
3980 obj_size = (guint) size;
3983 goto not_enough_data;
3986 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3987 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3988 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3989 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3990 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3991 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3992 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3993 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3994 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3995 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3996 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3997 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3998 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3999 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4000 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4002 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4003 GST_TIME_ARGS (esp.start_time));
4004 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4005 GST_TIME_ARGS (esp.end_time));
4006 GST_INFO ("flags = %08x", esp.flags);
4007 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4008 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4009 GST_INFO ("stream number = %u", stream_num);
4010 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4011 (esp.lang_idx < demux->num_languages) ?
4012 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4013 GST_INFO ("stream name count = %u", stream_name_count);
4015 /* read stream names */
4016 for (i = 0; i < stream_name_count; ++i) {
4017 guint16 stream_lang_idx G_GNUC_UNUSED;
4018 gchar *stream_name = NULL;
4021 goto not_enough_data;
4022 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4023 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4024 goto not_enough_data;
4025 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4026 g_free (stream_name); /* TODO: store names in struct */
4029 /* read payload extension systems stuff */
4030 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4032 if (num_payload_ext > 0)
4033 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4035 esp.payload_extensions = NULL;
4037 for (i = 0; i < num_payload_ext; ++i) {
4038 AsfPayloadExtension ext;
4040 guint32 sys_info_len;
4042 if (size < 16 + 2 + 4)
4043 goto not_enough_data;
4045 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4046 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4047 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4049 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4050 GST_LOG ("payload systems info len = %u", sys_info_len);
4051 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4052 goto not_enough_data;
4054 esp.payload_extensions[i] = ext;
4057 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4059 /* there might be an optional STREAM_INFO object here now; if not, we
4060 * should have parsed the corresponding stream info object already (since
4061 * we are parsing the extended stream properties objects delayed) */
4063 stream = gst_asf_demux_get_stream (demux, stream_num);
4067 /* get size of the stream object */
4068 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4069 goto not_enough_data;
4071 if (stream_obj.id != ASF_OBJ_STREAM)
4072 goto expected_stream_object;
4074 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4075 stream_obj.size > (10 * 1024 * 1024))
4076 goto not_enough_data;
4078 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4080 /* process this stream object later after all the other 'normal' ones
4081 * have been processed (since the others are more important/non-hidden) */
4082 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4083 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4084 goto not_enough_data;
4086 /* parse stream object */
4087 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4088 g_free (stream_obj_data);
4093 stream->ext_props = esp;
4095 /* try to set the framerate */
4096 if (stream->is_video && stream->caps) {
4097 GValue framerate = { 0 };
4101 g_value_init (&framerate, GST_TYPE_FRACTION);
4103 num = GST_SECOND / 100;
4104 denom = esp.avg_time_per_frame;
4106 /* avoid division by 0, assume 25/1 framerate */
4107 denom = GST_SECOND / 2500;
4110 gst_value_set_fraction (&framerate, num, denom);
4112 stream->caps = gst_caps_make_writable (stream->caps);
4113 s = gst_caps_get_structure (stream->caps, 0);
4114 gst_structure_set_value (s, "framerate", &framerate);
4115 g_value_unset (&framerate);
4116 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4117 num, denom, ((gdouble) num) / denom);
4120 /* add language info now if we have it */
4121 if (stream->ext_props.lang_idx < demux->num_languages) {
4122 if (stream->pending_tags == NULL)
4123 stream->pending_tags = gst_tag_list_new_empty ();
4124 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4125 demux->languages[stream->ext_props.lang_idx]);
4126 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4127 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4130 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4131 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4139 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4140 return GST_FLOW_OK; /* not absolutely fatal */
4142 expected_stream_object:
4144 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4145 "object: expected embedded stream object, but got %s object instead!",
4146 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4147 return GST_FLOW_OK; /* not absolutely fatal */
4151 static const gchar *
4152 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4156 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4157 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4158 nick += strlen ("ASF_OBJ_");
4160 if (demux->objpath == NULL) {
4161 demux->objpath = g_strdup (nick);
4165 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4166 g_free (demux->objpath);
4167 demux->objpath = newpath;
4170 return (const gchar *) demux->objpath;
4174 gst_asf_demux_pop_obj (GstASFDemux * demux)
4178 if ((s = g_strrstr (demux->objpath, "/"))) {
4181 g_free (demux->objpath);
4182 demux->objpath = NULL;
4187 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4192 /* Parse the queued extended stream property objects and add the info
4193 * to the existing streams or add the new embedded streams, but without
4194 * activating them yet */
4195 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4196 g_slist_length (demux->ext_stream_props));
4198 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4199 GstBuffer *buf = GST_BUFFER (l->data);
4202 gst_buffer_map (buf, &map, GST_MAP_READ);
4204 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4205 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4206 gst_buffer_unmap (buf, &map);
4207 gst_buffer_unref (buf);
4209 g_slist_free (demux->ext_stream_props);
4210 demux->ext_stream_props = NULL;
4215 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4219 for (i = 0; i < demux->num_streams; ++i) {
4224 stream = &demux->stream[i];
4226 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4228 if (stream->active) {
4229 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4234 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4237 /* check for each mutual exclusion whether it affects this stream */
4238 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4239 if (*mes == stream->id) {
4240 /* if yes, check if we've already added streams that are mutually
4241 * exclusive with the stream we're about to add */
4242 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4243 for (j = 0; j < demux->num_streams; ++j) {
4244 /* if the broadcast flag is set, assume the hidden streams aren't
4245 * actually streamed and hide them (or playbin won't work right),
4246 * otherwise assume their data is available */
4247 if (demux->stream[j].id == *mes && demux->broadcast) {
4249 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4250 "mutually exclusive with already existing stream ID %d, "
4251 "hiding stream", stream->id, demux->stream[j].id);
4263 /* FIXME: we should do stream activation based on preroll data in
4264 * streaming mode too */
4265 if (demux->streaming && !is_hidden)
4266 gst_asf_demux_activate_stream (demux, stream);
4271 static GstFlowReturn
4272 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4275 GstFlowReturn ret = GST_FLOW_OK;
4277 guint64 obj_data_size;
4279 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4280 return ASF_FLOW_NEED_MORE_DATA;
4282 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4283 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4285 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4287 if (*p_size < obj_data_size)
4288 return ASF_FLOW_NEED_MORE_DATA;
4290 gst_asf_demux_push_obj (demux, obj.id);
4292 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4295 case ASF_OBJ_STREAM:
4296 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4300 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4302 case ASF_OBJ_HEADER:
4303 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4305 case ASF_OBJ_COMMENT:
4306 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4309 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4311 case ASF_OBJ_BITRATE_PROPS:
4313 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4316 case ASF_OBJ_EXT_CONTENT_DESC:
4318 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4321 case ASF_OBJ_METADATA_OBJECT:
4322 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4324 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4327 /* process these later, we might not have parsed the corresponding
4328 * stream object yet */
4329 GST_LOG ("%s: queued for later parsing", demux->objpath);
4330 buf = gst_buffer_new_and_alloc (obj_data_size);
4331 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4332 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4336 case ASF_OBJ_LANGUAGE_LIST:
4337 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4339 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4340 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4343 case ASF_OBJ_SIMPLE_INDEX:
4344 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4346 case ASF_OBJ_CONTENT_ENCRYPTION:
4347 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4348 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4349 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4350 goto error_encrypted;
4351 case ASF_OBJ_CONCEAL_NONE:
4353 case ASF_OBJ_UNDEFINED:
4354 case ASF_OBJ_CODEC_COMMENT:
4356 case ASF_OBJ_PADDING:
4357 case ASF_OBJ_BITRATE_MUTEX:
4358 case ASF_OBJ_COMPATIBILITY:
4359 case ASF_OBJ_INDEX_PLACEHOLDER:
4360 case ASF_OBJ_INDEX_PARAMETERS:
4361 case ASF_OBJ_STREAM_PRIORITIZATION:
4362 case ASF_OBJ_SCRIPT_COMMAND:
4363 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4365 /* Unknown/unhandled object, skip it and hope for the best */
4366 GST_INFO ("%s: skipping object", demux->objpath);
4371 /* this can't fail, we checked the number of bytes available before */
4372 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4374 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4376 gst_asf_demux_pop_obj (demux);
4383 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4384 return GST_FLOW_ERROR;
4389 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4390 GstBuffer ** p_buffer)
4392 GstBuffer *descrambled_buffer;
4393 GstBuffer *scrambled_buffer;
4394 GstBuffer *sub_buffer;
4401 /* descrambled_buffer is initialised in the first iteration */
4402 descrambled_buffer = NULL;
4403 scrambled_buffer = *p_buffer;
4405 if (gst_buffer_get_size (scrambled_buffer) <
4406 stream->ds_packet_size * stream->span)
4409 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4410 offset += stream->ds_chunk_size) {
4411 off = offset / stream->ds_chunk_size;
4412 row = off / stream->span;
4413 col = off % stream->span;
4414 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4415 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4416 col, off, stream->ds_chunk_size);
4417 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4418 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4419 stream->span, stream->ds_packet_size);
4420 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4421 gst_buffer_get_size (scrambled_buffer));
4423 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4424 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4426 descrambled_buffer = sub_buffer;
4428 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4432 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4433 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4434 GST_BUFFER_DURATION (descrambled_buffer) =
4435 GST_BUFFER_DURATION (scrambled_buffer);
4436 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4437 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4438 GST_BUFFER_OFFSET_END (scrambled_buffer);
4440 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4442 gst_buffer_unref (scrambled_buffer);
4443 *p_buffer = descrambled_buffer;
4447 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4449 GstASFDemux *demux = GST_ASF_DEMUX (element);
4452 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4454 for (i = 0; i < demux->num_streams; ++i) {
4455 gst_event_ref (event);
4456 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4457 GST_OBJECT_CAST (element), event)) {
4458 gst_event_unref (event);
4463 gst_event_unref (event);
4467 /* takes ownership of the passed event */
4469 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4471 gboolean ret = TRUE;
4474 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4475 GST_EVENT_TYPE_NAME (event));
4477 for (i = 0; i < demux->num_streams; ++i) {
4478 gst_event_ref (event);
4479 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4481 gst_event_unref (event);
4486 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4490 gboolean res = FALSE;
4492 demux = GST_ASF_DEMUX (parent);
4494 GST_DEBUG ("handling %s query",
4495 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4497 switch (GST_QUERY_TYPE (query)) {
4498 case GST_QUERY_DURATION:
4502 gst_query_parse_duration (query, &format, NULL);
4504 if (format != GST_FORMAT_TIME) {
4505 GST_LOG ("only support duration queries in TIME format");
4509 res = gst_pad_query_default (pad, parent, query);
4511 GST_OBJECT_LOCK (demux);
4513 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4514 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4515 GST_TIME_ARGS (demux->segment.duration));
4517 gst_query_set_duration (query, GST_FORMAT_TIME,
4518 demux->segment.duration);
4522 GST_LOG ("duration not known yet");
4525 GST_OBJECT_UNLOCK (demux);
4530 case GST_QUERY_POSITION:{
4533 gst_query_parse_position (query, &format, NULL);
4535 if (format != GST_FORMAT_TIME) {
4536 GST_LOG ("only support position queries in TIME format");
4540 GST_OBJECT_LOCK (demux);
4542 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4543 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4544 GST_TIME_ARGS (demux->segment.position));
4546 gst_query_set_position (query, GST_FORMAT_TIME,
4547 demux->segment.position);
4551 GST_LOG ("position not known yet");
4554 GST_OBJECT_UNLOCK (demux);
4558 case GST_QUERY_SEEKING:{
4561 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4562 if (format == GST_FORMAT_TIME) {
4565 GST_OBJECT_LOCK (demux);
4566 duration = demux->segment.duration;
4567 GST_OBJECT_UNLOCK (demux);
4569 if (!demux->streaming || !demux->seekable) {
4570 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4577 /* try upstream first in TIME */
4578 res = gst_pad_query_default (pad, parent, query);
4580 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4581 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4582 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4583 /* if no luck, maybe in BYTES */
4584 if (!seekable || fmt != GST_FORMAT_TIME) {
4587 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4588 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4589 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4590 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4591 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4592 if (fmt != GST_FORMAT_BYTES)
4595 gst_query_unref (q);
4596 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4602 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4606 case GST_QUERY_LATENCY:
4609 GstClockTime min, max;
4611 /* preroll delay does not matter in non-live pipeline,
4612 * but we might end up in a live (rtsp) one ... */
4615 res = gst_pad_query_default (pad, parent, query);
4619 gst_query_parse_latency (query, &live, &min, &max);
4621 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4622 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4623 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4625 GST_OBJECT_LOCK (demux);
4626 min += demux->latency;
4628 max += demux->latency;
4629 GST_OBJECT_UNLOCK (demux);
4631 gst_query_set_latency (query, live, min, max);
4634 case GST_QUERY_SEGMENT:
4639 format = demux->segment.format;
4642 gst_segment_to_stream_time (&demux->segment, format,
4643 demux->segment.start);
4644 if ((stop = demux->segment.stop) == -1)
4645 stop = demux->segment.duration;
4647 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4649 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4654 res = gst_pad_query_default (pad, parent, query);
4661 static GstStateChangeReturn
4662 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4664 GstASFDemux *demux = GST_ASF_DEMUX (element);
4665 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4667 switch (transition) {
4668 case GST_STATE_CHANGE_NULL_TO_READY:{
4669 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4670 demux->need_newsegment = TRUE;
4671 demux->segment_running = FALSE;
4672 demux->keyunit_sync = FALSE;
4673 demux->accurate = FALSE;
4674 demux->adapter = gst_adapter_new ();
4675 demux->metadata = gst_caps_new_empty ();
4676 demux->global_metadata = gst_structure_new_empty ("metadata");
4677 demux->data_size = 0;
4678 demux->data_offset = 0;
4679 demux->index_offset = 0;
4680 demux->base_offset = 0;
4681 demux->flowcombiner = gst_flow_combiner_new ();
4689 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4690 if (ret == GST_STATE_CHANGE_FAILURE)
4693 switch (transition) {
4694 case GST_STATE_CHANGE_PAUSED_TO_READY:
4695 gst_asf_demux_reset (demux, FALSE);
4698 case GST_STATE_CHANGE_READY_TO_NULL:
4699 gst_asf_demux_reset (demux, FALSE);
4700 gst_flow_combiner_free (demux->flowcombiner);
4701 demux->flowcombiner = NULL;