1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <gst/video/video.h>
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS ("video/x-ms-asf")
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE (16+8)
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA 99
76 #define gst_asf_get_flow_name(flow) \
77 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
78 "need-more-data" : gst_flow_get_name (flow)
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83 GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89 GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98 GstObject * parent, GstPadMode mode, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
103 GstFlowReturn * pflow);
104 static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109 AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
123 GstElementClass *gstelement_class;
125 gstelement_class = (GstElementClass *) klass;
127 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
129 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 gst_element_class_add_static_pad_template (gstelement_class,
132 &audio_src_template);
133 gst_element_class_add_static_pad_template (gstelement_class,
134 &video_src_template);
135 gst_element_class_add_static_pad_template (gstelement_class,
136 &gst_asf_demux_sink_template);
138 gstelement_class->change_state =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140 gstelement_class->send_event =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 gst_caps_replace (&stream->caps, NULL);
148 if (stream->pending_tags) {
149 gst_tag_list_unref (stream->pending_tags);
150 stream->pending_tags = NULL;
152 if (stream->streamheader) {
153 gst_buffer_unref (stream->streamheader);
154 stream->streamheader = NULL;
157 if (stream->active) {
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
161 gst_object_unref (stream->pad);
165 if (stream->payloads) {
166 while (stream->payloads->len > 0) {
170 last = stream->payloads->len - 1;
171 payload = &g_array_index (stream->payloads, AsfPayload, last);
172 gst_buffer_replace (&payload->buf, NULL);
173 g_array_remove_index (stream->payloads, last);
175 g_array_free (stream->payloads, TRUE);
176 stream->payloads = NULL;
179 if (stream->payloads_rev) {
180 while (stream->payloads_rev->len > 0) {
184 last = stream->payloads_rev->len - 1;
185 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186 gst_buffer_replace (&payload->buf, NULL);
187 g_array_remove_index (stream->payloads_rev, last);
189 g_array_free (stream->payloads_rev, TRUE);
190 stream->payloads_rev = NULL;
193 if (stream->ext_props.valid) {
194 g_free (stream->ext_props.payload_extensions);
195 stream->ext_props.payload_extensions = NULL;
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
202 GST_LOG_OBJECT (demux, "resetting");
204 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205 demux->segment_running = FALSE;
206 if (demux->adapter && !chain_reset) {
207 gst_adapter_clear (demux->adapter);
208 g_object_unref (demux->adapter);
209 demux->adapter = NULL;
211 if (demux->taglist) {
212 gst_tag_list_unref (demux->taglist);
213 demux->taglist = NULL;
215 if (demux->metadata) {
216 gst_caps_unref (demux->metadata);
217 demux->metadata = NULL;
219 if (demux->global_metadata) {
220 gst_structure_free (demux->global_metadata);
221 demux->global_metadata = NULL;
223 if (demux->mut_ex_streams) {
224 g_slist_free (demux->mut_ex_streams);
225 demux->mut_ex_streams = NULL;
228 demux->state = GST_ASF_DEMUX_STATE_HEADER;
229 g_free (demux->objpath);
230 demux->objpath = NULL;
231 g_strfreev (demux->languages);
232 demux->languages = NULL;
233 demux->num_languages = 0;
234 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
236 g_slist_free (demux->ext_stream_props);
237 demux->ext_stream_props = NULL;
239 while (demux->old_num_streams > 0) {
240 gst_asf_demux_free_stream (demux,
241 &demux->old_stream[demux->old_num_streams - 1]);
242 --demux->old_num_streams;
244 memset (demux->old_stream, 0, sizeof (demux->old_stream));
245 demux->old_num_streams = 0;
247 /* when resetting for a new chained asf, we don't want to remove the pads
248 * before adding the new ones */
250 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251 demux->old_num_streams = demux->num_streams;
252 demux->num_streams = 0;
255 while (demux->num_streams > 0) {
256 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257 --demux->num_streams;
259 memset (demux->stream, 0, sizeof (demux->stream));
261 /* do not remove those for not adding pads with same name */
262 demux->num_audio_streams = 0;
263 demux->num_video_streams = 0;
264 demux->have_group_id = FALSE;
265 demux->group_id = G_MAXUINT;
267 demux->num_streams = 0;
268 demux->activated_streams = FALSE;
269 demux->first_ts = GST_CLOCK_TIME_NONE;
270 demux->segment_ts = GST_CLOCK_TIME_NONE;
273 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274 demux->state = GST_ASF_DEMUX_STATE_HEADER;
275 demux->seekable = FALSE;
276 demux->broadcast = FALSE;
277 demux->sidx_interval = 0;
278 demux->sidx_num_entries = 0;
279 g_free (demux->sidx_entries);
280 demux->sidx_entries = NULL;
282 demux->speed_packets = 1;
284 demux->asf_3D_mode = GST_ASF_3D_NONE;
287 GST_LOG_OBJECT (demux, "Restarting");
288 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289 demux->need_newsegment = TRUE;
290 demux->segment_seqnum = 0;
291 demux->segment_running = FALSE;
292 demux->keyunit_sync = FALSE;
293 demux->accurate = FALSE;
294 demux->metadata = gst_caps_new_empty ();
295 demux->global_metadata = gst_structure_new_empty ("metadata");
296 demux->data_size = 0;
297 demux->data_offset = 0;
298 demux->index_offset = 0;
300 demux->base_offset = 0;
303 g_slist_free (demux->other_streams);
304 demux->other_streams = NULL;
308 gst_asf_demux_init (GstASFDemux * demux)
311 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312 gst_pad_set_chain_function (demux->sinkpad,
313 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314 gst_pad_set_event_function (demux->sinkpad,
315 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316 gst_pad_set_activate_function (demux->sinkpad,
317 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318 gst_pad_set_activatemode_function (demux->sinkpad,
319 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
322 /* set initial state */
323 gst_asf_demux_reset (demux, FALSE);
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
332 query = gst_query_new_scheduling ();
334 if (!gst_pad_peer_query (sinkpad, query)) {
335 gst_query_unref (query);
339 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341 gst_query_unref (query);
346 GST_DEBUG_OBJECT (sinkpad, "activating pull");
347 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
351 GST_DEBUG_OBJECT (sinkpad, "activating push");
352 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358 GstPadMode mode, gboolean active)
363 demux = GST_ASF_DEMUX (parent);
366 case GST_PAD_MODE_PUSH:
367 demux->state = GST_ASF_DEMUX_STATE_HEADER;
368 demux->streaming = TRUE;
371 case GST_PAD_MODE_PULL:
373 demux->state = GST_ASF_DEMUX_STATE_HEADER;
374 demux->streaming = FALSE;
376 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
379 res = gst_pad_stop_task (sinkpad);
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
395 demux = GST_ASF_DEMUX (parent);
397 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398 switch (GST_EVENT_TYPE (event)) {
399 case GST_EVENT_SEGMENT:{
400 const GstSegment *segment;
402 gst_event_parse_segment (event, &segment);
404 if (segment->format == GST_FORMAT_BYTES) {
405 if (demux->packet_size && segment->start > demux->data_offset)
406 demux->packet = (segment->start - demux->data_offset) /
410 } else if (segment->format == GST_FORMAT_TIME) {
411 /* do not know packet position, not really a problem */
414 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415 gst_event_unref (event);
419 /* record upstream segment for interpolation */
420 if (segment->format != demux->in_segment.format)
421 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422 gst_segment_copy_into (segment, &demux->in_segment);
424 /* in either case, clear some state and generate newsegment later on */
425 GST_OBJECT_LOCK (demux);
426 demux->segment_ts = GST_CLOCK_TIME_NONE;
427 demux->in_gap = GST_CLOCK_TIME_NONE;
428 demux->need_newsegment = TRUE;
429 demux->segment_seqnum = gst_event_get_seqnum (event);
430 gst_asf_demux_reset_stream_state_after_discont (demux);
431 /* if we seek back after reaching EOS, go back to packet reading state */
432 if (demux->data_offset > 0 && segment->start >= demux->data_offset
433 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
434 demux->state = GST_ASF_DEMUX_STATE_DATA;
436 GST_OBJECT_UNLOCK (demux);
438 gst_event_unref (event);
444 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
446 (_("This stream contains no data.")),
447 ("got eos and didn't receive a complete header object"));
450 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
451 if (!demux->activated_streams) {
452 /* If we still haven't got activated streams, the file is most likely corrupt */
453 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
454 (_("This stream contains no data.")),
455 ("got eos and didn't receive a complete header object"));
458 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
459 GST_ELEMENT_FLOW_ERROR (demux, flow);
463 GST_OBJECT_LOCK (demux);
464 gst_adapter_clear (demux->adapter);
465 GST_OBJECT_UNLOCK (demux);
466 gst_asf_demux_send_event_unlocked (demux, event);
470 case GST_EVENT_FLUSH_STOP:
471 GST_OBJECT_LOCK (demux);
472 gst_asf_demux_reset_stream_state_after_discont (demux);
473 GST_OBJECT_UNLOCK (demux);
474 gst_asf_demux_send_event_unlocked (demux, event);
475 /* upon activation, latency is no longer introduced, e.g. after seek */
476 if (demux->activated_streams)
481 ret = gst_pad_event_default (pad, parent, event);
489 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
490 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
491 gboolean next, gboolean * eos)
493 GstClockTime idx_time;
499 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
502 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
505 /* if we want the next keyframe, we have to go forward till we find
506 a different packet number */
508 if (idx >= demux->sidx_num_entries - 1) {
509 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
514 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
515 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
522 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
528 *packet = demux->sidx_entries[idx].packet;
530 *speed = demux->sidx_entries[idx].count;
532 /* so we get closer to the actual time of the packet ... actually, let's not
533 * do this, since we throw away superfluous payloads before the seek position
534 * anyway; this way, our key unit seek 'snap resolution' is a bit better
535 * (ie. same as index resolution) */
537 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
541 idx_time = demux->sidx_interval * idx;
542 if (G_LIKELY (idx_time >= demux->preroll))
543 idx_time -= demux->preroll;
545 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
546 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
547 GST_TIME_ARGS (idx_time));
549 if (G_LIKELY (p_idx_time))
550 *p_idx_time = idx_time;
556 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
560 gst_adapter_clear (demux->adapter);
562 GST_DEBUG_OBJECT (demux, "reset stream state");
564 gst_flow_combiner_reset (demux->flowcombiner);
565 for (n = 0; n < demux->num_streams; n++) {
566 demux->stream[n].discont = TRUE;
567 demux->stream[n].first_buffer = TRUE;
569 while (demux->stream[n].payloads->len > 0) {
573 last = demux->stream[n].payloads->len - 1;
574 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
575 gst_buffer_replace (&payload->buf, NULL);
576 g_array_remove_index (demux->stream[n].payloads, last);
582 gst_asf_demux_mark_discont (GstASFDemux * demux)
586 GST_DEBUG_OBJECT (demux, "Mark stream discont");
588 for (n = 0; n < demux->num_streams; n++)
589 demux->stream[n].discont = TRUE;
592 /* do a seek in push based mode */
594 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
599 GstSeekType cur_type, stop_type;
603 GstEvent *byte_event;
605 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
608 stop_type = GST_SEEK_TYPE_NONE;
611 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
613 /* determine packet, by index or by estimation */
614 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
617 (guint) gst_util_uint64_scale (demux->num_packets, cur,
621 if (packet > demux->num_packets) {
622 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
627 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
629 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
631 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
632 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
633 /* BYTE seek event */
634 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
635 cur, stop_type, stop);
636 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
637 res = gst_pad_push_event (demux->sinkpad, byte_event);
643 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
645 GstClockTime idx_time;
648 GstSeekType cur_type, stop_type;
650 gboolean only_need_update;
651 gboolean after, before, next;
656 guint packet, speed_count = 1;
662 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
665 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
666 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
670 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
671 * so first try to let it handle the seek event. */
672 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
675 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
676 demux->num_packets == 0 || demux->play_time == 0)) {
677 GST_LOG_OBJECT (demux, "stream is not seekable");
681 if (G_UNLIKELY (!demux->activated_streams)) {
682 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
686 if (G_UNLIKELY (rate <= 0.0)) {
687 GST_LOG_OBJECT (demux, "backward playback");
688 demux->seek_to_cur_pos = TRUE;
689 for (i = 0; i < demux->num_streams; i++) {
690 demux->stream[i].reverse_kf_ready = FALSE;
694 seqnum = gst_event_get_seqnum (event);
695 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
697 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
698 demux->keyunit_sync =
699 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
700 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
701 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
702 next = after && !before;
704 if (G_UNLIKELY (demux->streaming)) {
705 /* support it safely needs more segment handling, e.g. closing etc */
707 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
710 /* we can (re)construct the start later on, but not the end */
711 if (stop_type != GST_SEEK_TYPE_NONE &&
712 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
713 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
716 return gst_asf_demux_handle_seek_push (demux, event);
719 /* unlock the streaming thread */
720 if (G_LIKELY (flush)) {
721 fevent = gst_event_new_flush_start ();
723 gst_event_set_seqnum (fevent, seqnum);
724 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
725 gst_asf_demux_send_event_unlocked (demux, fevent);
727 gst_pad_pause_task (demux->sinkpad);
730 /* grab the stream lock so that streaming cannot continue, for
731 * non flushing seeks when the element is in PAUSED this could block
733 GST_PAD_STREAM_LOCK (demux->sinkpad);
735 /* we now can stop flushing, since we have the stream lock now */
736 fevent = gst_event_new_flush_stop (TRUE);
737 gst_event_set_seqnum (fevent, seqnum);
738 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
740 if (G_LIKELY (flush))
741 gst_asf_demux_send_event_unlocked (demux, fevent);
743 gst_event_unref (fevent);
745 /* operating on copy of segment until we know the seek worked */
746 segment = demux->segment;
748 if (G_UNLIKELY (demux->segment_running && !flush)) {
749 GstSegment newsegment;
752 /* create the segment event to close the current segment */
753 gst_segment_copy_into (&segment, &newsegment);
754 newseg = gst_event_new_segment (&newsegment);
755 gst_event_set_seqnum (newseg, seqnum);
757 gst_asf_demux_send_event_unlocked (demux, newseg);
760 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
761 cur, stop_type, stop, &only_need_update);
763 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
764 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
766 if (cur_type != GST_SEEK_TYPE_SET)
767 seek_time = segment.start;
771 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
772 * real start of data and segment_start to indexed time for key unit seek*/
773 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
774 &idx_time, &speed_count, next, &eos))) {
778 demux->packet = demux->num_packets;
782 /* First try to query our source to see if it can convert for us. This is
783 the case when our source is an mms stream, notice that in this case
784 gstmms will do a time based seek to get the byte offset, this is not a
785 problem as the seek to this offset needs to happen anway. */
786 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
787 GST_FORMAT_BYTES, &offset)) {
788 packet = (offset - demux->data_offset) / demux->packet_size;
789 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
790 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
791 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
792 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
793 demux->packet_size, packet);
795 /* FIXME: For streams containing video, seek to an earlier position in
796 * the hope of hitting a keyframe and let the sinks throw away the stuff
797 * before the segment start. For audio-only this is unnecessary as every
799 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
800 && demux->num_video_streams > 0) {
801 seek_time -= 5 * GST_SECOND;
806 packet = (guint) gst_util_uint64_scale (demux->num_packets,
807 seek_time, demux->play_time);
809 if (packet > demux->num_packets)
810 packet = demux->num_packets;
813 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
814 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
815 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
816 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
817 segment.start = idx_time;
818 segment.position = idx_time;
819 segment.time = idx_time;
823 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
825 GST_OBJECT_LOCK (demux);
826 demux->segment = segment;
827 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
828 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
829 stop, demux->play_time);
831 demux->packet = packet;
834 demux->need_newsegment = TRUE;
835 demux->segment_seqnum = seqnum;
836 demux->speed_packets =
837 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
838 gst_asf_demux_reset_stream_state_after_discont (demux);
839 GST_OBJECT_UNLOCK (demux);
842 /* restart our task since it might have been stopped when we did the flush */
843 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
846 /* streaming can continue now */
847 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
853 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
859 demux = GST_ASF_DEMUX (parent);
861 switch (GST_EVENT_TYPE (event)) {
863 GST_LOG_OBJECT (pad, "seek event");
864 ret = gst_asf_demux_handle_seek_event (demux, event);
865 gst_event_unref (event);
868 case GST_EVENT_NAVIGATION:
869 /* just drop these two silently */
870 gst_event_unref (event);
874 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
875 ret = gst_pad_event_default (pad, parent, event);
882 static inline guint32
883 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
887 ret = gst_asf_identify_guid (guids, guid);
889 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
890 gst_asf_get_guid_nick (guids, ret),
891 guid->v1, guid->v2, guid->v3, guid->v4);
903 /* Peek for an object.
905 * Returns FALSE is the object is corrupted (such as the reported
906 * object size being greater than 2**32bits.
909 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
910 guint data_len, AsfObject * object, gboolean expect)
914 /* Callers should have made sure that data_len is big enough */
915 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
917 if (data_len < ASF_OBJECT_HEADER_SIZE)
920 guid.v1 = GST_READ_UINT32_LE (data + 0);
921 guid.v2 = GST_READ_UINT32_LE (data + 4);
922 guid.v3 = GST_READ_UINT32_LE (data + 8);
923 guid.v4 = GST_READ_UINT32_LE (data + 12);
925 /* FIXME: make asf_demux_identify_object_guid() */
926 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
927 if (object->id == ASF_OBJ_UNDEFINED && expect) {
928 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
929 guid.v1, guid.v2, guid.v3, guid.v4);
932 object->size = GST_READ_UINT64_LE (data + 16);
933 if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
934 GST_WARNING_OBJECT (demux,
935 "ASF Object size corrupted (greater than 32bit)");
944 gst_asf_demux_release_old_pads (GstASFDemux * demux)
946 GST_DEBUG_OBJECT (demux, "Releasing old pads");
948 while (demux->old_num_streams > 0) {
949 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
950 gst_event_new_eos ());
951 gst_asf_demux_free_stream (demux,
952 &demux->old_stream[demux->old_num_streams - 1]);
953 --demux->old_num_streams;
955 memset (demux->old_stream, 0, sizeof (demux->old_stream));
956 demux->old_num_streams = 0;
960 gst_asf_demux_chain_headers (GstASFDemux * demux)
963 guint8 *header_data, *data = NULL;
964 const guint8 *cdata = NULL;
966 GstFlowReturn flow = GST_FLOW_OK;
968 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
972 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
974 if (obj.id != ASF_OBJ_HEADER)
977 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
979 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
980 if (gst_adapter_available (demux->adapter) < obj.size + 50)
983 data = gst_adapter_take (demux->adapter, obj.size + 50);
986 header_size = obj.size;
987 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
988 if (flow != GST_FLOW_OK)
991 /* calculate where the packet data starts */
992 demux->data_offset = obj.size + 50;
994 /* now parse the beginning of the ASF_OBJ_DATA object */
995 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
998 if (demux->num_streams == 0)
1007 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1014 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1015 ("This doesn't seem to be an ASF file"));
1017 return GST_FLOW_ERROR;
1022 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1023 ("header parsing failed, or no streams found, flow = %s",
1024 gst_flow_get_name (flow)));
1026 return GST_FLOW_ERROR;
1031 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1032 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1037 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1040 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1042 if (G_LIKELY (p_flow))
1045 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1046 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1047 "+%u", gst_flow_get_name (flow), offset, size);
1052 g_assert (*p_buf != NULL);
1054 buffer_size = gst_buffer_get_size (*p_buf);
1055 if (G_UNLIKELY (buffer_size < size)) {
1056 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1057 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1058 gst_buffer_unref (*p_buf);
1059 if (G_LIKELY (p_flow))
1060 *p_flow = GST_FLOW_EOS;
1068 static GstFlowReturn
1069 gst_asf_demux_pull_indices (GstASFDemux * demux)
1071 GstBuffer *buf = NULL;
1074 GstFlowReturn ret = GST_FLOW_OK;
1076 offset = demux->index_offset;
1078 if (G_UNLIKELY (offset == 0)) {
1079 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1084 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1090 gst_buffer_map (buf, &map, GST_MAP_READ);
1091 g_assert (map.size >= 16 + 8);
1092 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1093 gst_buffer_unmap (buf, &map);
1094 gst_buffer_replace (&buf, NULL);
1095 ret = GST_FLOW_ERROR;
1098 gst_buffer_unmap (buf, &map);
1099 gst_buffer_replace (&buf, NULL);
1101 /* check for sanity */
1102 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1103 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1107 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1111 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1112 ", size %u", offset, (guint) obj.size);
1114 offset += obj.size; /* increase before _process_object changes it */
1116 gst_buffer_map (buf, &map, GST_MAP_READ);
1117 g_assert (map.size >= obj.size);
1118 bufdata = (guint8 *) map.data;
1119 obj_size = obj.size;
1120 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1121 gst_buffer_unmap (buf, &map);
1122 gst_buffer_replace (&buf, NULL);
1124 if (G_UNLIKELY (ret != GST_FLOW_OK))
1130 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1135 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1139 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1140 GST_WARNING_OBJECT (demux, "Corrupted data");
1143 if (obj.id != ASF_OBJ_DATA) {
1144 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1148 demux->state = GST_ASF_DEMUX_STATE_DATA;
1150 if (!demux->broadcast && obj.size > 50) {
1151 demux->data_size = obj.size - 50;
1152 /* CHECKME: for at least one file this is off by +158 bytes?! */
1153 demux->index_offset = demux->data_offset + demux->data_size;
1155 demux->data_size = 0;
1156 demux->index_offset = 0;
1161 if (!demux->broadcast) {
1162 /* skip object header (24 bytes) and file GUID (16 bytes) */
1163 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1165 demux->num_packets = 0;
1168 if (demux->num_packets == 0)
1169 demux->seekable = FALSE;
1171 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1172 if (demux->data_size == 0 && demux->num_packets > 0) {
1173 demux->data_size = demux->num_packets * demux->packet_size;
1174 demux->index_offset = demux->data_offset + demux->data_size;
1177 /* process pending stream objects and create pads for those */
1178 gst_asf_demux_process_queued_extended_stream_objects (demux);
1180 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1181 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1182 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1183 demux->data_offset, demux->data_size, demux->index_offset);
1189 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1191 GstFlowReturn flow = GST_FLOW_OK;
1193 GstBuffer *buf = NULL;
1198 GST_LOG_OBJECT (demux, "reading headers");
1200 /* pull HEADER object header, so we know its size */
1201 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1204 gst_buffer_map (buf, &map, GST_MAP_READ);
1205 g_assert (map.size >= 16 + 8);
1206 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1207 gst_buffer_unmap (buf, &map);
1208 gst_buffer_replace (&buf, NULL);
1209 flow = GST_FLOW_ERROR;
1212 gst_buffer_unmap (buf, &map);
1213 gst_buffer_replace (&buf, NULL);
1215 if (obj.id != ASF_OBJ_HEADER)
1218 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1220 /* pull HEADER object */
1221 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1225 size = obj.size; /* don't want obj.size changed */
1226 gst_buffer_map (buf, &map, GST_MAP_READ);
1227 g_assert (map.size >= size);
1228 bufdata = (guint8 *) map.data;
1229 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1230 gst_buffer_unmap (buf, &map);
1231 gst_buffer_replace (&buf, NULL);
1233 if (flow != GST_FLOW_OK) {
1234 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1238 /* calculate where the packet data starts */
1239 demux->data_offset = demux->base_offset + obj.size + 50;
1241 /* now pull beginning of DATA object before packet data */
1242 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1246 gst_buffer_map (buf, &map, GST_MAP_READ);
1247 g_assert (map.size >= size);
1248 bufdata = (guint8 *) map.data;
1249 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1252 if (demux->num_streams == 0)
1255 gst_buffer_unmap (buf, &map);
1256 gst_buffer_replace (&buf, NULL);
1264 gst_buffer_unmap (buf, &map);
1265 gst_buffer_replace (&buf, NULL);
1267 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1268 ("This doesn't seem to be an ASF file"));
1269 *pflow = GST_FLOW_ERROR;
1274 flow = GST_FLOW_ERROR;
1275 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1276 ("header parsing failed, or no streams found, flow = %s",
1277 gst_flow_get_name (flow)));
1282 gst_buffer_unmap (buf, &map);
1283 gst_buffer_replace (&buf, NULL);
1284 if (flow == ASF_FLOW_NEED_MORE_DATA)
1285 flow = GST_FLOW_ERROR;
1292 all_streams_prerolled (GstASFDemux * demux)
1294 GstClockTime preroll_time;
1295 guint i, num_no_data = 0;
1297 /* Allow at least 500ms of preroll_time */
1298 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1300 /* returns TRUE as long as there isn't a stream which (a) has data queued
1301 * and (b) the timestamp of last piece of data queued is < demux->preroll
1302 * AND there is at least one other stream with data queued */
1303 for (i = 0; i < demux->num_streams; ++i) {
1304 AsfPayload *last_payload = NULL;
1308 stream = &demux->stream[i];
1309 if (G_UNLIKELY (stream->payloads->len == 0)) {
1311 GST_LOG_OBJECT (stream->pad, "no data queued");
1315 /* find last payload with timestamp */
1316 for (last_idx = stream->payloads->len - 1;
1317 last_idx >= 0 && (last_payload == NULL
1318 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1319 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1322 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1323 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1324 GST_TIME_ARGS (preroll_time));
1325 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1326 || last_payload->ts <= preroll_time)) {
1327 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1332 if (G_UNLIKELY (num_no_data > 0))
1340 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1345 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1348 /* check for each mutual exclusion group whether it affects this stream */
1349 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1350 if (*mes == stream->id) {
1351 /* we are in this group; let's check if we've already activated streams
1352 * that are in the same group (and hence mutually exclusive to this
1354 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1357 for (i = 0; i < demux->num_streams; ++i) {
1358 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1359 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1360 "to already active stream with ID %d", stream->id,
1361 demux->stream[i].id);
1366 /* we can only be in this group once, let's break out and move on to
1367 * the next mutual exclusion group */
1378 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1380 /* remember the first queued timestamp for the segment */
1381 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1382 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1383 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1384 GST_TIME_ARGS (demux->first_ts));
1385 demux->segment_ts = payload_ts;
1386 /* always note, but only determines segment when streaming */
1387 if (demux->streaming)
1388 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1389 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1390 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1395 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1397 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1398 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1401 /* go trhough each stream, find smallest timestamp */
1402 for (i = 0; i < demux->num_streams; ++i) {
1405 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1406 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1407 stream = &demux->stream[i];
1409 for (j = 0; j < stream->payloads->len; ++j) {
1410 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1411 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1412 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1413 || stream_min_ts > payload->ts)) {
1414 stream_min_ts = payload->ts;
1416 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1417 payload->ts > stream_min_ts &&
1418 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1419 || stream_min_ts2 > payload->ts)) {
1420 stream_min_ts2 = payload->ts;
1424 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1425 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1426 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1427 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1428 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1430 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1433 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1434 stream_min_ts = stream_min_ts2;
1436 /* if we don't have timestamp for this stream, wait for more data */
1437 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1440 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1441 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1442 first_ts = stream_min_ts;
1445 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1448 demux->first_ts = first_ts;
1450 /* update packets queued before we knew first timestamp */
1451 for (i = 0; i < demux->num_streams; ++i) {
1454 stream = &demux->stream[i];
1456 for (j = 0; j < stream->payloads->len; ++j) {
1457 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1458 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1459 if (payload->ts > first_ts)
1460 payload->ts -= first_ts;
1468 gst_asf_demux_check_segment_ts (demux, 0);
1474 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1476 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1477 and often set wrong, inspecting the data is the only way that seem to be working */
1478 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1479 GstCaps *caps = NULL;
1481 GstAdapter *adapter = gst_adapter_new ();
1483 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1485 AsfPayload *payload;
1488 payload = &g_array_index (stream->payloads, AsfPayload, i);
1489 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1490 len = gst_adapter_available (adapter);
1491 data = gst_adapter_map (adapter, len);
1495 #define MIN_LENGTH 128
1497 /* look for the sync points */
1499 if (len < MIN_LENGTH || /* give typefind something to work on */
1500 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1501 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1507 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1510 if (prob < GST_TYPE_FIND_LIKELY) {
1513 if (len > MIN_LENGTH)
1514 /* this wasn't it, look for another sync point */
1518 gst_adapter_unmap (adapter);
1521 gst_object_unref (adapter);
1524 gst_caps_take (&stream->caps, caps);
1532 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1534 guint i, actual_streams = 0;
1536 if (demux->activated_streams)
1539 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1542 if (!all_streams_prerolled (demux) && !force) {
1543 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1547 for (i = 0; i < demux->num_streams; ++i) {
1548 AsfStream *stream = &demux->stream[i];
1550 if (stream->payloads->len > 0) {
1552 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1553 !stream->active && /* do not inspect active streams (caps were already set) */
1554 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1555 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1556 /* try to gather some more data */
1559 /* we don't check mutual exclusion stuff here; either we have data for
1560 * a stream, then we active it, or we don't, then we'll ignore it */
1561 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1562 gst_asf_demux_activate_stream (demux, stream);
1563 actual_streams += 1;
1565 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1569 if (actual_streams == 0) {
1570 /* We don't have any streams activated ! */
1571 GST_ERROR_OBJECT (demux, "No streams activated!");
1575 gst_asf_demux_release_old_pads (demux);
1577 demux->activated_streams = TRUE;
1578 GST_LOG_OBJECT (demux, "signalling no more pads");
1579 gst_element_no_more_pads (GST_ELEMENT (demux));
1583 /* returns the stream that has a complete payload with the lowest timestamp
1584 * queued, or NULL (we push things by timestamp because during the internal
1585 * prerolling we might accumulate more data then the external queues can take,
1586 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1588 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1590 AsfPayload *best_payload = NULL;
1591 AsfStream *best_stream = NULL;
1594 for (i = 0; i < demux->num_streams; ++i) {
1598 stream = &demux->stream[i];
1600 /* Don't push any data until we have at least one payload that falls within
1601 * the current segment. This way we can remove out-of-segment payloads that
1602 * don't need to be decoded after a seek, sending only data from the
1603 * keyframe directly before our segment start */
1604 if (stream->payloads->len > 0) {
1605 AsfPayload *payload = NULL;
1608 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1609 /* Reverse playback */
1611 if (stream->is_video) {
1612 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1613 if (stream->reverse_kf_ready) {
1615 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1616 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1617 /* TODO : remove payload from the list? */
1624 /* find first complete payload with timestamp */
1625 for (j = stream->payloads->len - 1;
1626 j >= 0 && (payload == NULL
1627 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1628 payload = &g_array_index (stream->payloads, AsfPayload, j);
1631 /* If there's a complete payload queued for this stream */
1632 if (!gst_asf_payload_is_complete (payload))
1638 /* find last payload with timestamp */
1639 for (last_idx = stream->payloads->len - 1;
1640 last_idx >= 0 && (payload == NULL
1641 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1642 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1645 /* if this is first payload after seek we might need to update the segment */
1646 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1647 gst_asf_demux_check_segment_ts (demux, payload->ts);
1649 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1650 (payload->ts < demux->segment.start))) {
1651 if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1652 && payload->keyframe)) {
1653 GST_DEBUG_OBJECT (stream->pad,
1654 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1655 GST_TIME_ARGS (payload->ts));
1656 demux->segment.start = payload->ts;
1657 demux->segment.time = payload->ts;
1659 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1660 GST_TIME_FORMAT " which is before our segment start %"
1661 GST_TIME_FORMAT ", not pushing yet",
1662 GST_TIME_ARGS (payload->ts),
1663 GST_TIME_ARGS (demux->segment.start));
1668 /* find first complete payload with timestamp */
1670 j < stream->payloads->len && (payload == NULL
1671 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1672 payload = &g_array_index (stream->payloads, AsfPayload, j);
1675 /* Now see if there's a complete payload queued for this stream */
1676 if (!gst_asf_payload_is_complete (payload))
1680 /* ... and whether its timestamp is lower than the current best */
1681 if (best_stream == NULL || best_payload->ts > payload->ts) {
1682 best_stream = stream;
1683 best_payload = payload;
1691 static GstFlowReturn
1692 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1695 GstFlowReturn ret = GST_FLOW_OK;
1697 if (G_UNLIKELY (!demux->activated_streams)) {
1698 if (!gst_asf_demux_check_activate_streams (demux, force))
1700 /* streams are now activated */
1703 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1704 AsfPayload *payload;
1705 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1706 GstClockTime duration = GST_CLOCK_TIME_NONE;
1708 /* wait until we had a chance to "lock on" some payload's timestamp */
1709 if (G_UNLIKELY (demux->need_newsegment
1710 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1713 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1714 && stream->payloads->len) {
1715 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1717 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1720 /* do we need to send a newsegment event */
1721 if ((G_UNLIKELY (demux->need_newsegment))) {
1722 GstEvent *segment_event;
1724 /* safe default if insufficient upstream info */
1725 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1728 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1729 demux->segment.duration > 0) {
1730 /* slight HACK; prevent clipping of last bit */
1731 demux->segment.stop = demux->segment.duration + demux->in_gap;
1734 /* FIXME : only if ACCURATE ! */
1735 if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1736 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1737 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1738 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1739 GST_TIME_ARGS (payload->ts));
1740 demux->segment.start = payload->ts;
1741 demux->segment.time = payload->ts;
1744 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1747 /* note: we fix up all timestamps to start from 0, so this should be ok */
1748 segment_event = gst_event_new_segment (&demux->segment);
1749 if (demux->segment_seqnum)
1750 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1751 gst_asf_demux_send_event_unlocked (demux, segment_event);
1753 /* now post any global tags we may have found */
1754 if (demux->taglist == NULL) {
1755 demux->taglist = gst_tag_list_new_empty ();
1756 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1759 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1760 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1762 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1763 gst_asf_demux_send_event_unlocked (demux,
1764 gst_event_new_tag (demux->taglist));
1765 demux->taglist = NULL;
1767 demux->need_newsegment = FALSE;
1768 demux->segment_seqnum = 0;
1769 demux->segment_running = TRUE;
1772 /* Do we have tags pending for this stream? */
1773 if (G_UNLIKELY (stream->pending_tags)) {
1774 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1775 gst_pad_push_event (stream->pad,
1776 gst_event_new_tag (stream->pending_tags));
1777 stream->pending_tags = NULL;
1780 /* We have the whole packet now so we should push the packet to
1781 * the src pad now. First though we should check if we need to do
1783 if (G_UNLIKELY (stream->span > 1)) {
1784 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1787 payload->buf = gst_buffer_make_writable (payload->buf);
1789 if (G_LIKELY (!payload->keyframe)) {
1790 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1793 if (G_UNLIKELY (stream->discont)) {
1794 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1795 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1796 stream->discont = FALSE;
1799 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1800 (payload->par_x != stream->par_x) &&
1801 (payload->par_y != stream->par_y))) {
1802 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1803 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1804 stream->par_x = payload->par_x;
1805 stream->par_y = payload->par_y;
1806 stream->caps = gst_caps_make_writable (stream->caps);
1807 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1808 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1809 gst_pad_set_caps (stream->pad, stream->caps);
1812 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1813 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1814 payload->interlaced);
1815 stream->interlaced = payload->interlaced;
1816 stream->caps = gst_caps_make_writable (stream->caps);
1817 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1818 (stream->interlaced ? "mixed" : "progressive"), NULL);
1819 gst_pad_set_caps (stream->pad, stream->caps);
1822 /* (sort of) interpolate timestamps using upstream "frame of reference",
1823 * typically useful for live src, but might (unavoidably) mess with
1824 * position reporting if a live src is playing not so live content
1825 * (e.g. rtspsrc taking some time to fall back to tcp) */
1826 timestamp = payload->ts;
1827 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1828 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1829 timestamp += demux->in_gap;
1831 /* Check if we're after the segment already, if so no need to push
1833 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1834 GST_DEBUG_OBJECT (stream->pad,
1835 "Payload after segment stop %" GST_TIME_FORMAT,
1836 GST_TIME_ARGS (demux->segment.stop));
1838 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1840 gst_buffer_unref (payload->buf);
1841 payload->buf = NULL;
1842 g_array_remove_index (stream->payloads, 0);
1843 /* Break out as soon as we have an issue */
1844 if (G_UNLIKELY (ret != GST_FLOW_OK))
1851 GST_BUFFER_PTS (payload->buf) = timestamp;
1853 if (payload->duration == GST_CLOCK_TIME_NONE
1854 && stream->ext_props.avg_time_per_frame != 0) {
1855 duration = stream->ext_props.avg_time_per_frame * 100;
1857 duration = payload->duration;
1859 GST_BUFFER_DURATION (payload->buf) = duration;
1861 /* FIXME: we should really set durations on buffers if we can */
1863 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1866 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1867 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1868 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1870 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1871 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1875 if (stream->active) {
1876 if (G_UNLIKELY (stream->first_buffer)) {
1877 if (stream->streamheader != NULL) {
1878 GST_DEBUG_OBJECT (stream->pad,
1879 "Pushing streamheader before first buffer");
1880 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1882 stream->first_buffer = FALSE;
1885 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1886 && timestamp > demux->segment.position) {
1887 demux->segment.position = timestamp;
1888 if (GST_CLOCK_TIME_IS_VALID (duration))
1889 demux->segment.position += timestamp;
1892 ret = gst_pad_push (stream->pad, payload->buf);
1894 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1897 gst_buffer_unref (payload->buf);
1900 payload->buf = NULL;
1901 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1902 && stream->reverse_kf_ready) {
1903 g_array_remove_index (stream->payloads, stream->kf_pos);
1906 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1908 stream->reverse_kf_ready = FALSE;
1911 g_array_remove_index (stream->payloads, 0);
1914 /* Break out as soon as we have an issue */
1915 if (G_UNLIKELY (ret != GST_FLOW_OK))
1923 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1928 g_assert (buf != NULL);
1930 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1932 gst_buffer_map (buf, &map, GST_MAP_READ);
1934 /* we return false on buffer too small */
1935 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1936 gst_buffer_unmap (buf, &map);
1940 /* check if it is a header */
1942 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1944 gst_buffer_unmap (buf, &map);
1945 if (valid && obj.id == ASF_OBJ_HEADER) {
1952 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1954 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1955 GstFlowReturn ret = GST_FLOW_OK;
1956 GstBuffer *buf = NULL;
1957 gboolean header = FALSE;
1959 /* TODO maybe we should skip index objects after the data and look
1960 * further for a new header */
1961 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1962 g_assert (buf != NULL);
1963 /* check if it is a header */
1964 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1965 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1966 demux->base_offset = off;
1970 gst_buffer_unref (buf);
1977 gst_asf_demux_loop (GstASFDemux * demux)
1979 GstFlowReturn flow = GST_FLOW_OK;
1980 GstBuffer *buf = NULL;
1983 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1984 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1988 flow = gst_asf_demux_pull_indices (demux);
1989 if (flow != GST_FLOW_OK)
1993 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1995 if (G_UNLIKELY (demux->num_packets != 0
1996 && demux->packet >= demux->num_packets))
1999 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2000 (guint) demux->num_packets);
2002 off = demux->data_offset + (demux->packet * demux->packet_size);
2004 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2005 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2006 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2007 if (flow == GST_FLOW_EOS) {
2009 } else if (flow == GST_FLOW_FLUSHING) {
2010 GST_DEBUG_OBJECT (demux, "Not fatal");
2017 if (G_LIKELY (demux->speed_packets == 1)) {
2018 GstAsfDemuxParsePacketError err;
2019 err = gst_asf_demux_parse_packet (demux, buf);
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, buf)) {
2025 GST_INFO_OBJECT (demux, "Chained asf found");
2026 demux->base_offset = off;
2027 gst_asf_demux_reset (demux, TRUE);
2028 gst_buffer_unref (buf);
2032 /* FIXME: We should tally up fatal errors and error out only
2033 * after a few broken packets in a row? */
2035 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2036 gst_buffer_unref (buf);
2038 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2039 && !demux->seek_to_cur_pos) {
2041 if (demux->packet < 0) {
2051 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2053 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2054 && !demux->seek_to_cur_pos) {
2056 if (demux->packet < 0) {
2065 for (n = 0; n < demux->speed_packets; n++) {
2067 GstAsfDemuxParsePacketError err;
2070 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2071 n * demux->packet_size, demux->packet_size);
2072 err = gst_asf_demux_parse_packet (demux, sub);
2073 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2074 /* when we don't know when the data object ends, we should check
2075 * for a chained asf */
2076 if (demux->num_packets == 0) {
2077 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2078 GST_INFO_OBJECT (demux, "Chained asf found");
2079 demux->base_offset = off + n * demux->packet_size;
2080 gst_asf_demux_reset (demux, TRUE);
2081 gst_buffer_unref (sub);
2082 gst_buffer_unref (buf);
2086 /* FIXME: We should tally up fatal errors and error out only
2087 * after a few broken packets in a row? */
2089 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2093 gst_buffer_unref (sub);
2095 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2096 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2102 /* reset speed pull */
2103 demux->speed_packets = 1;
2106 gst_buffer_unref (buf);
2108 if (G_UNLIKELY ((demux->num_packets > 0
2109 && demux->packet >= demux->num_packets)
2110 || flow == GST_FLOW_EOS)) {
2111 GST_LOG_OBJECT (demux, "reached EOS");
2115 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2116 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2120 /* check if we're at the end of the configured segment */
2121 /* FIXME: check if segment end reached etc. */
2127 /* if we haven't activated our streams yet, this might be because we have
2128 * less data queued than required for preroll; force stream activation and
2129 * send any pending payloads before sending EOS */
2130 if (!demux->activated_streams)
2131 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2133 /* we want to push an eos or post a segment-done in any case */
2134 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2137 /* for segment playback we need to post when (in stream time)
2138 * we stopped, this is either stop (when set) or the duration. */
2139 if ((stop = demux->segment.stop) == -1)
2140 stop = demux->segment.duration;
2142 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2143 gst_element_post_message (GST_ELEMENT_CAST (demux),
2144 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2146 gst_asf_demux_send_event_unlocked (demux,
2147 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2148 } else if (flow != GST_FLOW_EOS) {
2149 /* check if we have a chained asf, in case, we don't eos yet */
2150 if (gst_asf_demux_check_chained_asf (demux)) {
2151 GST_INFO_OBJECT (demux, "Chained ASF starting");
2152 gst_asf_demux_reset (demux, TRUE);
2157 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2158 if (demux->activated_streams) {
2159 /* normal playback, send EOS to all linked pads */
2160 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2161 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2163 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2164 flow = GST_FLOW_EOS;
2167 /* ... and fall through to pause */
2171 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2172 gst_flow_get_name (flow));
2173 demux->segment_running = FALSE;
2174 gst_pad_pause_task (demux->sinkpad);
2176 /* For the error cases */
2177 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2178 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2179 ("This doesn't seem to be an ASF file"));
2180 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2181 /* Post an error. Hopefully something else already has, but if not... */
2182 GST_ELEMENT_FLOW_ERROR (demux, flow);
2183 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2192 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2193 flow = GST_FLOW_EOS;
2197 /* See FIXMEs above */
2200 gst_buffer_unref (buf);
2201 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2202 ("Error parsing ASF packet %u", (guint) demux->packet));
2203 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2204 flow = GST_FLOW_ERROR;
2210 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2211 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2212 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2215 gst_asf_demux_check_header (GstASFDemux * demux)
2218 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2219 ASF_OBJECT_HEADER_SIZE);
2220 if (cdata == NULL) /* need more data */
2221 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2223 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE
2224 && obj.id == ASF_OBJ_HEADER))
2225 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2227 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2230 static GstFlowReturn
2231 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2233 GstFlowReturn ret = GST_FLOW_OK;
2236 demux = GST_ASF_DEMUX (parent);
2238 GST_LOG_OBJECT (demux,
2239 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2240 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2241 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2243 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2244 GST_DEBUG_OBJECT (demux, "received DISCONT");
2245 gst_asf_demux_mark_discont (demux);
2248 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2249 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2250 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2251 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2252 ", interpolation gap: %" GST_TIME_FORMAT,
2253 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2256 gst_adapter_push (demux->adapter, buf);
2258 switch (demux->state) {
2259 case GST_ASF_DEMUX_STATE_INDEX:{
2260 gint result = gst_asf_demux_check_header (demux);
2261 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2264 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2265 /* we don't care about this, probably an index */
2266 /* TODO maybe would be smarter to skip all the indices
2267 * until we got a new header or EOS to decide */
2268 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2271 GST_INFO_OBJECT (demux, "Chained asf starting");
2272 /* cleanup and get ready for a chained asf */
2273 gst_asf_demux_reset (demux, TRUE);
2277 case GST_ASF_DEMUX_STATE_HEADER:{
2278 ret = gst_asf_demux_chain_headers (demux);
2279 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2281 /* otherwise fall through */
2283 case GST_ASF_DEMUX_STATE_DATA:
2287 data_size = demux->packet_size;
2289 while (gst_adapter_available (demux->adapter) >= data_size) {
2291 GstAsfDemuxParsePacketError err;
2293 /* we don't know the length of the stream
2294 * check for a chained asf everytime */
2295 if (demux->num_packets == 0) {
2296 gint result = gst_asf_demux_check_header (demux);
2298 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2299 GST_INFO_OBJECT (demux, "Chained asf starting");
2300 /* cleanup and get ready for a chained asf */
2301 gst_asf_demux_reset (demux, TRUE);
2304 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2305 && demux->packet >= demux->num_packets)) {
2306 /* do not overshoot data section when streaming */
2310 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2312 /* FIXME: We should tally up fatal errors and error out only
2313 * after a few broken packets in a row? */
2314 err = gst_asf_demux_parse_packet (demux, buf);
2316 gst_buffer_unref (buf);
2318 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2319 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2321 GST_WARNING_OBJECT (demux, "Parse error");
2323 if (demux->packet >= 0)
2326 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2327 && demux->packet >= demux->num_packets)) {
2328 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2333 g_assert_not_reached ();
2337 if (ret != GST_FLOW_OK)
2338 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2344 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2350 static inline gboolean
2351 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2353 if (*p_size < num_bytes)
2356 *p_data += num_bytes;
2357 *p_size -= num_bytes;
2361 static inline guint8
2362 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2366 g_assert (*p_size >= 1);
2367 ret = GST_READ_UINT8 (*p_data);
2368 *p_data += sizeof (guint8);
2369 *p_size -= sizeof (guint8);
2373 static inline guint16
2374 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2378 g_assert (*p_size >= 2);
2379 ret = GST_READ_UINT16_LE (*p_data);
2380 *p_data += sizeof (guint16);
2381 *p_size -= sizeof (guint16);
2385 static inline guint32
2386 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2390 g_assert (*p_size >= 4);
2391 ret = GST_READ_UINT32_LE (*p_data);
2392 *p_data += sizeof (guint32);
2393 *p_size -= sizeof (guint32);
2397 static inline guint64
2398 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2402 g_assert (*p_size >= 8);
2403 ret = GST_READ_UINT64_LE (*p_data);
2404 *p_data += sizeof (guint64);
2405 *p_size -= sizeof (guint64);
2410 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2411 guint8 ** p_data, guint64 * p_size)
2415 if (*p_size < num_bytes_to_read)
2418 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2419 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2421 *p_data += num_bytes_to_read;
2422 *p_size -= num_bytes_to_read;
2428 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2429 guint8 ** p_data, guint64 * p_size)
2433 if (*p_size < num_bytes_to_read)
2436 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2437 *p_data += num_bytes_to_read;
2438 *p_size -= num_bytes_to_read;
2443 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2444 guint8 ** p_data, guint64 * p_size)
2454 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2457 *p_strlen = s_length;
2459 if (s_length == 0) {
2460 GST_WARNING ("zero-length string");
2461 *p_str = g_strdup ("");
2465 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2468 g_assert (s != NULL);
2470 /* just because They don't exist doesn't
2471 * mean They are not out to get you ... */
2472 if (s[s_length - 1] != '\0') {
2473 s = g_realloc (s, s_length + 1);
2477 *p_str = (gchar *) s;
2483 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2485 g_assert (*p_size >= 4 * sizeof (guint32));
2487 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2488 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2489 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2490 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2494 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2497 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2500 /* WAVEFORMATEX Structure */
2501 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2502 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2503 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2504 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2505 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2506 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2507 /* Codec specific data size */
2508 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2509 if (audio->size > *p_size) {
2510 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2511 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2518 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2521 if (*p_size < (4 + 4 + 1 + 2))
2524 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2525 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2526 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2527 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2532 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2533 guint8 ** p_data, guint64 * p_size)
2535 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2538 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2540 if (fmt->size < 40) {
2541 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2544 if ((guint64) fmt->size - 4 > *p_size) {
2545 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2548 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2549 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2550 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2551 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2552 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2553 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2554 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2555 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2556 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2557 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2562 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2566 for (i = 0; i < demux->num_streams; i++) {
2567 if (demux->stream[i].id == id)
2568 return &demux->stream[i];
2571 if (gst_asf_demux_is_unknown_stream (demux, id))
2572 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2577 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2578 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2583 gst_pad_use_fixed_caps (src_pad);
2584 gst_pad_set_caps (src_pad, caps);
2586 gst_pad_set_event_function (src_pad,
2587 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2588 gst_pad_set_query_function (src_pad,
2589 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2591 stream = &demux->stream[demux->num_streams];
2592 stream->caps = caps;
2593 stream->pad = src_pad;
2595 stream->fps_known = !is_video; /* bit hacky for audio */
2596 stream->is_video = is_video;
2597 stream->pending_tags = tags;
2598 stream->discont = TRUE;
2599 stream->first_buffer = TRUE;
2600 stream->streamheader = streamheader;
2601 if (stream->streamheader) {
2602 stream->streamheader = gst_buffer_make_writable (streamheader);
2603 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2608 st = gst_caps_get_structure (caps, 0);
2609 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2610 par_x > 0 && par_y > 0) {
2611 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2612 stream->par_x = par_x;
2613 stream->par_y = par_y;
2617 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2619 /* TODO: create this array during reverse play? */
2620 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2622 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2623 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2625 ++demux->num_streams;
2627 stream->active = FALSE;
2633 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2634 GstBuffer * buffer, GstStructure * structure)
2636 GValue arr_val = G_VALUE_INIT;
2637 GValue buf_val = G_VALUE_INIT;
2639 g_value_init (&arr_val, GST_TYPE_ARRAY);
2640 g_value_init (&buf_val, GST_TYPE_BUFFER);
2642 gst_value_set_buffer (&buf_val, buffer);
2643 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2645 gst_structure_take_value (structure, "streamheader", &arr_val);
2649 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2650 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2652 GstTagList *tags = NULL;
2653 GstBuffer *extradata = NULL;
2656 guint16 size_left = 0;
2657 gchar *codec_name = NULL;
2660 size_left = audio->size;
2662 /* Create the audio pad */
2663 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2665 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2668 /* Swallow up any left over data and set up the
2669 * standard properties from the header info */
2671 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2672 "codec specific data", size_left);
2674 g_assert (size_left <= *p_size);
2675 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2678 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2679 * additional two bytes indicating extradata. */
2680 /* FIXME: Handle the channel reorder map here */
2681 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2682 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2685 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2686 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2689 /* Informing about that audio format we just added */
2691 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2692 g_free (codec_name);
2695 if (audio->byte_rate > 0) {
2696 /* Some ASF files have no bitrate props object (often seen with
2697 * ASF files that contain raw audio data). Example files can
2698 * be generated with FFmpeg (tested with v2.8.6), like this:
2700 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2702 * In this case, if audio->byte_rate is nonzero, use that as
2705 guint bitrate = audio->byte_rate * 8;
2708 tags = gst_tag_list_new_empty ();
2710 /* Add bitrate, but only if there is none set already, since
2711 * this is just a fallback in case there is no bitrate tag
2712 * already present */
2713 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2717 gst_buffer_unref (extradata);
2719 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2720 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2721 audio->codec_tag, tags);
2723 ++demux->num_audio_streams;
2725 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2729 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2730 asf_stream_video_format * video, guint16 id,
2731 guint8 ** p_data, guint64 * p_size)
2733 GstTagList *tags = NULL;
2734 GstStructure *caps_s;
2735 GstBuffer *extradata = NULL;
2740 gchar *codec_name = NULL;
2741 guint64 size_left = video->size - 40;
2742 GstBuffer *streamheader = NULL;
2743 guint par_w = 1, par_h = 1;
2745 /* Create the video pad */
2746 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2747 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2750 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2752 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2753 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2755 g_assert (size_left <= *p_size);
2756 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2759 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2761 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2762 caps = gst_riff_create_video_caps (video->tag, NULL,
2763 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2766 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2767 G_TYPE_UINT, video->tag, NULL);
2772 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2773 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2774 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2777 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2781 /* retry with the global metadata */
2782 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2783 demux->global_metadata);
2784 s = demux->global_metadata;
2785 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2786 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2787 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2788 if (ax > 0 && ay > 0) {
2791 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2796 s = gst_caps_get_structure (caps, 0);
2797 gst_structure_remove_field (s, "framerate");
2800 caps_s = gst_caps_get_structure (caps, 0);
2802 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2803 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2804 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2805 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2808 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2809 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2810 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2812 GstBuffer *buf = gst_value_get_buffer (value);
2815 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2816 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2817 /* this looks like a bytestream start */
2818 streamheader = gst_buffer_ref (buf);
2819 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2820 gst_structure_remove_field (caps_s, "codec_data");
2823 gst_buffer_unmap (buf, &mapinfo);
2828 /* For a 3D video, set multiview information into the caps based on
2829 * what was detected during object parsing */
2830 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2831 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2832 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2833 const gchar *mview_mode_str;
2835 switch (demux->asf_3D_mode) {
2836 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2837 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2839 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2840 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2841 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2843 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2844 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2846 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2847 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2848 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2850 case GST_ASF_3D_DUAL_STREAM:{
2851 gboolean is_right_view = FALSE;
2852 /* if Advanced_Mutual_Exclusion object exists, use it
2853 * to figure out which is the left view (lower ID) */
2854 if (demux->mut_ex_streams != NULL) {
2858 length = g_slist_length (demux->mut_ex_streams);
2860 for (i = 0; i < length; i++) {
2863 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2865 GST_DEBUG_OBJECT (demux,
2866 "has Mutual_Exclusion object. stream id in object is %d",
2867 GPOINTER_TO_INT (v_s_id));
2869 if (id > GPOINTER_TO_INT (v_s_id))
2870 is_right_view = TRUE;
2873 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2874 * first video stream encountered has the lower ID */
2875 if (demux->num_video_streams > 0) {
2876 /* This is not the first video stream, assuming right eye view */
2877 is_right_view = TRUE;
2881 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2883 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2890 GST_INFO_OBJECT (demux,
2891 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2894 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2895 if (mview_mode_str != NULL) {
2896 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2897 video->height, par_w, par_h))
2898 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2900 gst_caps_set_simple (caps,
2901 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2902 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2903 GST_FLAG_SET_MASK_EXACT, NULL);
2908 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2909 g_free (codec_name);
2913 gst_buffer_unref (extradata);
2915 GST_INFO ("Adding video stream #%u, id %u, codec %"
2916 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2917 GST_FOURCC_ARGS (video->tag), video->tag);
2919 ++demux->num_video_streams;
2921 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2922 streamheader, tags);
2926 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2928 if (!stream->active) {
2932 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2933 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2934 gst_pad_set_active (stream->pad, TRUE);
2937 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2938 "%03u", stream->id);
2941 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2943 if (gst_event_parse_group_id (event, &demux->group_id))
2944 demux->have_group_id = TRUE;
2946 demux->have_group_id = FALSE;
2947 gst_event_unref (event);
2948 } else if (!demux->have_group_id) {
2949 demux->have_group_id = TRUE;
2950 demux->group_id = gst_util_group_id_next ();
2953 event = gst_event_new_stream_start (stream_id);
2954 if (demux->have_group_id)
2955 gst_event_set_group_id (event, demux->group_id);
2957 gst_pad_push_event (stream->pad, event);
2959 gst_pad_set_caps (stream->pad, stream->caps);
2961 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2962 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2963 stream->active = TRUE;
2968 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2971 AsfCorrectionType correction_type;
2972 AsfStreamType stream_type;
2973 GstClockTime time_offset;
2974 gboolean is_encrypted G_GNUC_UNUSED;
2978 guint stream_specific_size;
2979 guint type_specific_size G_GNUC_UNUSED;
2980 guint unknown G_GNUC_UNUSED;
2981 gboolean inspect_payload = FALSE;
2982 AsfStream *stream = NULL;
2984 /* Get the rest of the header's header */
2985 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2986 goto not_enough_data;
2988 gst_asf_demux_get_guid (&guid, &data, &size);
2989 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2991 gst_asf_demux_get_guid (&guid, &data, &size);
2992 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2994 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2996 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2997 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2999 flags = gst_asf_demux_get_uint16 (&data, &size);
3000 stream_id = flags & 0x7f;
3001 is_encrypted = ! !((flags & 0x8000) << 15);
3002 unknown = gst_asf_demux_get_uint32 (&data, &size);
3004 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3005 stream_id, GST_TIME_ARGS (time_offset));
3007 /* dvr-ms has audio stream declared in stream specific data */
3008 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3009 AsfExtStreamType ext_stream_type;
3010 gst_asf_demux_get_guid (&guid, &data, &size);
3011 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3013 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3014 inspect_payload = TRUE;
3016 gst_asf_demux_get_guid (&guid, &data, &size);
3017 gst_asf_demux_get_uint32 (&data, &size);
3018 gst_asf_demux_get_uint32 (&data, &size);
3019 gst_asf_demux_get_uint32 (&data, &size);
3020 gst_asf_demux_get_guid (&guid, &data, &size);
3021 gst_asf_demux_get_uint32 (&data, &size);
3022 stream_type = ASF_STREAM_AUDIO;
3026 switch (stream_type) {
3027 case ASF_STREAM_AUDIO:{
3028 asf_stream_audio audio_object;
3030 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3031 goto not_enough_data;
3033 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3036 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3039 switch (correction_type) {
3040 case ASF_CORRECTION_ON:{
3041 guint span, packet_size, chunk_size, data_size, silence_data;
3043 GST_INFO ("Using error correction");
3045 if (size < (1 + 2 + 2 + 2 + 1))
3046 goto not_enough_data;
3048 span = gst_asf_demux_get_uint8 (&data, &size);
3049 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3050 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3051 data_size = gst_asf_demux_get_uint16 (&data, &size);
3052 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3054 stream->span = span;
3056 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3057 packet_size, chunk_size, data_size, span, silence_data);
3059 if (stream->span > 1) {
3060 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3061 /* Disable descrambling */
3064 /* FIXME: this else branch was added for
3065 * weird_al_yankovic - the saga begins.asf */
3066 stream->ds_packet_size = packet_size;
3067 stream->ds_chunk_size = chunk_size;
3070 /* Descambling is enabled */
3071 stream->ds_packet_size = packet_size;
3072 stream->ds_chunk_size = chunk_size;
3075 /* Now skip the rest of the silence data */
3077 gst_bytestream_flush (demux->bs, data_size - 1);
3079 /* FIXME: CHECKME. And why -1? */
3080 if (data_size > 1) {
3081 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3082 goto not_enough_data;
3088 case ASF_CORRECTION_OFF:{
3089 GST_INFO ("Error correction off");
3090 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3091 goto not_enough_data;
3095 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3096 ("Audio stream using unknown error correction"));
3103 case ASF_STREAM_VIDEO:{
3104 asf_stream_video_format video_format_object;
3105 asf_stream_video video_object;
3108 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3109 goto not_enough_data;
3111 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3113 GST_INFO ("object is a video stream with %u bytes of "
3114 "additional data", vsize);
3116 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3118 goto not_enough_data;
3121 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3122 stream_id, &data, &size);
3128 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3130 demux->other_streams =
3131 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3136 stream->inspect_payload = inspect_payload;
3141 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3142 /* we'll error out later if we found no streams */
3147 static const gchar *
3148 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3152 const gchar *asf_name;
3153 const gchar *gst_name;
3156 "WM/Genre", GST_TAG_GENRE}, {
3157 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3158 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3159 "WM/Picture", GST_TAG_IMAGE}, {
3160 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3161 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3162 "WM/Year", GST_TAG_DATE_TIME}
3163 /* { "WM/Composer", GST_TAG_COMPOSER } */
3168 if (name_utf8 == NULL) {
3169 GST_WARNING ("Failed to convert name to UTF8, skipping");
3173 out = strlen (name_utf8);
3175 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3176 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3177 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3178 return tags[i].gst_name;
3185 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3187 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3191 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3193 if (taglist == NULL)
3196 if (gst_tag_list_is_empty (taglist)) {
3197 gst_tag_list_unref (taglist);
3201 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3202 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3204 gst_tag_list_unref (demux->taglist);
3205 gst_tag_list_unref (taglist);
3207 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3210 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3211 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3212 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3213 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3216 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3220 const guint8 *img_data = NULL;
3221 guint32 img_data_len = 0;
3222 guint8 pic_type = 0;
3224 gst_byte_reader_init (&r, tag_data, tag_data_len);
3226 /* skip mime type string (we don't trust it and do our own typefinding),
3227 * and also skip the description string, since we don't use it */
3228 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3229 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3230 !gst_byte_reader_skip_string_utf16 (&r) ||
3231 !gst_byte_reader_skip_string_utf16 (&r) ||
3232 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3233 goto not_enough_data;
3237 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3238 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3244 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3245 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3250 /* Extended Content Description Object */
3251 static GstFlowReturn
3252 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3255 /* Other known (and unused) 'text/unicode' metadata available :
3258 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3259 * WMFSDKVersion = 9.00.00.2980
3260 * WMFSDKNeeded = 0.0.0.0000
3261 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3262 * WM/Publisher = 4AD
3264 * WM/ProviderRating = 8
3265 * WM/ProviderStyle = Rock (similar to WM/Genre)
3266 * WM/GenreID (similar to WM/Genre)
3267 * WM/TrackNumber (same as WM/Track but as a string)
3269 * Other known (and unused) 'non-text' metadata available :
3275 * We might want to read WM/TrackNumber and use atoi() if we don't have
3279 GstTagList *taglist;
3280 guint16 blockcount, i;
3281 gboolean content3D = FALSE;
3285 const gchar *interleave_name;
3286 GstASF3DMode interleaving_type;
3287 } stereoscopic_layout_map[] = {
3289 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3290 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3291 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3292 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3293 "DualStream", GST_ASF_3D_DUAL_STREAM}
3295 GST_INFO_OBJECT (demux, "object is an extended content description");
3297 taglist = gst_tag_list_new_empty ();
3299 /* Content Descriptor Count */
3301 goto not_enough_data;
3303 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3305 for (i = 1; i <= blockcount; ++i) {
3306 const gchar *gst_tag_name;
3310 GValue tag_value = { 0, };
3313 gchar *name_utf8 = NULL;
3317 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3318 goto not_enough_data;
3322 goto not_enough_data;
3324 /* Descriptor Value Data Type */
3325 datatype = gst_asf_demux_get_uint16 (&data, &size);
3327 /* Descriptor Value (not really a string, but same thing reading-wise) */
3328 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3330 goto not_enough_data;
3334 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3336 if (name_utf8 != NULL) {
3337 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3339 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3340 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3343 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3346 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3349 /* get rid of tags with empty value */
3350 if (value_utf8 != NULL && *value_utf8 != '\0') {
3351 GST_DEBUG ("string value %s", value_utf8);
3353 value_utf8[out] = '\0';
3355 if (gst_tag_name != NULL) {
3356 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3357 guint year = atoi (value_utf8);
3360 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3361 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3363 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3364 guint id3v1_genre_id;
3365 const gchar *genre_str;
3367 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3368 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3369 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3370 g_free (value_utf8);
3371 value_utf8 = g_strdup (genre_str);
3376 /* convert tag from string to other type if required */
3377 tag_type = gst_tag_get_type (gst_tag_name);
3378 g_value_init (&tag_value, tag_type);
3379 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3380 GValue from_val = { 0, };
3382 g_value_init (&from_val, G_TYPE_STRING);
3383 g_value_set_string (&from_val, value_utf8);
3384 if (!g_value_transform (&from_val, &tag_value)) {
3385 GST_WARNING_OBJECT (demux,
3386 "Could not transform string tag to " "%s tag type %s",
3387 gst_tag_name, g_type_name (tag_type));
3388 g_value_unset (&tag_value);
3390 g_value_unset (&from_val);
3395 GST_DEBUG ("Setting metadata");
3396 g_value_init (&tag_value, G_TYPE_STRING);
3397 g_value_set_string (&tag_value, value_utf8);
3398 /* If we found a stereoscopic marker, look for StereoscopicLayout
3402 if (strncmp ("StereoscopicLayout", name_utf8,
3403 strlen (name_utf8)) == 0) {
3404 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3405 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3407 demux->asf_3D_mode =
3408 stereoscopic_layout_map[i].interleaving_type;
3409 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3413 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3415 demux->asf_3D_mode = GST_ASF_3D_NONE;
3416 GST_INFO_OBJECT (demux, "None 3d type");
3419 } else if (value_utf8 == NULL) {
3420 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3422 GST_DEBUG ("Skipping empty string value for %s",
3423 GST_STR_NULL (gst_tag_name));
3425 g_free (value_utf8);
3428 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3430 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3431 GST_FIXME ("Unhandled byte array tag %s",
3432 GST_STR_NULL (gst_tag_name));
3435 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3441 case ASF_DEMUX_DATA_TYPE_DWORD:{
3442 guint uint_val = GST_READ_UINT32_LE (value);
3444 /* this is the track number */
3445 g_value_init (&tag_value, G_TYPE_UINT);
3447 /* WM/Track counts from 0 */
3448 if (!strcmp (name_utf8, "WM/Track"))
3451 g_value_set_uint (&tag_value, uint_val);
3455 case ASF_DEMUX_DATA_TYPE_BOOL:{
3456 gboolean bool_val = GST_READ_UINT32_LE (value);
3458 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3460 GST_INFO_OBJECT (demux, "This is 3D contents");
3463 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3471 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3476 if (G_IS_VALUE (&tag_value)) {
3478 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3480 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3481 * is supposed to have a 0 base but is often wrongly written to start
3482 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3483 * replace the value added earlier from WM/Track or put it first in
3484 * the list, so that it will get picked up by _get_uint() */
3485 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3486 merge_mode = GST_TAG_MERGE_REPLACE;
3488 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3491 GST_DEBUG ("Setting global metadata %s", name_utf8);
3492 gst_structure_set_value (demux->global_metadata, name_utf8,
3496 g_value_unset (&tag_value);
3505 gst_asf_demux_add_global_tags (demux, taglist);
3512 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3513 gst_tag_list_unref (taglist);
3514 return GST_FLOW_OK; /* not really fatal */
3518 static GstStructure *
3519 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3524 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3526 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3529 s = gst_caps_get_structure (demux->metadata, i);
3530 if (gst_structure_has_name (s, sname))
3534 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3536 /* try lookup again; demux->metadata took ownership of the structure, so we
3537 * can't really make any assumptions about what happened to it, so we can't
3538 * just return it directly after appending it */
3539 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3542 static GstFlowReturn
3543 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3546 guint16 blockcount, i;
3548 GST_INFO_OBJECT (demux, "object is a metadata object");
3550 /* Content Descriptor Count */
3552 goto not_enough_data;
3554 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3556 for (i = 0; i < blockcount; ++i) {
3558 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3559 guint32 data_len, ival;
3562 if (size < (2 + 2 + 2 + 2 + 4))
3563 goto not_enough_data;
3565 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3566 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3567 name_len = gst_asf_demux_get_uint16 (&data, &size);
3568 data_type = gst_asf_demux_get_uint16 (&data, &size);
3569 data_len = gst_asf_demux_get_uint32 (&data, &size);
3571 if (size < name_len + data_len)
3572 goto not_enough_data;
3574 /* convert name to UTF-8 */
3575 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3577 gst_asf_demux_skip_bytes (name_len, &data, &size);
3579 if (name_utf8 == NULL) {
3580 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3581 gst_asf_demux_skip_bytes (data_len, &data, &size);
3585 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3586 gst_asf_demux_skip_bytes (data_len, &data, &size);
3594 goto not_enough_data;
3597 ival = gst_asf_demux_get_uint32 (&data, &size);
3599 /* skip anything else there may be, just in case */
3600 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3602 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3603 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3607 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3613 GST_WARNING ("Unexpected end of data parsing metadata object");
3614 return GST_FLOW_OK; /* not really fatal */
3618 static GstFlowReturn
3619 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3621 GstFlowReturn ret = GST_FLOW_OK;
3622 guint32 i, num_objects;
3623 guint8 unknown G_GNUC_UNUSED;
3625 /* Get the rest of the header's header */
3626 if (size < (4 + 1 + 1))
3627 goto not_enough_data;
3629 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3630 unknown = gst_asf_demux_get_uint8 (&data, &size);
3631 unknown = gst_asf_demux_get_uint8 (&data, &size);
3633 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3634 demux->saw_file_header = FALSE;
3635 /* Loop through the header's objects, processing those */
3636 for (i = 0; i < num_objects; ++i) {
3637 GST_INFO_OBJECT (demux, "reading header part %u", i);
3638 ret = gst_asf_demux_process_object (demux, &data, &size);
3639 if (ret != GST_FLOW_OK) {
3640 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3644 if (!demux->saw_file_header) {
3645 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3646 ("Header does not have mandatory FILE section"));
3647 return GST_FLOW_ERROR;
3654 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3655 ("short read parsing HEADER object"));
3656 return GST_FLOW_ERROR;
3660 static GstFlowReturn
3661 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3663 guint64 creation_time G_GNUC_UNUSED;
3664 guint64 file_size G_GNUC_UNUSED;
3665 guint64 send_time G_GNUC_UNUSED;
3666 guint64 packets_count, play_time, preroll;
3667 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3669 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3670 goto not_enough_data;
3672 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3673 file_size = gst_asf_demux_get_uint64 (&data, &size);
3674 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3675 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3676 play_time = gst_asf_demux_get_uint64 (&data, &size);
3677 send_time = gst_asf_demux_get_uint64 (&data, &size);
3678 preroll = gst_asf_demux_get_uint64 (&data, &size);
3679 flags = gst_asf_demux_get_uint32 (&data, &size);
3680 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3681 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3682 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3684 demux->broadcast = ! !(flags & 0x01);
3685 demux->seekable = ! !(flags & 0x02);
3687 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3688 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3689 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3691 if (demux->broadcast) {
3692 /* these fields are invalid if the broadcast flag is set */
3697 if (min_pktsize != max_pktsize)
3698 goto non_fixed_packet_size;
3700 demux->packet_size = max_pktsize;
3702 /* FIXME: do we need send_time as well? what is it? */
3703 if ((play_time * 100) >= (preroll * GST_MSECOND))
3704 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3706 demux->play_time = 0;
3708 demux->preroll = preroll * GST_MSECOND;
3710 /* initial latency */
3711 demux->latency = demux->preroll;
3713 if (demux->play_time == 0)
3714 demux->seekable = FALSE;
3716 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3717 GST_TIME_ARGS (demux->play_time));
3718 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3719 GST_TIME_ARGS (demux->preroll));
3721 if (demux->play_time > 0) {
3722 demux->segment.duration = demux->play_time;
3725 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3727 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3729 demux->saw_file_header = TRUE;
3734 non_fixed_packet_size:
3736 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3737 ("packet size must be fixed"));
3738 return GST_FLOW_ERROR;
3742 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3743 ("short read parsing FILE object"));
3744 return GST_FLOW_ERROR;
3748 /* Content Description Object */
3749 static GstFlowReturn
3750 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3754 const gchar *gst_tag;
3759 GST_TAG_TITLE, 0, NULL}, {
3760 GST_TAG_ARTIST, 0, NULL}, {
3761 GST_TAG_COPYRIGHT, 0, NULL}, {
3762 GST_TAG_DESCRIPTION, 0, NULL}, {
3763 GST_TAG_COMMENT, 0, NULL}
3765 GstTagList *taglist;
3766 GValue value = { 0 };
3770 GST_INFO_OBJECT (demux, "object is a comment");
3772 if (size < (2 + 2 + 2 + 2 + 2))
3773 goto not_enough_data;
3775 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3776 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3777 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3778 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3779 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3781 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3782 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3783 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3785 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3786 if (size < tags[i].val_length)
3787 goto not_enough_data;
3789 /* might be just '/0', '/0'... */
3790 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3791 /* convert to UTF-8 */
3792 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3793 "UTF-8", "UTF-16LE", &in, &out, NULL);
3795 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3798 /* parse metadata into taglist */
3799 taglist = gst_tag_list_new_empty ();
3800 g_value_init (&value, G_TYPE_STRING);
3801 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3802 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3803 g_value_set_string (&value, tags[i].val_utf8);
3804 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3805 tags[i].gst_tag, &value, NULL);
3808 g_value_unset (&value);
3810 gst_asf_demux_add_global_tags (demux, taglist);
3812 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3813 g_free (tags[i].val_utf8);
3819 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3820 "comment tag section %d, skipping comment object", i);
3821 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3822 g_free (tags[i].val_utf8);
3823 return GST_FLOW_OK; /* not really fatal */
3827 static GstFlowReturn
3828 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3831 guint16 num_streams, i;
3835 goto not_enough_data;
3837 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3839 GST_INFO ("object is a bitrate properties object with %u streams",
3842 if (size < (num_streams * (2 + 4)))
3843 goto not_enough_data;
3845 for (i = 0; i < num_streams; ++i) {
3849 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3850 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3852 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3853 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3854 stream = gst_asf_demux_get_stream (demux, stream_id);
3856 if (stream->pending_tags == NULL)
3857 stream->pending_tags = gst_tag_list_new_empty ();
3858 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3859 GST_TAG_BITRATE, bitrate, NULL);
3861 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3864 GST_WARNING ("stream id %u is too large", stream_id);
3872 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3873 return GST_FLOW_OK; /* not really fatal */
3877 static GstFlowReturn
3878 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3881 GstFlowReturn ret = GST_FLOW_OK;
3884 /* Get the rest of the header's header */
3885 if (size < (16 + 2 + 4))
3886 goto not_enough_data;
3888 /* skip GUID and two other bytes */
3889 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3890 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3892 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3894 /* FIXME: does data_size include the rest of the header that we have read? */
3895 if (hdr_size > size)
3896 goto not_enough_data;
3898 while (hdr_size > 0) {
3899 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3900 if (ret != GST_FLOW_OK)
3908 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3909 ("short read parsing extended header object"));
3910 return GST_FLOW_ERROR;
3914 static GstFlowReturn
3915 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3921 goto not_enough_data;
3923 if (demux->languages) {
3924 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3925 g_strfreev (demux->languages);
3926 demux->languages = NULL;
3927 demux->num_languages = 0;
3930 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3931 GST_LOG ("%u languages:", demux->num_languages);
3933 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3934 for (i = 0; i < demux->num_languages; ++i) {
3935 guint8 len, *lang_data = NULL;
3938 goto not_enough_data;
3939 len = gst_asf_demux_get_uint8 (&data, &size);
3940 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3943 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3946 /* truncate "en-us" etc. to just "en" */
3947 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3950 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3951 demux->languages[i] = utf8;
3954 goto not_enough_data;
3962 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3963 g_free (demux->languages);
3964 demux->languages = NULL;
3965 demux->num_languages = 0;
3966 return GST_FLOW_OK; /* not fatal */
3970 static GstFlowReturn
3971 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3974 GstClockTime interval;
3977 if (size < (16 + 8 + 4 + 4))
3978 goto not_enough_data;
3981 gst_asf_demux_skip_bytes (16, &data, &size);
3982 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3983 gst_asf_demux_skip_bytes (4, &data, &size);
3984 count = gst_asf_demux_get_uint32 (&data, &size);
3986 demux->sidx_interval = interval;
3987 demux->sidx_num_entries = count;
3988 g_free (demux->sidx_entries);
3989 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3991 for (i = 0; i < count; ++i) {
3992 if (G_UNLIKELY (size < 6)) {
3993 /* adjust for broken files, to avoid having entries at the end
3994 * of the parsed index that point to time=0. Resulting in seeking to
3995 * the end of the file leading back to the beginning */
3996 demux->sidx_num_entries -= (count - i);
3999 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4000 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4001 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4002 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4003 demux->sidx_entries[i].count);
4006 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4013 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4014 return GST_FLOW_OK; /* not fatal */
4018 static GstFlowReturn
4019 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4020 guint8 * data, guint64 size)
4025 if (size < 16 + 2 + (2 * 2))
4026 goto not_enough_data;
4028 gst_asf_demux_get_guid (&guid, &data, &size);
4029 num = gst_asf_demux_get_uint16 (&data, &size);
4032 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4036 if (size < (num * sizeof (guint16)))
4037 goto not_enough_data;
4039 /* read mutually exclusive stream numbers */
4040 for (i = 0; i < num; ++i) {
4042 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4043 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4045 demux->mut_ex_streams =
4046 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4055 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4056 return GST_FLOW_OK; /* not absolutely fatal */
4061 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4063 return g_slist_find (demux->other_streams,
4064 GINT_TO_POINTER (stream_num)) == NULL;
4067 static GstFlowReturn
4068 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4071 AsfStreamExtProps esp;
4072 AsfStream *stream = NULL;
4073 AsfObject stream_obj;
4074 guint16 stream_name_count;
4075 guint16 num_payload_ext;
4077 guint8 *stream_obj_data = NULL;
4080 guint i, stream_num;
4083 obj_size = (guint) size;
4085 esp.payload_extensions = NULL;
4088 goto not_enough_data;
4091 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4092 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4093 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4094 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4095 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4096 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4097 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4098 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4099 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4100 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4101 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4102 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4103 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4104 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4105 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4107 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4108 GST_TIME_ARGS (esp.start_time));
4109 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4110 GST_TIME_ARGS (esp.end_time));
4111 GST_INFO ("flags = %08x", esp.flags);
4112 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4113 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4114 GST_INFO ("stream number = %u", stream_num);
4115 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4116 (esp.lang_idx < demux->num_languages) ?
4117 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4118 GST_INFO ("stream name count = %u", stream_name_count);
4120 /* read stream names */
4121 for (i = 0; i < stream_name_count; ++i) {
4122 guint16 stream_lang_idx G_GNUC_UNUSED;
4123 gchar *stream_name = NULL;
4126 goto not_enough_data;
4127 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4128 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4129 goto not_enough_data;
4130 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4131 g_free (stream_name); /* TODO: store names in struct */
4134 /* read payload extension systems stuff */
4135 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4137 if (num_payload_ext > 0)
4138 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4140 for (i = 0; i < num_payload_ext; ++i) {
4141 AsfPayloadExtension ext;
4143 guint32 sys_info_len;
4145 if (size < 16 + 2 + 4)
4146 goto not_enough_data;
4148 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4149 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4150 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4152 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4153 GST_LOG ("payload systems info len = %u", sys_info_len);
4154 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4155 goto not_enough_data;
4157 esp.payload_extensions[i] = ext;
4160 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4162 /* there might be an optional STREAM_INFO object here now; if not, we
4163 * should have parsed the corresponding stream info object already (since
4164 * we are parsing the extended stream properties objects delayed) */
4166 stream = gst_asf_demux_get_stream (demux, stream_num);
4170 if (size < ASF_OBJECT_HEADER_SIZE)
4171 goto not_enough_data;
4173 /* get size of the stream object */
4174 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4175 goto corrupted_stream;
4177 if (stream_obj.id != ASF_OBJ_STREAM)
4178 goto expected_stream_object;
4180 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4181 stream_obj.size > (10 * 1024 * 1024))
4182 goto not_enough_data;
4184 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4186 /* process this stream object later after all the other 'normal' ones
4187 * have been processed (since the others are more important/non-hidden) */
4188 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4189 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4190 goto not_enough_data;
4192 /* parse stream object */
4193 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4194 g_free (stream_obj_data);
4199 stream->ext_props = esp;
4201 /* try to set the framerate */
4202 if (stream->is_video && stream->caps) {
4203 GValue framerate = { 0 };
4207 g_value_init (&framerate, GST_TYPE_FRACTION);
4209 num = GST_SECOND / 100;
4210 denom = esp.avg_time_per_frame;
4212 /* avoid division by 0, assume 25/1 framerate */
4213 denom = GST_SECOND / 2500;
4216 gst_value_set_fraction (&framerate, num, denom);
4218 stream->caps = gst_caps_make_writable (stream->caps);
4219 s = gst_caps_get_structure (stream->caps, 0);
4220 gst_structure_set_value (s, "framerate", &framerate);
4221 g_value_unset (&framerate);
4222 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4223 num, denom, ((gdouble) num) / denom);
4226 /* add language info now if we have it */
4227 if (stream->ext_props.lang_idx < demux->num_languages) {
4228 if (stream->pending_tags == NULL)
4229 stream->pending_tags = gst_tag_list_new_empty ();
4230 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4231 demux->languages[stream->ext_props.lang_idx]);
4232 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4233 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4236 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4237 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4241 g_free (esp.payload_extensions);
4248 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4249 g_free (esp.payload_extensions);
4250 return GST_FLOW_OK; /* not absolutely fatal */
4252 expected_stream_object:
4254 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4255 "object: expected embedded stream object, but got %s object instead!",
4256 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4257 g_free (esp.payload_extensions);
4258 return GST_FLOW_OK; /* not absolutely fatal */
4262 GST_WARNING_OBJECT (demux, "Corrupted stream");
4263 g_free (esp.payload_extensions);
4264 return GST_FLOW_ERROR;
4268 static const gchar *
4269 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4273 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4274 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4275 nick += strlen ("ASF_OBJ_");
4277 if (demux->objpath == NULL) {
4278 demux->objpath = g_strdup (nick);
4282 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4283 g_free (demux->objpath);
4284 demux->objpath = newpath;
4287 return (const gchar *) demux->objpath;
4291 gst_asf_demux_pop_obj (GstASFDemux * demux)
4295 if ((s = g_strrstr (demux->objpath, "/"))) {
4298 g_free (demux->objpath);
4299 demux->objpath = NULL;
4304 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4309 /* Parse the queued extended stream property objects and add the info
4310 * to the existing streams or add the new embedded streams, but without
4311 * activating them yet */
4312 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4313 g_slist_length (demux->ext_stream_props));
4315 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4316 GstBuffer *buf = GST_BUFFER (l->data);
4319 gst_buffer_map (buf, &map, GST_MAP_READ);
4321 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4322 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4323 gst_buffer_unmap (buf, &map);
4324 gst_buffer_unref (buf);
4326 g_slist_free (demux->ext_stream_props);
4327 demux->ext_stream_props = NULL;
4332 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4336 for (i = 0; i < demux->num_streams; ++i) {
4341 stream = &demux->stream[i];
4343 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4345 if (stream->active) {
4346 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4351 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4354 /* check for each mutual exclusion whether it affects this stream */
4355 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4356 if (*mes == stream->id) {
4357 /* if yes, check if we've already added streams that are mutually
4358 * exclusive with the stream we're about to add */
4359 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4360 for (j = 0; j < demux->num_streams; ++j) {
4361 /* if the broadcast flag is set, assume the hidden streams aren't
4362 * actually streamed and hide them (or playbin won't work right),
4363 * otherwise assume their data is available */
4364 if (demux->stream[j].id == *mes && demux->broadcast) {
4366 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4367 "mutually exclusive with already existing stream ID %d, "
4368 "hiding stream", stream->id, demux->stream[j].id);
4380 /* FIXME: we should do stream activation based on preroll data in
4381 * streaming mode too */
4382 if (demux->streaming && !is_hidden)
4383 gst_asf_demux_activate_stream (demux, stream);
4388 static GstFlowReturn
4389 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4392 GstFlowReturn ret = GST_FLOW_OK;
4394 guint64 obj_data_size;
4396 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4397 return ASF_FLOW_NEED_MORE_DATA;
4399 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4401 return GST_FLOW_ERROR;
4402 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4404 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4406 if (*p_size < obj_data_size)
4407 return ASF_FLOW_NEED_MORE_DATA;
4409 gst_asf_demux_push_obj (demux, obj.id);
4411 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4414 case ASF_OBJ_STREAM:
4415 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4419 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4421 case ASF_OBJ_HEADER:
4422 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4424 case ASF_OBJ_COMMENT:
4425 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4428 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4430 case ASF_OBJ_BITRATE_PROPS:
4432 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4435 case ASF_OBJ_EXT_CONTENT_DESC:
4437 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4440 case ASF_OBJ_METADATA_OBJECT:
4441 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4443 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4446 /* process these later, we might not have parsed the corresponding
4447 * stream object yet */
4448 GST_LOG ("%s: queued for later parsing", demux->objpath);
4449 buf = gst_buffer_new_and_alloc (obj_data_size);
4450 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4451 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4455 case ASF_OBJ_LANGUAGE_LIST:
4456 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4458 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4459 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4462 case ASF_OBJ_SIMPLE_INDEX:
4463 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4465 case ASF_OBJ_CONTENT_ENCRYPTION:
4466 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4467 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4468 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4469 goto error_encrypted;
4470 case ASF_OBJ_CONCEAL_NONE:
4472 case ASF_OBJ_UNDEFINED:
4473 case ASF_OBJ_CODEC_COMMENT:
4475 case ASF_OBJ_PADDING:
4476 case ASF_OBJ_BITRATE_MUTEX:
4477 case ASF_OBJ_COMPATIBILITY:
4478 case ASF_OBJ_INDEX_PLACEHOLDER:
4479 case ASF_OBJ_INDEX_PARAMETERS:
4480 case ASF_OBJ_STREAM_PRIORITIZATION:
4481 case ASF_OBJ_SCRIPT_COMMAND:
4482 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4484 /* Unknown/unhandled object, skip it and hope for the best */
4485 GST_INFO ("%s: skipping object", demux->objpath);
4490 /* this can't fail, we checked the number of bytes available before */
4491 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4493 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4495 gst_asf_demux_pop_obj (demux);
4502 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4503 return GST_FLOW_ERROR;
4508 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4509 GstBuffer ** p_buffer)
4511 GstBuffer *descrambled_buffer;
4512 GstBuffer *scrambled_buffer;
4513 GstBuffer *sub_buffer;
4520 /* descrambled_buffer is initialised in the first iteration */
4521 descrambled_buffer = NULL;
4522 scrambled_buffer = *p_buffer;
4524 if (gst_buffer_get_size (scrambled_buffer) <
4525 stream->ds_packet_size * stream->span)
4528 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4529 offset += stream->ds_chunk_size) {
4530 off = offset / stream->ds_chunk_size;
4531 row = off / stream->span;
4532 col = off % stream->span;
4533 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4534 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4535 col, off, stream->ds_chunk_size);
4536 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4537 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4538 stream->span, stream->ds_packet_size);
4539 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4540 gst_buffer_get_size (scrambled_buffer));
4542 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4543 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4545 descrambled_buffer = sub_buffer;
4547 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4551 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4552 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4553 GST_BUFFER_DURATION (descrambled_buffer) =
4554 GST_BUFFER_DURATION (scrambled_buffer);
4555 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4556 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4557 GST_BUFFER_OFFSET_END (scrambled_buffer);
4559 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4561 gst_buffer_unref (scrambled_buffer);
4562 *p_buffer = descrambled_buffer;
4566 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4568 GstASFDemux *demux = GST_ASF_DEMUX (element);
4571 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4573 for (i = 0; i < demux->num_streams; ++i) {
4574 gst_event_ref (event);
4575 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4576 GST_OBJECT_CAST (element), event)) {
4577 gst_event_unref (event);
4582 gst_event_unref (event);
4586 /* takes ownership of the passed event */
4588 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4590 gboolean ret = TRUE;
4593 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4594 GST_EVENT_TYPE_NAME (event));
4596 for (i = 0; i < demux->num_streams; ++i) {
4597 gst_event_ref (event);
4598 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4600 gst_event_unref (event);
4605 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4609 gboolean res = FALSE;
4611 demux = GST_ASF_DEMUX (parent);
4613 GST_DEBUG ("handling %s query",
4614 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4616 switch (GST_QUERY_TYPE (query)) {
4617 case GST_QUERY_DURATION:
4621 gst_query_parse_duration (query, &format, NULL);
4623 if (format != GST_FORMAT_TIME) {
4624 GST_LOG ("only support duration queries in TIME format");
4628 res = gst_pad_query_default (pad, parent, query);
4630 GST_OBJECT_LOCK (demux);
4632 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4633 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4634 GST_TIME_ARGS (demux->segment.duration));
4636 gst_query_set_duration (query, GST_FORMAT_TIME,
4637 demux->segment.duration);
4641 GST_LOG ("duration not known yet");
4644 GST_OBJECT_UNLOCK (demux);
4649 case GST_QUERY_POSITION:{
4652 gst_query_parse_position (query, &format, NULL);
4654 if (format != GST_FORMAT_TIME) {
4655 GST_LOG ("only support position queries in TIME format");
4659 GST_OBJECT_LOCK (demux);
4661 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4662 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4663 GST_TIME_ARGS (demux->segment.position));
4665 gst_query_set_position (query, GST_FORMAT_TIME,
4666 demux->segment.position);
4670 GST_LOG ("position not known yet");
4673 GST_OBJECT_UNLOCK (demux);
4677 case GST_QUERY_SEEKING:{
4680 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4681 if (format == GST_FORMAT_TIME) {
4684 GST_OBJECT_LOCK (demux);
4685 duration = demux->segment.duration;
4686 GST_OBJECT_UNLOCK (demux);
4688 if (!demux->streaming || !demux->seekable) {
4689 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4696 /* try upstream first in TIME */
4697 res = gst_pad_query_default (pad, parent, query);
4699 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4700 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4701 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4702 /* if no luck, maybe in BYTES */
4703 if (!seekable || fmt != GST_FORMAT_TIME) {
4706 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4707 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4708 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4709 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4710 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4711 if (fmt != GST_FORMAT_BYTES)
4714 gst_query_unref (q);
4715 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4721 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4725 case GST_QUERY_LATENCY:
4728 GstClockTime min, max;
4730 /* preroll delay does not matter in non-live pipeline,
4731 * but we might end up in a live (rtsp) one ... */
4734 res = gst_pad_query_default (pad, parent, query);
4738 gst_query_parse_latency (query, &live, &min, &max);
4740 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4741 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4742 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4744 GST_OBJECT_LOCK (demux);
4745 min += demux->latency;
4747 max += demux->latency;
4748 GST_OBJECT_UNLOCK (demux);
4750 gst_query_set_latency (query, live, min, max);
4753 case GST_QUERY_SEGMENT:
4758 format = demux->segment.format;
4761 gst_segment_to_stream_time (&demux->segment, format,
4762 demux->segment.start);
4763 if ((stop = demux->segment.stop) == -1)
4764 stop = demux->segment.duration;
4766 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4768 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4773 res = gst_pad_query_default (pad, parent, query);
4780 static GstStateChangeReturn
4781 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4783 GstASFDemux *demux = GST_ASF_DEMUX (element);
4784 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4786 switch (transition) {
4787 case GST_STATE_CHANGE_NULL_TO_READY:{
4788 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4789 demux->need_newsegment = TRUE;
4790 demux->segment_running = FALSE;
4791 demux->keyunit_sync = FALSE;
4792 demux->accurate = FALSE;
4793 demux->adapter = gst_adapter_new ();
4794 demux->metadata = gst_caps_new_empty ();
4795 demux->global_metadata = gst_structure_new_empty ("metadata");
4796 demux->data_size = 0;
4797 demux->data_offset = 0;
4798 demux->index_offset = 0;
4799 demux->base_offset = 0;
4800 demux->flowcombiner = gst_flow_combiner_new ();
4808 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4809 if (ret == GST_STATE_CHANGE_FAILURE)
4812 switch (transition) {
4813 case GST_STATE_CHANGE_PAUSED_TO_READY:
4814 gst_asf_demux_reset (demux, FALSE);
4817 case GST_STATE_CHANGE_READY_TO_NULL:
4818 gst_asf_demux_reset (demux, FALSE);
4819 gst_flow_combiner_free (demux->flowcombiner);
4820 demux->flowcombiner = NULL;