1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <gst/video/video.h>
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS ("video/x-ms-asf")
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE (16+8)
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA 99
76 #define gst_asf_get_flow_name(flow) \
77 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
78 "need-more-data" : gst_flow_get_name (flow)
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83 GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89 GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98 GstObject * parent, GstPadMode mode, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
103 GstFlowReturn * pflow);
104 static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109 AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
123 GstElementClass *gstelement_class;
125 gstelement_class = (GstElementClass *) klass;
127 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
129 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 gst_element_class_add_static_pad_template (gstelement_class,
132 &audio_src_template);
133 gst_element_class_add_static_pad_template (gstelement_class,
134 &video_src_template);
135 gst_element_class_add_static_pad_template (gstelement_class,
136 &gst_asf_demux_sink_template);
138 gstelement_class->change_state =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140 gstelement_class->send_event =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 gst_caps_replace (&stream->caps, NULL);
148 if (stream->pending_tags) {
149 gst_tag_list_unref (stream->pending_tags);
150 stream->pending_tags = NULL;
152 if (stream->streamheader) {
153 gst_buffer_unref (stream->streamheader);
154 stream->streamheader = NULL;
157 if (stream->active) {
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
161 gst_object_unref (stream->pad);
165 if (stream->payloads) {
166 while (stream->payloads->len > 0) {
170 last = stream->payloads->len - 1;
171 payload = &g_array_index (stream->payloads, AsfPayload, last);
172 gst_buffer_replace (&payload->buf, NULL);
173 g_array_remove_index (stream->payloads, last);
175 g_array_free (stream->payloads, TRUE);
176 stream->payloads = NULL;
179 if (stream->payloads_rev) {
180 while (stream->payloads_rev->len > 0) {
184 last = stream->payloads_rev->len - 1;
185 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186 gst_buffer_replace (&payload->buf, NULL);
187 g_array_remove_index (stream->payloads_rev, last);
189 g_array_free (stream->payloads_rev, TRUE);
190 stream->payloads_rev = NULL;
193 if (stream->ext_props.valid) {
194 g_free (stream->ext_props.payload_extensions);
195 stream->ext_props.payload_extensions = NULL;
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
202 GST_LOG_OBJECT (demux, "resetting");
204 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205 demux->segment_running = FALSE;
206 if (demux->adapter && !chain_reset) {
207 gst_adapter_clear (demux->adapter);
208 g_object_unref (demux->adapter);
209 demux->adapter = NULL;
211 if (demux->taglist) {
212 gst_tag_list_unref (demux->taglist);
213 demux->taglist = NULL;
215 if (demux->metadata) {
216 gst_caps_unref (demux->metadata);
217 demux->metadata = NULL;
219 if (demux->global_metadata) {
220 gst_structure_free (demux->global_metadata);
221 demux->global_metadata = NULL;
223 if (demux->mut_ex_streams) {
224 g_slist_free (demux->mut_ex_streams);
225 demux->mut_ex_streams = NULL;
228 demux->state = GST_ASF_DEMUX_STATE_HEADER;
229 g_free (demux->objpath);
230 demux->objpath = NULL;
231 g_strfreev (demux->languages);
232 demux->languages = NULL;
233 demux->num_languages = 0;
234 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
236 g_slist_free (demux->ext_stream_props);
237 demux->ext_stream_props = NULL;
239 while (demux->old_num_streams > 0) {
240 gst_asf_demux_free_stream (demux,
241 &demux->old_stream[demux->old_num_streams - 1]);
242 --demux->old_num_streams;
244 memset (demux->old_stream, 0, sizeof (demux->old_stream));
245 demux->old_num_streams = 0;
247 /* when resetting for a new chained asf, we don't want to remove the pads
248 * before adding the new ones */
250 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251 demux->old_num_streams = demux->num_streams;
252 demux->num_streams = 0;
255 while (demux->num_streams > 0) {
256 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257 --demux->num_streams;
259 memset (demux->stream, 0, sizeof (demux->stream));
261 /* do not remove those for not adding pads with same name */
262 demux->num_audio_streams = 0;
263 demux->num_video_streams = 0;
264 demux->have_group_id = FALSE;
265 demux->group_id = G_MAXUINT;
267 demux->num_streams = 0;
268 demux->activated_streams = FALSE;
269 demux->first_ts = GST_CLOCK_TIME_NONE;
270 demux->segment_ts = GST_CLOCK_TIME_NONE;
273 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274 demux->state = GST_ASF_DEMUX_STATE_HEADER;
275 demux->seekable = FALSE;
276 demux->broadcast = FALSE;
277 demux->sidx_interval = 0;
278 demux->sidx_num_entries = 0;
279 g_free (demux->sidx_entries);
280 demux->sidx_entries = NULL;
282 demux->speed_packets = 1;
284 demux->asf_3D_mode = GST_ASF_3D_NONE;
287 GST_LOG_OBJECT (demux, "Restarting");
288 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289 demux->need_newsegment = TRUE;
290 demux->segment_seqnum = 0;
291 demux->segment_running = FALSE;
292 demux->keyunit_sync = FALSE;
293 demux->accurate = FALSE;
294 demux->metadata = gst_caps_new_empty ();
295 demux->global_metadata = gst_structure_new_empty ("metadata");
296 demux->data_size = 0;
297 demux->data_offset = 0;
298 demux->index_offset = 0;
300 demux->base_offset = 0;
303 g_slist_free (demux->other_streams);
304 demux->other_streams = NULL;
308 gst_asf_demux_init (GstASFDemux * demux)
311 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312 gst_pad_set_chain_function (demux->sinkpad,
313 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314 gst_pad_set_event_function (demux->sinkpad,
315 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316 gst_pad_set_activate_function (demux->sinkpad,
317 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318 gst_pad_set_activatemode_function (demux->sinkpad,
319 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
322 /* set initial state */
323 gst_asf_demux_reset (demux, FALSE);
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
332 query = gst_query_new_scheduling ();
334 if (!gst_pad_peer_query (sinkpad, query)) {
335 gst_query_unref (query);
339 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341 gst_query_unref (query);
346 GST_DEBUG_OBJECT (sinkpad, "activating pull");
347 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
351 GST_DEBUG_OBJECT (sinkpad, "activating push");
352 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358 GstPadMode mode, gboolean active)
363 demux = GST_ASF_DEMUX (parent);
366 case GST_PAD_MODE_PUSH:
367 demux->state = GST_ASF_DEMUX_STATE_HEADER;
368 demux->streaming = TRUE;
371 case GST_PAD_MODE_PULL:
373 demux->state = GST_ASF_DEMUX_STATE_HEADER;
374 demux->streaming = FALSE;
376 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
379 res = gst_pad_stop_task (sinkpad);
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
395 demux = GST_ASF_DEMUX (parent);
397 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398 switch (GST_EVENT_TYPE (event)) {
399 case GST_EVENT_SEGMENT:{
400 const GstSegment *segment;
402 gst_event_parse_segment (event, &segment);
404 if (segment->format == GST_FORMAT_BYTES) {
405 if (demux->packet_size && segment->start > demux->data_offset)
406 demux->packet = (segment->start - demux->data_offset) /
410 } else if (segment->format == GST_FORMAT_TIME) {
411 /* do not know packet position, not really a problem */
414 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415 gst_event_unref (event);
419 /* record upstream segment for interpolation */
420 if (segment->format != demux->in_segment.format)
421 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422 gst_segment_copy_into (segment, &demux->in_segment);
424 /* in either case, clear some state and generate newsegment later on */
425 GST_OBJECT_LOCK (demux);
426 demux->segment_ts = GST_CLOCK_TIME_NONE;
427 demux->in_gap = GST_CLOCK_TIME_NONE;
428 demux->need_newsegment = TRUE;
429 demux->segment_seqnum = gst_event_get_seqnum (event);
430 gst_asf_demux_reset_stream_state_after_discont (demux);
431 /* if we seek back after reaching EOS, go back to packet reading state */
432 if (demux->data_offset > 0 && segment->start >= demux->data_offset
433 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
434 demux->state = GST_ASF_DEMUX_STATE_DATA;
436 GST_OBJECT_UNLOCK (demux);
438 gst_event_unref (event);
444 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
446 (_("This stream contains no data.")),
447 ("got eos and didn't receive a complete header object"));
450 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
451 if (!demux->activated_streams) {
452 /* If we still haven't got activated streams, the file is most likely corrupt */
453 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
454 (_("This stream contains no data.")),
455 ("got eos and didn't receive a complete header object"));
458 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
459 GST_ELEMENT_FLOW_ERROR (demux, flow);
463 GST_OBJECT_LOCK (demux);
464 gst_adapter_clear (demux->adapter);
465 GST_OBJECT_UNLOCK (demux);
466 gst_asf_demux_send_event_unlocked (demux, event);
470 case GST_EVENT_FLUSH_STOP:
471 GST_OBJECT_LOCK (demux);
472 gst_asf_demux_reset_stream_state_after_discont (demux);
473 GST_OBJECT_UNLOCK (demux);
474 gst_asf_demux_send_event_unlocked (demux, event);
475 /* upon activation, latency is no longer introduced, e.g. after seek */
476 if (demux->activated_streams)
481 ret = gst_pad_event_default (pad, parent, event);
489 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
490 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
491 gboolean next, gboolean * eos)
493 GstClockTime idx_time;
499 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
502 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
505 /* if we want the next keyframe, we have to go forward till we find
506 a different packet number */
508 if (idx >= demux->sidx_num_entries - 1) {
509 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
514 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
515 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
522 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
528 *packet = demux->sidx_entries[idx].packet;
530 *speed = demux->sidx_entries[idx].count;
532 /* so we get closer to the actual time of the packet ... actually, let's not
533 * do this, since we throw away superfluous payloads before the seek position
534 * anyway; this way, our key unit seek 'snap resolution' is a bit better
535 * (ie. same as index resolution) */
537 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
541 idx_time = demux->sidx_interval * idx;
542 if (G_LIKELY (idx_time >= demux->preroll))
543 idx_time -= demux->preroll;
545 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
546 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
547 GST_TIME_ARGS (idx_time));
549 if (G_LIKELY (p_idx_time))
550 *p_idx_time = idx_time;
556 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
560 gst_adapter_clear (demux->adapter);
562 GST_DEBUG_OBJECT (demux, "reset stream state");
564 gst_flow_combiner_reset (demux->flowcombiner);
565 for (n = 0; n < demux->num_streams; n++) {
566 demux->stream[n].discont = TRUE;
567 demux->stream[n].first_buffer = TRUE;
569 while (demux->stream[n].payloads->len > 0) {
573 last = demux->stream[n].payloads->len - 1;
574 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
575 gst_buffer_replace (&payload->buf, NULL);
576 g_array_remove_index (demux->stream[n].payloads, last);
582 gst_asf_demux_mark_discont (GstASFDemux * demux)
586 GST_DEBUG_OBJECT (demux, "Mark stream discont");
588 for (n = 0; n < demux->num_streams; n++)
589 demux->stream[n].discont = TRUE;
592 /* do a seek in push based mode */
594 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
599 GstSeekType cur_type, stop_type;
603 GstEvent *byte_event;
605 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
608 stop_type = GST_SEEK_TYPE_NONE;
611 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
613 /* determine packet, by index or by estimation */
614 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
617 (guint) gst_util_uint64_scale (demux->num_packets, cur,
621 if (packet > demux->num_packets) {
622 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
627 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
629 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
631 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
632 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
633 /* BYTE seek event */
634 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
635 cur, stop_type, stop);
636 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
637 res = gst_pad_push_event (demux->sinkpad, byte_event);
643 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
645 GstClockTime idx_time;
648 GstSeekType cur_type, stop_type;
650 gboolean only_need_update;
651 gboolean after, before, next;
656 guint packet, speed_count = 1;
662 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
665 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
666 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
670 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
671 * so first try to let it handle the seek event. */
672 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
675 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
676 demux->num_packets == 0 || demux->play_time == 0)) {
677 GST_LOG_OBJECT (demux, "stream is not seekable");
681 if (G_UNLIKELY (!demux->activated_streams)) {
682 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
686 if (G_UNLIKELY (rate <= 0.0)) {
687 GST_LOG_OBJECT (demux, "backward playback");
688 demux->seek_to_cur_pos = TRUE;
689 for (i = 0; i < demux->num_streams; i++) {
690 demux->stream[i].reverse_kf_ready = FALSE;
694 seqnum = gst_event_get_seqnum (event);
695 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
697 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
698 demux->keyunit_sync =
699 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
700 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
701 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
702 next = after && !before;
704 if (G_UNLIKELY (demux->streaming)) {
705 /* support it safely needs more segment handling, e.g. closing etc */
707 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
710 /* we can (re)construct the start later on, but not the end */
711 if (stop_type != GST_SEEK_TYPE_NONE &&
712 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
713 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
716 return gst_asf_demux_handle_seek_push (demux, event);
719 /* unlock the streaming thread */
720 if (G_LIKELY (flush)) {
721 fevent = gst_event_new_flush_start ();
723 gst_event_set_seqnum (fevent, seqnum);
724 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
725 gst_asf_demux_send_event_unlocked (demux, fevent);
727 gst_pad_pause_task (demux->sinkpad);
730 /* grab the stream lock so that streaming cannot continue, for
731 * non flushing seeks when the element is in PAUSED this could block
733 GST_PAD_STREAM_LOCK (demux->sinkpad);
735 /* we now can stop flushing, since we have the stream lock now */
736 fevent = gst_event_new_flush_stop (TRUE);
737 gst_event_set_seqnum (fevent, seqnum);
738 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
740 if (G_LIKELY (flush))
741 gst_asf_demux_send_event_unlocked (demux, fevent);
743 gst_event_unref (fevent);
745 /* operating on copy of segment until we know the seek worked */
746 segment = demux->segment;
748 if (G_UNLIKELY (demux->segment_running && !flush)) {
749 GstSegment newsegment;
752 /* create the segment event to close the current segment */
753 gst_segment_copy_into (&segment, &newsegment);
754 newseg = gst_event_new_segment (&newsegment);
755 gst_event_set_seqnum (newseg, seqnum);
757 gst_asf_demux_send_event_unlocked (demux, newseg);
760 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
761 cur, stop_type, stop, &only_need_update);
763 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
764 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
766 if (cur_type != GST_SEEK_TYPE_SET)
767 seek_time = segment.start;
771 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
772 * real start of data and segment_start to indexed time for key unit seek*/
773 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
774 &idx_time, &speed_count, next, &eos))) {
778 demux->packet = demux->num_packets;
782 /* First try to query our source to see if it can convert for us. This is
783 the case when our source is an mms stream, notice that in this case
784 gstmms will do a time based seek to get the byte offset, this is not a
785 problem as the seek to this offset needs to happen anway. */
786 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
787 GST_FORMAT_BYTES, &offset)) {
788 packet = (offset - demux->data_offset) / demux->packet_size;
789 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
790 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
791 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
792 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
793 demux->packet_size, packet);
795 /* FIXME: For streams containing video, seek to an earlier position in
796 * the hope of hitting a keyframe and let the sinks throw away the stuff
797 * before the segment start. For audio-only this is unnecessary as every
799 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
800 && demux->num_video_streams > 0) {
801 seek_time -= 5 * GST_SECOND;
806 packet = (guint) gst_util_uint64_scale (demux->num_packets,
807 seek_time, demux->play_time);
809 if (packet > demux->num_packets)
810 packet = demux->num_packets;
813 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
814 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
815 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
816 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
817 segment.start = idx_time;
818 segment.position = idx_time;
819 segment.time = idx_time;
823 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
825 GST_OBJECT_LOCK (demux);
826 demux->segment = segment;
827 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
828 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
829 stop, demux->play_time);
831 demux->packet = packet;
834 demux->need_newsegment = TRUE;
835 demux->segment_seqnum = seqnum;
836 demux->speed_packets =
837 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
838 gst_asf_demux_reset_stream_state_after_discont (demux);
839 GST_OBJECT_UNLOCK (demux);
842 /* restart our task since it might have been stopped when we did the flush */
843 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
846 /* streaming can continue now */
847 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
853 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
859 demux = GST_ASF_DEMUX (parent);
861 switch (GST_EVENT_TYPE (event)) {
863 GST_LOG_OBJECT (pad, "seek event");
864 ret = gst_asf_demux_handle_seek_event (demux, event);
865 gst_event_unref (event);
868 case GST_EVENT_NAVIGATION:
869 /* just drop these two silently */
870 gst_event_unref (event);
874 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
875 ret = gst_pad_event_default (pad, parent, event);
882 static inline guint32
883 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
887 ret = gst_asf_identify_guid (guids, guid);
889 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
890 gst_asf_get_guid_nick (guids, ret),
891 guid->v1, guid->v2, guid->v3, guid->v4);
903 /* Peek for an object.
905 * Returns FALSE is the object is corrupted (such as the reported
906 * object size being greater than 2**32bits.
909 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
910 guint data_len, AsfObject * object, gboolean expect)
914 /* Callers should have made sure that data_len is big enough */
915 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
917 if (data_len < ASF_OBJECT_HEADER_SIZE)
920 guid.v1 = GST_READ_UINT32_LE (data + 0);
921 guid.v2 = GST_READ_UINT32_LE (data + 4);
922 guid.v3 = GST_READ_UINT32_LE (data + 8);
923 guid.v4 = GST_READ_UINT32_LE (data + 12);
925 /* FIXME: make asf_demux_identify_object_guid() */
926 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
927 if (object->id == ASF_OBJ_UNDEFINED && expect) {
928 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
929 guid.v1, guid.v2, guid.v3, guid.v4);
932 object->size = GST_READ_UINT64_LE (data + 16);
933 if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
934 GST_WARNING_OBJECT (demux,
935 "ASF Object size corrupted (greater than 32bit)");
944 gst_asf_demux_release_old_pads (GstASFDemux * demux)
946 GST_DEBUG_OBJECT (demux, "Releasing old pads");
948 while (demux->old_num_streams > 0) {
949 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
950 gst_event_new_eos ());
951 gst_asf_demux_free_stream (demux,
952 &demux->old_stream[demux->old_num_streams - 1]);
953 --demux->old_num_streams;
955 memset (demux->old_stream, 0, sizeof (demux->old_stream));
956 demux->old_num_streams = 0;
960 gst_asf_demux_chain_headers (GstASFDemux * demux)
963 guint8 *header_data, *data = NULL;
964 const guint8 *cdata = NULL;
966 GstFlowReturn flow = GST_FLOW_OK;
968 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
972 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
974 if (obj.id != ASF_OBJ_HEADER)
977 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
979 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
980 if (gst_adapter_available (demux->adapter) < obj.size + 50)
983 data = gst_adapter_take (demux->adapter, obj.size + 50);
986 header_size = obj.size;
987 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
988 if (flow != GST_FLOW_OK)
991 /* calculate where the packet data starts */
992 demux->data_offset = obj.size + 50;
994 /* now parse the beginning of the ASF_OBJ_DATA object */
995 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
998 if (demux->num_streams == 0)
1007 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1014 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1015 ("This doesn't seem to be an ASF file"));
1017 return GST_FLOW_ERROR;
1022 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1023 ("header parsing failed, or no streams found, flow = %s",
1024 gst_flow_get_name (flow)));
1026 return GST_FLOW_ERROR;
1031 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1032 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1037 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1040 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1042 if (G_LIKELY (p_flow))
1045 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1046 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1047 "+%u", gst_flow_get_name (flow), offset, size);
1052 g_assert (*p_buf != NULL);
1054 buffer_size = gst_buffer_get_size (*p_buf);
1055 if (G_UNLIKELY (buffer_size < size)) {
1056 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1057 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1058 gst_buffer_unref (*p_buf);
1059 if (G_LIKELY (p_flow))
1060 *p_flow = GST_FLOW_EOS;
1068 static GstFlowReturn
1069 gst_asf_demux_pull_indices (GstASFDemux * demux)
1071 GstBuffer *buf = NULL;
1074 GstFlowReturn ret = GST_FLOW_OK;
1076 offset = demux->index_offset;
1078 if (G_UNLIKELY (offset == 0)) {
1079 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1084 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1090 gst_buffer_map (buf, &map, GST_MAP_READ);
1091 g_assert (map.size >= 16 + 8);
1092 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1093 GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
1094 GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
1096 gst_buffer_unmap (buf, &map);
1097 gst_buffer_replace (&buf, NULL);
1098 /* Non-fatal, return */
1101 gst_buffer_unmap (buf, &map);
1102 gst_buffer_replace (&buf, NULL);
1104 /* check for sanity */
1105 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1106 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1110 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1114 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1115 ", size %u", offset, (guint) obj.size);
1117 offset += obj.size; /* increase before _process_object changes it */
1119 gst_buffer_map (buf, &map, GST_MAP_READ);
1120 g_assert (map.size >= obj.size);
1121 bufdata = (guint8 *) map.data;
1122 obj_size = obj.size;
1123 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1124 gst_buffer_unmap (buf, &map);
1125 gst_buffer_replace (&buf, NULL);
1127 if (ret == ASF_FLOW_NEED_MORE_DATA) {
1128 /* Since indices are at the end of the file, if we need more data,
1129 * we consider it as a non-fatal corrupted index */
1134 if (G_UNLIKELY (ret != GST_FLOW_OK))
1140 GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
1141 gst_flow_get_name (ret));
1146 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1150 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1151 GST_WARNING_OBJECT (demux, "Corrupted data");
1154 if (obj.id != ASF_OBJ_DATA) {
1155 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1159 demux->state = GST_ASF_DEMUX_STATE_DATA;
1161 if (!demux->broadcast && obj.size > 50) {
1162 demux->data_size = obj.size - 50;
1163 /* CHECKME: for at least one file this is off by +158 bytes?! */
1164 demux->index_offset = demux->data_offset + demux->data_size;
1166 demux->data_size = 0;
1167 demux->index_offset = 0;
1172 if (!demux->broadcast) {
1173 /* skip object header (24 bytes) and file GUID (16 bytes) */
1174 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1176 demux->num_packets = 0;
1179 if (demux->num_packets == 0)
1180 demux->seekable = FALSE;
1182 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1183 if (demux->data_size == 0 && demux->num_packets > 0) {
1184 demux->data_size = demux->num_packets * demux->packet_size;
1185 demux->index_offset = demux->data_offset + demux->data_size;
1188 /* process pending stream objects and create pads for those */
1189 gst_asf_demux_process_queued_extended_stream_objects (demux);
1191 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1192 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1193 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1194 demux->data_offset, demux->data_size, demux->index_offset);
1195 #ifdef TIZEN_FEATURE_ASFDEMUX_CHECK_DATA_SIZE
1196 if (demux->data_size == 0) {
1197 GST_WARNING_OBJECT (demux, "DATA object size is zero");
1205 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1207 GstFlowReturn flow = GST_FLOW_OK;
1209 GstBuffer *buf = NULL;
1214 GST_LOG_OBJECT (demux, "reading headers");
1216 /* pull HEADER object header, so we know its size */
1217 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1220 gst_buffer_map (buf, &map, GST_MAP_READ);
1221 g_assert (map.size >= 16 + 8);
1222 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1223 gst_buffer_unmap (buf, &map);
1224 gst_buffer_replace (&buf, NULL);
1225 flow = GST_FLOW_ERROR;
1228 gst_buffer_unmap (buf, &map);
1229 gst_buffer_replace (&buf, NULL);
1231 if (obj.id != ASF_OBJ_HEADER)
1234 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1236 /* pull HEADER object */
1237 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1241 size = obj.size; /* don't want obj.size changed */
1242 gst_buffer_map (buf, &map, GST_MAP_READ);
1243 g_assert (map.size >= size);
1244 bufdata = (guint8 *) map.data;
1245 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1246 gst_buffer_unmap (buf, &map);
1247 gst_buffer_replace (&buf, NULL);
1249 if (flow != GST_FLOW_OK) {
1250 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1254 /* calculate where the packet data starts */
1255 demux->data_offset = demux->base_offset + obj.size + 50;
1257 /* now pull beginning of DATA object before packet data */
1258 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1262 gst_buffer_map (buf, &map, GST_MAP_READ);
1263 g_assert (map.size >= size);
1264 bufdata = (guint8 *) map.data;
1265 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1268 if (demux->num_streams == 0)
1271 gst_buffer_unmap (buf, &map);
1272 gst_buffer_replace (&buf, NULL);
1280 gst_buffer_unmap (buf, &map);
1281 gst_buffer_replace (&buf, NULL);
1283 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1284 ("This doesn't seem to be an ASF file"));
1285 *pflow = GST_FLOW_ERROR;
1290 flow = GST_FLOW_ERROR;
1291 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1292 ("header parsing failed, or no streams found, flow = %s",
1293 gst_flow_get_name (flow)));
1298 gst_buffer_unmap (buf, &map);
1299 gst_buffer_replace (&buf, NULL);
1300 if (flow == ASF_FLOW_NEED_MORE_DATA)
1301 flow = GST_FLOW_ERROR;
1308 all_streams_prerolled (GstASFDemux * demux)
1310 GstClockTime preroll_time;
1311 guint i, num_no_data = 0;
1313 /* Allow at least 500ms of preroll_time */
1314 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1316 /* returns TRUE as long as there isn't a stream which (a) has data queued
1317 * and (b) the timestamp of last piece of data queued is < demux->preroll
1318 * AND there is at least one other stream with data queued */
1319 for (i = 0; i < demux->num_streams; ++i) {
1320 AsfPayload *last_payload = NULL;
1324 stream = &demux->stream[i];
1325 if (G_UNLIKELY (stream->payloads->len == 0)) {
1327 GST_LOG_OBJECT (stream->pad, "no data queued");
1331 /* find last payload with timestamp */
1332 for (last_idx = stream->payloads->len - 1;
1333 last_idx >= 0 && (last_payload == NULL
1334 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1335 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1338 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1339 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1340 GST_TIME_ARGS (preroll_time));
1341 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1342 || last_payload->ts <= preroll_time)) {
1343 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1348 if (G_UNLIKELY (num_no_data > 0))
1356 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1361 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1364 /* check for each mutual exclusion group whether it affects this stream */
1365 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1366 if (*mes == stream->id) {
1367 /* we are in this group; let's check if we've already activated streams
1368 * that are in the same group (and hence mutually exclusive to this
1370 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1373 for (i = 0; i < demux->num_streams; ++i) {
1374 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1375 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1376 "to already active stream with ID %d", stream->id,
1377 demux->stream[i].id);
1382 /* we can only be in this group once, let's break out and move on to
1383 * the next mutual exclusion group */
1394 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1396 /* remember the first queued timestamp for the segment */
1397 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1398 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1399 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1400 GST_TIME_ARGS (demux->first_ts));
1401 demux->segment_ts = payload_ts;
1402 /* always note, but only determines segment when streaming */
1403 if (demux->streaming)
1404 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1405 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1406 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1411 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1413 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1414 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1417 /* go trhough each stream, find smallest timestamp */
1418 for (i = 0; i < demux->num_streams; ++i) {
1421 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1422 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1423 stream = &demux->stream[i];
1425 for (j = 0; j < stream->payloads->len; ++j) {
1426 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1427 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1428 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1429 || stream_min_ts > payload->ts)) {
1430 stream_min_ts = payload->ts;
1432 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1433 payload->ts > stream_min_ts &&
1434 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1435 || stream_min_ts2 > payload->ts)) {
1436 stream_min_ts2 = payload->ts;
1440 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1441 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1442 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1443 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1444 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1446 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1449 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1450 stream_min_ts = stream_min_ts2;
1452 /* if we don't have timestamp for this stream, wait for more data */
1453 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1456 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1457 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1458 first_ts = stream_min_ts;
1461 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1464 demux->first_ts = first_ts;
1466 /* update packets queued before we knew first timestamp */
1467 for (i = 0; i < demux->num_streams; ++i) {
1470 stream = &demux->stream[i];
1472 for (j = 0; j < stream->payloads->len; ++j) {
1473 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1474 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1475 if (payload->ts > first_ts)
1476 payload->ts -= first_ts;
1484 gst_asf_demux_check_segment_ts (demux, 0);
1490 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1492 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1493 and often set wrong, inspecting the data is the only way that seem to be working */
1494 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1495 GstCaps *caps = NULL;
1497 GstAdapter *adapter = gst_adapter_new ();
1499 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1501 AsfPayload *payload;
1504 payload = &g_array_index (stream->payloads, AsfPayload, i);
1505 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1506 len = gst_adapter_available (adapter);
1507 data = gst_adapter_map (adapter, len);
1511 #define MIN_LENGTH 128
1513 /* look for the sync points */
1515 if (len < MIN_LENGTH || /* give typefind something to work on */
1516 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1517 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1523 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1526 if (prob < GST_TYPE_FIND_LIKELY) {
1529 if (len > MIN_LENGTH)
1530 /* this wasn't it, look for another sync point */
1534 gst_adapter_unmap (adapter);
1537 gst_object_unref (adapter);
1540 gst_caps_take (&stream->caps, caps);
1548 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1550 guint i, actual_streams = 0;
1552 if (demux->activated_streams)
1555 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1558 if (!all_streams_prerolled (demux) && !force) {
1559 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1563 for (i = 0; i < demux->num_streams; ++i) {
1564 AsfStream *stream = &demux->stream[i];
1566 if (stream->payloads->len > 0) {
1568 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1569 !stream->active && /* do not inspect active streams (caps were already set) */
1570 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1571 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1572 /* try to gather some more data */
1575 /* we don't check mutual exclusion stuff here; either we have data for
1576 * a stream, then we active it, or we don't, then we'll ignore it */
1577 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1578 gst_asf_demux_activate_stream (demux, stream);
1579 actual_streams += 1;
1581 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1585 if (actual_streams == 0) {
1586 /* We don't have any streams activated ! */
1587 GST_ERROR_OBJECT (demux, "No streams activated!");
1591 gst_asf_demux_release_old_pads (demux);
1593 demux->activated_streams = TRUE;
1594 GST_LOG_OBJECT (demux, "signalling no more pads");
1595 gst_element_no_more_pads (GST_ELEMENT (demux));
1599 /* returns the stream that has a complete payload with the lowest timestamp
1600 * queued, or NULL (we push things by timestamp because during the internal
1601 * prerolling we might accumulate more data then the external queues can take,
1602 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1604 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1606 AsfPayload *best_payload = NULL;
1607 AsfStream *best_stream = NULL;
1610 for (i = 0; i < demux->num_streams; ++i) {
1614 stream = &demux->stream[i];
1616 /* Don't push any data until we have at least one payload that falls within
1617 * the current segment. This way we can remove out-of-segment payloads that
1618 * don't need to be decoded after a seek, sending only data from the
1619 * keyframe directly before our segment start */
1620 if (stream->payloads->len > 0) {
1621 AsfPayload *payload = NULL;
1624 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1625 /* Reverse playback */
1627 if (stream->is_video) {
1628 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1629 if (stream->reverse_kf_ready) {
1631 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1632 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1633 /* TODO : remove payload from the list? */
1640 /* find first complete payload with timestamp */
1641 for (j = stream->payloads->len - 1;
1642 j >= 0 && (payload == NULL
1643 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1644 payload = &g_array_index (stream->payloads, AsfPayload, j);
1647 /* If there's a complete payload queued for this stream */
1648 if (!gst_asf_payload_is_complete (payload))
1654 /* find last payload with timestamp */
1655 for (last_idx = stream->payloads->len - 1;
1656 last_idx >= 0 && (payload == NULL
1657 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1658 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1661 /* if this is first payload after seek we might need to update the segment */
1662 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1663 gst_asf_demux_check_segment_ts (demux, payload->ts);
1665 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1666 (payload->ts < demux->segment.start))) {
1667 if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1668 && payload->keyframe)) {
1669 GST_DEBUG_OBJECT (stream->pad,
1670 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1671 GST_TIME_ARGS (payload->ts));
1672 demux->segment.start = payload->ts;
1673 demux->segment.time = payload->ts;
1675 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1676 GST_TIME_FORMAT " which is before our segment start %"
1677 GST_TIME_FORMAT ", not pushing yet",
1678 GST_TIME_ARGS (payload->ts),
1679 GST_TIME_ARGS (demux->segment.start));
1684 /* find first complete payload with timestamp */
1686 j < stream->payloads->len && (payload == NULL
1687 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1688 payload = &g_array_index (stream->payloads, AsfPayload, j);
1691 /* Now see if there's a complete payload queued for this stream */
1692 if (!gst_asf_payload_is_complete (payload))
1696 /* ... and whether its timestamp is lower than the current best */
1697 if (best_stream == NULL || best_payload->ts > payload->ts) {
1698 best_stream = stream;
1699 best_payload = payload;
1707 static GstFlowReturn
1708 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1711 GstFlowReturn ret = GST_FLOW_OK;
1713 if (G_UNLIKELY (!demux->activated_streams)) {
1714 if (!gst_asf_demux_check_activate_streams (demux, force))
1716 /* streams are now activated */
1719 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1720 AsfPayload *payload;
1721 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1722 GstClockTime duration = GST_CLOCK_TIME_NONE;
1724 /* wait until we had a chance to "lock on" some payload's timestamp */
1725 if (G_UNLIKELY (demux->need_newsegment
1726 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1729 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1730 && stream->payloads->len) {
1731 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1733 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1736 /* do we need to send a newsegment event */
1737 if ((G_UNLIKELY (demux->need_newsegment))) {
1738 GstEvent *segment_event;
1740 /* safe default if insufficient upstream info */
1741 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1744 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1745 demux->segment.duration > 0) {
1746 /* slight HACK; prevent clipping of last bit */
1747 demux->segment.stop = demux->segment.duration + demux->in_gap;
1750 /* FIXME : only if ACCURATE ! */
1751 if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1752 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1753 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1754 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1755 GST_TIME_ARGS (payload->ts));
1756 demux->segment.start = payload->ts;
1757 demux->segment.time = payload->ts;
1760 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1763 /* note: we fix up all timestamps to start from 0, so this should be ok */
1764 segment_event = gst_event_new_segment (&demux->segment);
1765 if (demux->segment_seqnum)
1766 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1767 gst_asf_demux_send_event_unlocked (demux, segment_event);
1769 /* now post any global tags we may have found */
1770 if (demux->taglist == NULL) {
1771 demux->taglist = gst_tag_list_new_empty ();
1772 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1775 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1776 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1778 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1779 gst_asf_demux_send_event_unlocked (demux,
1780 gst_event_new_tag (demux->taglist));
1781 demux->taglist = NULL;
1783 demux->need_newsegment = FALSE;
1784 demux->segment_seqnum = 0;
1785 demux->segment_running = TRUE;
1788 /* Do we have tags pending for this stream? */
1789 if (G_UNLIKELY (stream->pending_tags)) {
1790 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1791 gst_pad_push_event (stream->pad,
1792 gst_event_new_tag (stream->pending_tags));
1793 stream->pending_tags = NULL;
1796 /* We have the whole packet now so we should push the packet to
1797 * the src pad now. First though we should check if we need to do
1799 if (G_UNLIKELY (stream->span > 1)) {
1800 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1803 payload->buf = gst_buffer_make_writable (payload->buf);
1805 if (G_LIKELY (!payload->keyframe)) {
1806 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1809 if (G_UNLIKELY (stream->discont)) {
1810 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1811 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1812 stream->discont = FALSE;
1815 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1816 (payload->par_x != stream->par_x) &&
1817 (payload->par_y != stream->par_y))) {
1818 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1819 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1820 stream->par_x = payload->par_x;
1821 stream->par_y = payload->par_y;
1822 stream->caps = gst_caps_make_writable (stream->caps);
1823 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1824 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1825 gst_pad_set_caps (stream->pad, stream->caps);
1828 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1829 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1830 payload->interlaced);
1831 stream->interlaced = payload->interlaced;
1832 stream->caps = gst_caps_make_writable (stream->caps);
1833 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1834 (stream->interlaced ? "mixed" : "progressive"), NULL);
1835 gst_pad_set_caps (stream->pad, stream->caps);
1838 /* (sort of) interpolate timestamps using upstream "frame of reference",
1839 * typically useful for live src, but might (unavoidably) mess with
1840 * position reporting if a live src is playing not so live content
1841 * (e.g. rtspsrc taking some time to fall back to tcp) */
1842 timestamp = payload->ts;
1843 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1844 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1845 timestamp += demux->in_gap;
1847 /* Check if we're after the segment already, if so no need to push
1849 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1850 GST_DEBUG_OBJECT (stream->pad,
1851 "Payload after segment stop %" GST_TIME_FORMAT,
1852 GST_TIME_ARGS (demux->segment.stop));
1854 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1856 gst_buffer_unref (payload->buf);
1857 payload->buf = NULL;
1858 g_array_remove_index (stream->payloads, 0);
1859 /* Break out as soon as we have an issue */
1860 if (G_UNLIKELY (ret != GST_FLOW_OK))
1867 GST_BUFFER_PTS (payload->buf) = timestamp;
1869 if (payload->duration == GST_CLOCK_TIME_NONE
1870 && stream->ext_props.avg_time_per_frame != 0) {
1871 duration = stream->ext_props.avg_time_per_frame * 100;
1873 duration = payload->duration;
1875 GST_BUFFER_DURATION (payload->buf) = duration;
1877 /* FIXME: we should really set durations on buffers if we can */
1879 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1882 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1883 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1884 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1886 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1887 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1891 if (stream->active) {
1892 if (G_UNLIKELY (stream->first_buffer)) {
1893 if (stream->streamheader != NULL) {
1894 GST_DEBUG_OBJECT (stream->pad,
1895 "Pushing streamheader before first buffer");
1896 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1898 stream->first_buffer = FALSE;
1901 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1902 && timestamp > demux->segment.position) {
1903 demux->segment.position = timestamp;
1904 if (GST_CLOCK_TIME_IS_VALID (duration))
1905 demux->segment.position += timestamp;
1908 ret = gst_pad_push (stream->pad, payload->buf);
1910 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1913 gst_buffer_unref (payload->buf);
1916 payload->buf = NULL;
1917 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1918 && stream->reverse_kf_ready) {
1919 g_array_remove_index (stream->payloads, stream->kf_pos);
1922 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1924 stream->reverse_kf_ready = FALSE;
1927 g_array_remove_index (stream->payloads, 0);
1930 /* Break out as soon as we have an issue */
1931 if (G_UNLIKELY (ret != GST_FLOW_OK))
1939 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1944 g_assert (buf != NULL);
1946 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1948 gst_buffer_map (buf, &map, GST_MAP_READ);
1950 /* we return false on buffer too small */
1951 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1952 gst_buffer_unmap (buf, &map);
1956 /* check if it is a header */
1958 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1960 gst_buffer_unmap (buf, &map);
1961 if (valid && obj.id == ASF_OBJ_HEADER) {
1968 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1970 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1971 GstFlowReturn ret = GST_FLOW_OK;
1972 GstBuffer *buf = NULL;
1973 gboolean header = FALSE;
1975 /* TODO maybe we should skip index objects after the data and look
1976 * further for a new header */
1977 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1978 g_assert (buf != NULL);
1979 /* check if it is a header */
1980 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1981 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1982 demux->base_offset = off;
1986 gst_buffer_unref (buf);
1993 gst_asf_demux_loop (GstASFDemux * demux)
1995 GstFlowReturn flow = GST_FLOW_OK;
1996 GstBuffer *buf = NULL;
1999 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
2000 if (!gst_asf_demux_pull_headers (demux, &flow)) {
2004 flow = gst_asf_demux_pull_indices (demux);
2005 if (flow != GST_FLOW_OK)
2009 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
2011 if (G_UNLIKELY (demux->num_packets != 0
2012 && demux->packet >= demux->num_packets))
2015 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2016 (guint) demux->num_packets);
2018 off = demux->data_offset + (demux->packet * demux->packet_size);
2020 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2021 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2022 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2023 if (flow == GST_FLOW_EOS) {
2025 } else if (flow == GST_FLOW_FLUSHING) {
2026 GST_DEBUG_OBJECT (demux, "Not fatal");
2033 if (G_LIKELY (demux->speed_packets == 1)) {
2034 GstAsfDemuxParsePacketError err;
2035 err = gst_asf_demux_parse_packet (demux, buf);
2036 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2037 /* when we don't know when the data object ends, we should check
2038 * for a chained asf */
2039 if (demux->num_packets == 0) {
2040 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2041 GST_INFO_OBJECT (demux, "Chained asf found");
2042 demux->base_offset = off;
2043 gst_asf_demux_reset (demux, TRUE);
2044 gst_buffer_unref (buf);
2048 /* FIXME: We should tally up fatal errors and error out only
2049 * after a few broken packets in a row? */
2051 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2052 gst_buffer_unref (buf);
2054 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2055 && !demux->seek_to_cur_pos) {
2057 if (demux->packet < 0) {
2067 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2069 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2070 && !demux->seek_to_cur_pos) {
2072 if (demux->packet < 0) {
2081 for (n = 0; n < demux->speed_packets; n++) {
2083 GstAsfDemuxParsePacketError err;
2086 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2087 n * demux->packet_size, demux->packet_size);
2088 err = gst_asf_demux_parse_packet (demux, sub);
2089 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2090 /* when we don't know when the data object ends, we should check
2091 * for a chained asf */
2092 if (demux->num_packets == 0) {
2093 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2094 GST_INFO_OBJECT (demux, "Chained asf found");
2095 demux->base_offset = off + n * demux->packet_size;
2096 gst_asf_demux_reset (demux, TRUE);
2097 gst_buffer_unref (sub);
2098 gst_buffer_unref (buf);
2102 /* FIXME: We should tally up fatal errors and error out only
2103 * after a few broken packets in a row? */
2105 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2109 gst_buffer_unref (sub);
2111 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2112 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2118 /* reset speed pull */
2119 demux->speed_packets = 1;
2122 gst_buffer_unref (buf);
2124 if (G_UNLIKELY ((demux->num_packets > 0
2125 && demux->packet >= demux->num_packets)
2126 || flow == GST_FLOW_EOS)) {
2127 GST_LOG_OBJECT (demux, "reached EOS");
2131 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2132 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2136 /* check if we're at the end of the configured segment */
2137 /* FIXME: check if segment end reached etc. */
2143 /* if we haven't activated our streams yet, this might be because we have
2144 * less data queued than required for preroll; force stream activation and
2145 * send any pending payloads before sending EOS */
2146 if (!demux->activated_streams)
2147 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2149 /* we want to push an eos or post a segment-done in any case */
2150 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2153 /* for segment playback we need to post when (in stream time)
2154 * we stopped, this is either stop (when set) or the duration. */
2155 if ((stop = demux->segment.stop) == -1)
2156 stop = demux->segment.duration;
2158 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2159 gst_element_post_message (GST_ELEMENT_CAST (demux),
2160 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2162 gst_asf_demux_send_event_unlocked (demux,
2163 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2164 } else if (flow != GST_FLOW_EOS) {
2165 /* check if we have a chained asf, in case, we don't eos yet */
2166 if (gst_asf_demux_check_chained_asf (demux)) {
2167 GST_INFO_OBJECT (demux, "Chained ASF starting");
2168 gst_asf_demux_reset (demux, TRUE);
2173 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2174 if (demux->activated_streams) {
2175 /* normal playback, send EOS to all linked pads */
2176 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2177 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2179 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2180 flow = GST_FLOW_EOS;
2183 /* ... and fall through to pause */
2187 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2188 gst_flow_get_name (flow));
2189 demux->segment_running = FALSE;
2190 gst_pad_pause_task (demux->sinkpad);
2192 /* For the error cases */
2193 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2194 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2195 ("This doesn't seem to be an ASF file"));
2196 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2197 /* Post an error. Hopefully something else already has, but if not... */
2198 GST_ELEMENT_FLOW_ERROR (demux, flow);
2199 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2208 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2209 flow = GST_FLOW_EOS;
2213 /* See FIXMEs above */
2216 gst_buffer_unref (buf);
2217 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2218 ("Error parsing ASF packet %u", (guint) demux->packet));
2219 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2220 flow = GST_FLOW_ERROR;
2226 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2227 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2228 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2231 gst_asf_demux_check_header (GstASFDemux * demux)
2234 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2235 ASF_OBJECT_HEADER_SIZE);
2236 if (cdata == NULL) /* need more data */
2237 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2239 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
2240 && obj.id == ASF_OBJ_HEADER) {
2241 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2244 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2247 static GstFlowReturn
2248 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2250 GstFlowReturn ret = GST_FLOW_OK;
2253 demux = GST_ASF_DEMUX (parent);
2255 GST_LOG_OBJECT (demux,
2256 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2257 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2258 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2260 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2261 GST_DEBUG_OBJECT (demux, "received DISCONT");
2262 gst_asf_demux_mark_discont (demux);
2265 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2266 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2267 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2268 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2269 ", interpolation gap: %" GST_TIME_FORMAT,
2270 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2273 gst_adapter_push (demux->adapter, buf);
2275 switch (demux->state) {
2276 case GST_ASF_DEMUX_STATE_INDEX:{
2277 gint result = gst_asf_demux_check_header (demux);
2278 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2281 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2282 /* we don't care about this, probably an index */
2283 /* TODO maybe would be smarter to skip all the indices
2284 * until we got a new header or EOS to decide */
2285 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2288 GST_INFO_OBJECT (demux, "Chained asf starting");
2289 /* cleanup and get ready for a chained asf */
2290 gst_asf_demux_reset (demux, TRUE);
2294 case GST_ASF_DEMUX_STATE_HEADER:{
2295 ret = gst_asf_demux_chain_headers (demux);
2296 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2298 /* otherwise fall through */
2300 case GST_ASF_DEMUX_STATE_DATA:
2304 data_size = demux->packet_size;
2306 while (gst_adapter_available (demux->adapter) >= data_size) {
2308 GstAsfDemuxParsePacketError err;
2310 /* we don't know the length of the stream
2311 * check for a chained asf everytime */
2312 if (demux->num_packets == 0) {
2313 gint result = gst_asf_demux_check_header (demux);
2315 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2316 GST_INFO_OBJECT (demux, "Chained asf starting");
2317 /* cleanup and get ready for a chained asf */
2318 gst_asf_demux_reset (demux, TRUE);
2321 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2322 && demux->packet >= demux->num_packets)) {
2323 /* do not overshoot data section when streaming */
2327 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2329 /* FIXME: We should tally up fatal errors and error out only
2330 * after a few broken packets in a row? */
2331 err = gst_asf_demux_parse_packet (demux, buf);
2333 gst_buffer_unref (buf);
2335 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2336 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2338 GST_WARNING_OBJECT (demux, "Parse error");
2340 if (demux->packet >= 0)
2343 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2344 && demux->packet >= demux->num_packets)) {
2345 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2350 g_assert_not_reached ();
2354 if (ret != GST_FLOW_OK)
2355 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2361 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2367 static inline gboolean
2368 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2370 if (*p_size < num_bytes)
2373 *p_data += num_bytes;
2374 *p_size -= num_bytes;
2378 static inline guint8
2379 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2383 g_assert (*p_size >= 1);
2384 ret = GST_READ_UINT8 (*p_data);
2385 *p_data += sizeof (guint8);
2386 *p_size -= sizeof (guint8);
2390 static inline guint16
2391 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2395 g_assert (*p_size >= 2);
2396 ret = GST_READ_UINT16_LE (*p_data);
2397 *p_data += sizeof (guint16);
2398 *p_size -= sizeof (guint16);
2402 static inline guint32
2403 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2407 g_assert (*p_size >= 4);
2408 ret = GST_READ_UINT32_LE (*p_data);
2409 *p_data += sizeof (guint32);
2410 *p_size -= sizeof (guint32);
2414 static inline guint64
2415 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2419 g_assert (*p_size >= 8);
2420 ret = GST_READ_UINT64_LE (*p_data);
2421 *p_data += sizeof (guint64);
2422 *p_size -= sizeof (guint64);
2427 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2428 guint8 ** p_data, guint64 * p_size)
2432 if (*p_size < num_bytes_to_read)
2435 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2436 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2438 *p_data += num_bytes_to_read;
2439 *p_size -= num_bytes_to_read;
2445 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2446 guint8 ** p_data, guint64 * p_size)
2450 if (*p_size < num_bytes_to_read)
2453 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2454 *p_data += num_bytes_to_read;
2455 *p_size -= num_bytes_to_read;
2460 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2461 guint8 ** p_data, guint64 * p_size)
2471 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2474 *p_strlen = s_length;
2476 if (s_length == 0) {
2477 GST_WARNING ("zero-length string");
2478 *p_str = g_strdup ("");
2482 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2485 g_assert (s != NULL);
2487 /* just because They don't exist doesn't
2488 * mean They are not out to get you ... */
2489 if (s[s_length - 1] != '\0') {
2490 s = g_realloc (s, s_length + 1);
2494 *p_str = (gchar *) s;
2500 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2502 g_assert (*p_size >= 4 * sizeof (guint32));
2504 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2505 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2506 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2507 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2511 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2514 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2517 /* WAVEFORMATEX Structure */
2518 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2519 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2520 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2521 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2522 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2523 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2524 /* Codec specific data size */
2525 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2526 if (audio->size > *p_size) {
2527 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2528 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2535 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2538 if (*p_size < (4 + 4 + 1 + 2))
2541 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2542 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2543 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2544 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2549 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2550 guint8 ** p_data, guint64 * p_size)
2552 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2555 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2557 if (fmt->size < 40) {
2558 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2561 if ((guint64) fmt->size - 4 > *p_size) {
2562 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2565 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2566 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2567 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2568 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2569 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2570 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2571 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2572 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2573 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2574 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2579 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2583 for (i = 0; i < demux->num_streams; i++) {
2584 if (demux->stream[i].id == id)
2585 return &demux->stream[i];
2588 if (gst_asf_demux_is_unknown_stream (demux, id))
2589 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2594 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2595 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2600 gst_pad_use_fixed_caps (src_pad);
2601 gst_pad_set_caps (src_pad, caps);
2603 gst_pad_set_event_function (src_pad,
2604 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2605 gst_pad_set_query_function (src_pad,
2606 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2608 stream = &demux->stream[demux->num_streams];
2609 stream->caps = caps;
2610 stream->pad = src_pad;
2612 stream->fps_known = !is_video; /* bit hacky for audio */
2613 stream->is_video = is_video;
2614 stream->pending_tags = tags;
2615 stream->discont = TRUE;
2616 stream->first_buffer = TRUE;
2617 stream->streamheader = streamheader;
2618 if (stream->streamheader) {
2619 stream->streamheader = gst_buffer_make_writable (streamheader);
2620 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2625 st = gst_caps_get_structure (caps, 0);
2626 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2627 par_x > 0 && par_y > 0) {
2628 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2629 stream->par_x = par_x;
2630 stream->par_y = par_y;
2634 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2636 /* TODO: create this array during reverse play? */
2637 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2639 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2640 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2642 ++demux->num_streams;
2644 stream->active = FALSE;
2650 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2651 GstBuffer * buffer, GstStructure * structure)
2653 GValue arr_val = G_VALUE_INIT;
2654 GValue buf_val = G_VALUE_INIT;
2656 g_value_init (&arr_val, GST_TYPE_ARRAY);
2657 g_value_init (&buf_val, GST_TYPE_BUFFER);
2659 gst_value_set_buffer (&buf_val, buffer);
2660 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2662 gst_structure_take_value (structure, "streamheader", &arr_val);
2666 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2667 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2669 GstTagList *tags = NULL;
2670 GstBuffer *extradata = NULL;
2673 guint16 size_left = 0;
2674 gchar *codec_name = NULL;
2677 size_left = audio->size;
2679 /* Create the audio pad */
2680 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2682 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2685 /* Swallow up any left over data and set up the
2686 * standard properties from the header info */
2688 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2689 "codec specific data", size_left);
2691 g_assert (size_left <= *p_size);
2692 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2695 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2696 * additional two bytes indicating extradata. */
2697 /* FIXME: Handle the channel reorder map here */
2698 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2699 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2702 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2703 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2706 /* Informing about that audio format we just added */
2708 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2709 g_free (codec_name);
2712 if (audio->byte_rate > 0) {
2713 /* Some ASF files have no bitrate props object (often seen with
2714 * ASF files that contain raw audio data). Example files can
2715 * be generated with FFmpeg (tested with v2.8.6), like this:
2717 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2719 * In this case, if audio->byte_rate is nonzero, use that as
2722 guint bitrate = audio->byte_rate * 8;
2725 tags = gst_tag_list_new_empty ();
2727 /* Add bitrate, but only if there is none set already, since
2728 * this is just a fallback in case there is no bitrate tag
2729 * already present */
2730 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2734 gst_buffer_unref (extradata);
2736 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2737 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2738 audio->codec_tag, tags);
2740 ++demux->num_audio_streams;
2742 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2746 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2747 asf_stream_video_format * video, guint16 id,
2748 guint8 ** p_data, guint64 * p_size)
2750 GstTagList *tags = NULL;
2751 GstStructure *caps_s;
2752 GstBuffer *extradata = NULL;
2757 gchar *codec_name = NULL;
2758 guint64 size_left = video->size - 40;
2759 GstBuffer *streamheader = NULL;
2760 guint par_w = 1, par_h = 1;
2762 /* Create the video pad */
2763 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2764 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2767 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2769 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2770 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2772 g_assert (size_left <= *p_size);
2773 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2776 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2778 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2779 caps = gst_riff_create_video_caps (video->tag, NULL,
2780 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2783 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2784 G_TYPE_UINT, video->tag, NULL);
2789 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2790 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2791 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2794 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2798 /* retry with the global metadata */
2799 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2800 demux->global_metadata);
2801 s = demux->global_metadata;
2802 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2803 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2804 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2805 if (ax > 0 && ay > 0) {
2808 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2813 s = gst_caps_get_structure (caps, 0);
2814 gst_structure_remove_field (s, "framerate");
2817 caps_s = gst_caps_get_structure (caps, 0);
2819 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2820 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2821 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2822 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2825 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2826 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2827 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2829 GstBuffer *buf = gst_value_get_buffer (value);
2832 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2833 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2834 /* this looks like a bytestream start */
2835 streamheader = gst_buffer_ref (buf);
2836 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2837 gst_structure_remove_field (caps_s, "codec_data");
2840 gst_buffer_unmap (buf, &mapinfo);
2845 /* For a 3D video, set multiview information into the caps based on
2846 * what was detected during object parsing */
2847 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2848 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2849 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2850 const gchar *mview_mode_str;
2852 switch (demux->asf_3D_mode) {
2853 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2854 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2856 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2857 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2858 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2860 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2861 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2863 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2864 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2865 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2867 case GST_ASF_3D_DUAL_STREAM:{
2868 gboolean is_right_view = FALSE;
2869 /* if Advanced_Mutual_Exclusion object exists, use it
2870 * to figure out which is the left view (lower ID) */
2871 if (demux->mut_ex_streams != NULL) {
2875 length = g_slist_length (demux->mut_ex_streams);
2877 for (i = 0; i < length; i++) {
2880 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2882 GST_DEBUG_OBJECT (demux,
2883 "has Mutual_Exclusion object. stream id in object is %d",
2884 GPOINTER_TO_INT (v_s_id));
2886 if (id > GPOINTER_TO_INT (v_s_id))
2887 is_right_view = TRUE;
2890 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2891 * first video stream encountered has the lower ID */
2892 if (demux->num_video_streams > 0) {
2893 /* This is not the first video stream, assuming right eye view */
2894 is_right_view = TRUE;
2898 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2900 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2907 GST_INFO_OBJECT (demux,
2908 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2911 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2912 if (mview_mode_str != NULL) {
2913 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2914 video->height, par_w, par_h))
2915 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2917 gst_caps_set_simple (caps,
2918 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2919 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2920 GST_FLAG_SET_MASK_EXACT, NULL);
2925 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2926 g_free (codec_name);
2930 gst_buffer_unref (extradata);
2932 GST_INFO ("Adding video stream #%u, id %u, codec %"
2933 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2934 GST_FOURCC_ARGS (video->tag), video->tag);
2936 ++demux->num_video_streams;
2938 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2939 streamheader, tags);
2943 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2945 if (!stream->active) {
2949 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2950 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2951 gst_pad_set_active (stream->pad, TRUE);
2954 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2955 "%03u", stream->id);
2958 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2960 if (gst_event_parse_group_id (event, &demux->group_id))
2961 demux->have_group_id = TRUE;
2963 demux->have_group_id = FALSE;
2964 gst_event_unref (event);
2965 } else if (!demux->have_group_id) {
2966 demux->have_group_id = TRUE;
2967 demux->group_id = gst_util_group_id_next ();
2970 event = gst_event_new_stream_start (stream_id);
2971 if (demux->have_group_id)
2972 gst_event_set_group_id (event, demux->group_id);
2974 gst_pad_push_event (stream->pad, event);
2976 gst_pad_set_caps (stream->pad, stream->caps);
2978 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2979 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2980 stream->active = TRUE;
2985 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2988 AsfCorrectionType correction_type;
2989 AsfStreamType stream_type;
2990 GstClockTime time_offset;
2991 gboolean is_encrypted G_GNUC_UNUSED;
2995 guint stream_specific_size;
2996 guint type_specific_size G_GNUC_UNUSED;
2997 guint unknown G_GNUC_UNUSED;
2998 gboolean inspect_payload = FALSE;
2999 AsfStream *stream = NULL;
3001 /* Get the rest of the header's header */
3002 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
3003 goto not_enough_data;
3005 gst_asf_demux_get_guid (&guid, &data, &size);
3006 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
3008 gst_asf_demux_get_guid (&guid, &data, &size);
3009 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
3011 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
3013 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3014 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3016 flags = gst_asf_demux_get_uint16 (&data, &size);
3017 stream_id = flags & 0x7f;
3018 is_encrypted = ! !(flags & 0x8000);
3019 unknown = gst_asf_demux_get_uint32 (&data, &size);
3021 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3022 stream_id, GST_TIME_ARGS (time_offset));
3024 /* dvr-ms has audio stream declared in stream specific data */
3025 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3026 AsfExtStreamType ext_stream_type;
3027 gst_asf_demux_get_guid (&guid, &data, &size);
3028 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3030 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3031 inspect_payload = TRUE;
3033 gst_asf_demux_get_guid (&guid, &data, &size);
3034 gst_asf_demux_get_uint32 (&data, &size);
3035 gst_asf_demux_get_uint32 (&data, &size);
3036 gst_asf_demux_get_uint32 (&data, &size);
3037 gst_asf_demux_get_guid (&guid, &data, &size);
3038 gst_asf_demux_get_uint32 (&data, &size);
3039 stream_type = ASF_STREAM_AUDIO;
3043 switch (stream_type) {
3044 case ASF_STREAM_AUDIO:{
3045 asf_stream_audio audio_object;
3047 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3048 goto not_enough_data;
3050 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3053 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3056 switch (correction_type) {
3057 case ASF_CORRECTION_ON:{
3058 guint span, packet_size, chunk_size, data_size, silence_data;
3060 GST_INFO ("Using error correction");
3062 if (size < (1 + 2 + 2 + 2 + 1))
3063 goto not_enough_data;
3065 span = gst_asf_demux_get_uint8 (&data, &size);
3066 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3067 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3068 data_size = gst_asf_demux_get_uint16 (&data, &size);
3069 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3071 stream->span = span;
3073 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3074 packet_size, chunk_size, data_size, span, silence_data);
3076 if (stream->span > 1) {
3077 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3078 /* Disable descrambling */
3081 /* FIXME: this else branch was added for
3082 * weird_al_yankovic - the saga begins.asf */
3083 stream->ds_packet_size = packet_size;
3084 stream->ds_chunk_size = chunk_size;
3087 /* Descambling is enabled */
3088 stream->ds_packet_size = packet_size;
3089 stream->ds_chunk_size = chunk_size;
3092 /* Now skip the rest of the silence data */
3094 gst_bytestream_flush (demux->bs, data_size - 1);
3096 /* FIXME: CHECKME. And why -1? */
3097 if (data_size > 1) {
3098 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3099 goto not_enough_data;
3105 case ASF_CORRECTION_OFF:{
3106 GST_INFO ("Error correction off");
3107 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3108 goto not_enough_data;
3112 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3113 ("Audio stream using unknown error correction"));
3120 case ASF_STREAM_VIDEO:{
3121 asf_stream_video_format video_format_object;
3122 asf_stream_video video_object;
3125 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3126 goto not_enough_data;
3128 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3130 GST_INFO ("object is a video stream with %u bytes of "
3131 "additional data", vsize);
3133 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3135 goto not_enough_data;
3138 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3139 stream_id, &data, &size);
3145 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3147 demux->other_streams =
3148 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3153 stream->inspect_payload = inspect_payload;
3158 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3159 /* we'll error out later if we found no streams */
3164 static const gchar *
3165 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3169 const gchar *asf_name;
3170 const gchar *gst_name;
3173 "WM/Genre", GST_TAG_GENRE}, {
3174 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3175 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3176 "WM/Picture", GST_TAG_IMAGE}, {
3177 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3178 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3179 "WM/Year", GST_TAG_DATE_TIME}
3180 /* { "WM/Composer", GST_TAG_COMPOSER } */
3185 if (name_utf8 == NULL) {
3186 GST_WARNING ("Failed to convert name to UTF8, skipping");
3190 out = strlen (name_utf8);
3192 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3193 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3194 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3195 return tags[i].gst_name;
3202 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3204 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3208 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3210 if (taglist == NULL)
3213 if (gst_tag_list_is_empty (taglist)) {
3214 gst_tag_list_unref (taglist);
3218 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3219 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3221 gst_tag_list_unref (demux->taglist);
3222 gst_tag_list_unref (taglist);
3224 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3227 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3228 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3229 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3230 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3233 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3237 const guint8 *img_data = NULL;
3238 guint32 img_data_len = 0;
3239 guint8 pic_type = 0;
3241 gst_byte_reader_init (&r, tag_data, tag_data_len);
3243 /* skip mime type string (we don't trust it and do our own typefinding),
3244 * and also skip the description string, since we don't use it */
3245 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3246 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3247 !gst_byte_reader_skip_string_utf16 (&r) ||
3248 !gst_byte_reader_skip_string_utf16 (&r) ||
3249 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3250 goto not_enough_data;
3254 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3255 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3261 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3262 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3267 /* Extended Content Description Object */
3268 static GstFlowReturn
3269 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3272 /* Other known (and unused) 'text/unicode' metadata available :
3275 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3276 * WMFSDKVersion = 9.00.00.2980
3277 * WMFSDKNeeded = 0.0.0.0000
3278 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3279 * WM/Publisher = 4AD
3281 * WM/ProviderRating = 8
3282 * WM/ProviderStyle = Rock (similar to WM/Genre)
3283 * WM/GenreID (similar to WM/Genre)
3284 * WM/TrackNumber (same as WM/Track but as a string)
3286 * Other known (and unused) 'non-text' metadata available :
3292 * We might want to read WM/TrackNumber and use atoi() if we don't have
3296 GstTagList *taglist;
3297 guint16 blockcount, i;
3298 gboolean content3D = FALSE;
3302 const gchar *interleave_name;
3303 GstASF3DMode interleaving_type;
3304 } stereoscopic_layout_map[] = {
3306 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3307 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3308 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3309 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3310 "DualStream", GST_ASF_3D_DUAL_STREAM}
3312 GST_INFO_OBJECT (demux, "object is an extended content description");
3314 taglist = gst_tag_list_new_empty ();
3316 /* Content Descriptor Count */
3318 goto not_enough_data;
3320 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3322 for (i = 1; i <= blockcount; ++i) {
3323 const gchar *gst_tag_name;
3327 GValue tag_value = { 0, };
3330 gchar *name_utf8 = NULL;
3334 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3335 goto not_enough_data;
3339 goto not_enough_data;
3341 /* Descriptor Value Data Type */
3342 datatype = gst_asf_demux_get_uint16 (&data, &size);
3344 /* Descriptor Value (not really a string, but same thing reading-wise) */
3345 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3347 goto not_enough_data;
3351 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3353 if (name_utf8 != NULL) {
3354 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3356 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3357 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3360 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3363 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3366 /* get rid of tags with empty value */
3367 if (value_utf8 != NULL && *value_utf8 != '\0') {
3368 GST_DEBUG ("string value %s", value_utf8);
3370 value_utf8[out] = '\0';
3372 if (gst_tag_name != NULL) {
3373 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3374 guint year = atoi (value_utf8);
3377 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3378 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3380 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3381 guint id3v1_genre_id;
3382 const gchar *genre_str;
3384 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3385 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3386 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3387 g_free (value_utf8);
3388 value_utf8 = g_strdup (genre_str);
3393 /* convert tag from string to other type if required */
3394 tag_type = gst_tag_get_type (gst_tag_name);
3395 g_value_init (&tag_value, tag_type);
3396 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3397 GValue from_val = { 0, };
3399 g_value_init (&from_val, G_TYPE_STRING);
3400 g_value_set_string (&from_val, value_utf8);
3401 if (!g_value_transform (&from_val, &tag_value)) {
3402 GST_WARNING_OBJECT (demux,
3403 "Could not transform string tag to " "%s tag type %s",
3404 gst_tag_name, g_type_name (tag_type));
3405 g_value_unset (&tag_value);
3407 g_value_unset (&from_val);
3412 GST_DEBUG ("Setting metadata");
3413 g_value_init (&tag_value, G_TYPE_STRING);
3414 g_value_set_string (&tag_value, value_utf8);
3415 /* If we found a stereoscopic marker, look for StereoscopicLayout
3419 if (strncmp ("StereoscopicLayout", name_utf8,
3420 strlen (name_utf8)) == 0) {
3421 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3422 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3424 demux->asf_3D_mode =
3425 stereoscopic_layout_map[i].interleaving_type;
3426 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3430 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3432 demux->asf_3D_mode = GST_ASF_3D_NONE;
3433 GST_INFO_OBJECT (demux, "None 3d type");
3436 } else if (value_utf8 == NULL) {
3437 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3439 GST_DEBUG ("Skipping empty string value for %s",
3440 GST_STR_NULL (gst_tag_name));
3442 g_free (value_utf8);
3445 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3447 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3448 GST_FIXME ("Unhandled byte array tag %s",
3449 GST_STR_NULL (gst_tag_name));
3452 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3458 case ASF_DEMUX_DATA_TYPE_DWORD:{
3464 uint_val = GST_READ_UINT32_LE (value);
3466 /* this is the track number */
3467 g_value_init (&tag_value, G_TYPE_UINT);
3469 /* WM/Track counts from 0 */
3470 if (!strcmp (name_utf8, "WM/Track"))
3473 g_value_set_uint (&tag_value, uint_val);
3477 case ASF_DEMUX_DATA_TYPE_BOOL:{
3483 bool_val = GST_READ_UINT32_LE (value);
3485 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3487 GST_INFO_OBJECT (demux, "This is 3D contents");
3490 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3498 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3503 if (G_IS_VALUE (&tag_value)) {
3505 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3507 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3508 * is supposed to have a 0 base but is often wrongly written to start
3509 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3510 * replace the value added earlier from WM/Track or put it first in
3511 * the list, so that it will get picked up by _get_uint() */
3512 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3513 merge_mode = GST_TAG_MERGE_REPLACE;
3515 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3518 GST_DEBUG ("Setting global metadata %s", name_utf8);
3519 gst_structure_set_value (demux->global_metadata, name_utf8,
3523 g_value_unset (&tag_value);
3532 gst_asf_demux_add_global_tags (demux, taglist);
3539 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3540 gst_tag_list_unref (taglist);
3541 return GST_FLOW_OK; /* not really fatal */
3545 static GstStructure *
3546 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3551 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3553 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3556 s = gst_caps_get_structure (demux->metadata, i);
3557 if (gst_structure_has_name (s, sname))
3561 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3563 /* try lookup again; demux->metadata took ownership of the structure, so we
3564 * can't really make any assumptions about what happened to it, so we can't
3565 * just return it directly after appending it */
3566 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3569 static GstFlowReturn
3570 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3573 guint16 blockcount, i;
3575 GST_INFO_OBJECT (demux, "object is a metadata object");
3577 /* Content Descriptor Count */
3579 goto not_enough_data;
3581 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3583 for (i = 0; i < blockcount; ++i) {
3585 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3586 guint32 data_len, ival;
3589 if (size < (2 + 2 + 2 + 2 + 4))
3590 goto not_enough_data;
3592 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3593 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3594 name_len = gst_asf_demux_get_uint16 (&data, &size);
3595 data_type = gst_asf_demux_get_uint16 (&data, &size);
3596 data_len = gst_asf_demux_get_uint32 (&data, &size);
3598 if (size < name_len + data_len)
3599 goto not_enough_data;
3601 /* convert name to UTF-8 */
3602 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3604 gst_asf_demux_skip_bytes (name_len, &data, &size);
3606 if (name_utf8 == NULL) {
3607 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3608 gst_asf_demux_skip_bytes (data_len, &data, &size);
3612 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3613 gst_asf_demux_skip_bytes (data_len, &data, &size);
3621 goto not_enough_data;
3624 ival = gst_asf_demux_get_uint32 (&data, &size);
3626 /* skip anything else there may be, just in case */
3627 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3629 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3630 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3634 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3640 GST_WARNING ("Unexpected end of data parsing metadata object");
3641 return GST_FLOW_OK; /* not really fatal */
3645 static GstFlowReturn
3646 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3648 GstFlowReturn ret = GST_FLOW_OK;
3649 guint32 i, num_objects;
3650 guint8 unknown G_GNUC_UNUSED;
3652 /* Get the rest of the header's header */
3653 if (size < (4 + 1 + 1))
3654 goto not_enough_data;
3656 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3657 unknown = gst_asf_demux_get_uint8 (&data, &size);
3658 unknown = gst_asf_demux_get_uint8 (&data, &size);
3660 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3661 demux->saw_file_header = FALSE;
3662 /* Loop through the header's objects, processing those */
3663 for (i = 0; i < num_objects; ++i) {
3664 GST_INFO_OBJECT (demux, "reading header part %u", i);
3665 ret = gst_asf_demux_process_object (demux, &data, &size);
3666 if (ret != GST_FLOW_OK) {
3667 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3671 if (!demux->saw_file_header) {
3672 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3673 ("Header does not have mandatory FILE section"));
3674 return GST_FLOW_ERROR;
3681 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3682 ("short read parsing HEADER object"));
3683 return GST_FLOW_ERROR;
3687 static GstFlowReturn
3688 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3690 guint64 creation_time G_GNUC_UNUSED;
3691 guint64 file_size G_GNUC_UNUSED;
3692 guint64 send_time G_GNUC_UNUSED;
3693 guint64 packets_count, play_time, preroll;
3694 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3696 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3697 goto not_enough_data;
3699 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3700 file_size = gst_asf_demux_get_uint64 (&data, &size);
3701 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3702 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3703 play_time = gst_asf_demux_get_uint64 (&data, &size);
3704 send_time = gst_asf_demux_get_uint64 (&data, &size);
3705 preroll = gst_asf_demux_get_uint64 (&data, &size);
3706 flags = gst_asf_demux_get_uint32 (&data, &size);
3707 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3708 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3709 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3711 demux->broadcast = ! !(flags & 0x01);
3712 demux->seekable = ! !(flags & 0x02);
3714 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3715 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3716 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3718 if (demux->broadcast) {
3719 /* these fields are invalid if the broadcast flag is set */
3724 if (min_pktsize != max_pktsize)
3725 goto non_fixed_packet_size;
3727 demux->packet_size = max_pktsize;
3729 /* FIXME: do we need send_time as well? what is it? */
3730 if ((play_time * 100) >= (preroll * GST_MSECOND))
3731 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3733 demux->play_time = 0;
3735 demux->preroll = preroll * GST_MSECOND;
3737 /* initial latency */
3738 demux->latency = demux->preroll;
3740 if (demux->play_time == 0)
3741 demux->seekable = FALSE;
3743 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3744 GST_TIME_ARGS (demux->play_time));
3745 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3746 GST_TIME_ARGS (demux->preroll));
3748 if (demux->play_time > 0) {
3749 demux->segment.duration = demux->play_time;
3752 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3754 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3756 demux->saw_file_header = TRUE;
3761 non_fixed_packet_size:
3763 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3764 ("packet size must be fixed"));
3765 return GST_FLOW_ERROR;
3769 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3770 ("short read parsing FILE object"));
3771 return GST_FLOW_ERROR;
3775 /* Content Description Object */
3776 static GstFlowReturn
3777 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3781 const gchar *gst_tag;
3786 GST_TAG_TITLE, 0, NULL}, {
3787 GST_TAG_ARTIST, 0, NULL}, {
3788 GST_TAG_COPYRIGHT, 0, NULL}, {
3789 GST_TAG_DESCRIPTION, 0, NULL}, {
3790 GST_TAG_COMMENT, 0, NULL}
3792 GstTagList *taglist;
3793 GValue value = { 0 };
3797 GST_INFO_OBJECT (demux, "object is a comment");
3799 if (size < (2 + 2 + 2 + 2 + 2))
3800 goto not_enough_data;
3802 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3803 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3804 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3805 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3806 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3808 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3809 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3810 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3812 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3813 if (size < tags[i].val_length)
3814 goto not_enough_data;
3816 /* might be just '/0', '/0'... */
3817 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3818 /* convert to UTF-8 */
3819 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3820 "UTF-8", "UTF-16LE", &in, &out, NULL);
3822 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3825 /* parse metadata into taglist */
3826 taglist = gst_tag_list_new_empty ();
3827 g_value_init (&value, G_TYPE_STRING);
3828 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3829 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3830 g_value_set_string (&value, tags[i].val_utf8);
3831 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3832 tags[i].gst_tag, &value, NULL);
3835 g_value_unset (&value);
3837 gst_asf_demux_add_global_tags (demux, taglist);
3839 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3840 g_free (tags[i].val_utf8);
3846 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3847 "comment tag section %d, skipping comment object", i);
3848 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3849 g_free (tags[i].val_utf8);
3850 return GST_FLOW_OK; /* not really fatal */
3854 static GstFlowReturn
3855 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3858 guint16 num_streams, i;
3862 goto not_enough_data;
3864 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3866 GST_INFO ("object is a bitrate properties object with %u streams",
3869 if (size < (num_streams * (2 + 4)))
3870 goto not_enough_data;
3872 for (i = 0; i < num_streams; ++i) {
3876 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3877 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3879 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3880 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3881 stream = gst_asf_demux_get_stream (demux, stream_id);
3883 if (stream->pending_tags == NULL)
3884 stream->pending_tags = gst_tag_list_new_empty ();
3885 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3886 GST_TAG_BITRATE, bitrate, NULL);
3888 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3891 GST_WARNING ("stream id %u is too large", stream_id);
3899 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3900 return GST_FLOW_OK; /* not really fatal */
3904 static GstFlowReturn
3905 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3908 GstFlowReturn ret = GST_FLOW_OK;
3911 /* Get the rest of the header's header */
3912 if (size < (16 + 2 + 4))
3913 goto not_enough_data;
3915 /* skip GUID and two other bytes */
3916 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3917 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3919 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3921 /* FIXME: does data_size include the rest of the header that we have read? */
3922 if (hdr_size > size)
3923 goto not_enough_data;
3925 while (hdr_size > 0) {
3926 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3927 if (ret != GST_FLOW_OK)
3935 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3936 ("short read parsing extended header object"));
3937 return GST_FLOW_ERROR;
3941 static GstFlowReturn
3942 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3948 goto not_enough_data;
3950 if (demux->languages) {
3951 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3952 g_strfreev (demux->languages);
3953 demux->languages = NULL;
3954 demux->num_languages = 0;
3957 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3958 GST_LOG ("%u languages:", demux->num_languages);
3960 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3961 for (i = 0; i < demux->num_languages; ++i) {
3962 guint8 len, *lang_data = NULL;
3965 goto not_enough_data;
3966 len = gst_asf_demux_get_uint8 (&data, &size);
3967 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3970 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3973 /* truncate "en-us" etc. to just "en" */
3974 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3977 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3978 demux->languages[i] = utf8;
3981 goto not_enough_data;
3989 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3990 g_free (demux->languages);
3991 demux->languages = NULL;
3992 demux->num_languages = 0;
3993 return GST_FLOW_OK; /* not fatal */
3997 static GstFlowReturn
3998 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
4001 GstClockTime interval;
4004 if (size < (16 + 8 + 4 + 4))
4005 goto not_enough_data;
4008 gst_asf_demux_skip_bytes (16, &data, &size);
4009 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
4010 gst_asf_demux_skip_bytes (4, &data, &size);
4011 count = gst_asf_demux_get_uint32 (&data, &size);
4013 demux->sidx_interval = interval;
4014 demux->sidx_num_entries = count;
4015 g_free (demux->sidx_entries);
4016 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
4018 for (i = 0; i < count; ++i) {
4019 if (G_UNLIKELY (size < 6)) {
4020 /* adjust for broken files, to avoid having entries at the end
4021 * of the parsed index that point to time=0. Resulting in seeking to
4022 * the end of the file leading back to the beginning */
4023 demux->sidx_num_entries -= (count - i);
4026 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4027 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4028 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4029 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4030 demux->sidx_entries[i].count);
4033 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4040 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4041 return GST_FLOW_OK; /* not fatal */
4045 static GstFlowReturn
4046 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4047 guint8 * data, guint64 size)
4052 if (size < 16 + 2 + (2 * 2))
4053 goto not_enough_data;
4055 gst_asf_demux_get_guid (&guid, &data, &size);
4056 num = gst_asf_demux_get_uint16 (&data, &size);
4059 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4063 if (size < (num * sizeof (guint16)))
4064 goto not_enough_data;
4066 /* read mutually exclusive stream numbers */
4067 for (i = 0; i < num; ++i) {
4069 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4070 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4072 demux->mut_ex_streams =
4073 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4082 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4083 return GST_FLOW_OK; /* not absolutely fatal */
4088 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4090 return g_slist_find (demux->other_streams,
4091 GINT_TO_POINTER (stream_num)) == NULL;
4094 static GstFlowReturn
4095 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4098 AsfStreamExtProps esp;
4099 AsfStream *stream = NULL;
4100 AsfObject stream_obj;
4101 guint16 stream_name_count;
4102 guint16 num_payload_ext;
4104 guint8 *stream_obj_data = NULL;
4107 guint i, stream_num;
4110 obj_size = (guint) size;
4112 esp.payload_extensions = NULL;
4115 goto not_enough_data;
4118 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4119 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4120 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4121 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4122 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4123 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4124 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4125 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4126 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4127 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4128 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4129 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4130 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4131 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4132 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4134 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4135 GST_TIME_ARGS (esp.start_time));
4136 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4137 GST_TIME_ARGS (esp.end_time));
4138 GST_INFO ("flags = %08x", esp.flags);
4139 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4140 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4141 GST_INFO ("stream number = %u", stream_num);
4142 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4143 (esp.lang_idx < demux->num_languages) ?
4144 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4145 GST_INFO ("stream name count = %u", stream_name_count);
4147 /* read stream names */
4148 for (i = 0; i < stream_name_count; ++i) {
4149 guint16 stream_lang_idx G_GNUC_UNUSED;
4150 gchar *stream_name = NULL;
4153 goto not_enough_data;
4154 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4155 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4156 goto not_enough_data;
4157 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4158 g_free (stream_name); /* TODO: store names in struct */
4161 /* read payload extension systems stuff */
4162 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4164 if (num_payload_ext > 0)
4165 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4167 for (i = 0; i < num_payload_ext; ++i) {
4168 AsfPayloadExtension ext;
4170 guint32 sys_info_len;
4172 if (size < 16 + 2 + 4)
4173 goto not_enough_data;
4175 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4176 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4177 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4179 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4180 GST_LOG ("payload systems info len = %u", sys_info_len);
4181 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4182 goto not_enough_data;
4184 esp.payload_extensions[i] = ext;
4187 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4189 /* there might be an optional STREAM_INFO object here now; if not, we
4190 * should have parsed the corresponding stream info object already (since
4191 * we are parsing the extended stream properties objects delayed) */
4193 stream = gst_asf_demux_get_stream (demux, stream_num);
4197 if (size < ASF_OBJECT_HEADER_SIZE)
4198 goto not_enough_data;
4200 /* get size of the stream object */
4201 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4202 goto corrupted_stream;
4204 if (stream_obj.id != ASF_OBJ_STREAM)
4205 goto expected_stream_object;
4207 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4208 stream_obj.size > (10 * 1024 * 1024))
4209 goto not_enough_data;
4211 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4213 /* process this stream object later after all the other 'normal' ones
4214 * have been processed (since the others are more important/non-hidden) */
4215 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4216 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4217 goto not_enough_data;
4219 /* parse stream object */
4220 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4221 g_free (stream_obj_data);
4226 stream->ext_props = esp;
4228 /* try to set the framerate */
4229 if (stream->is_video && stream->caps) {
4230 GValue framerate = { 0 };
4234 g_value_init (&framerate, GST_TYPE_FRACTION);
4236 num = GST_SECOND / 100;
4237 denom = esp.avg_time_per_frame;
4239 /* avoid division by 0, assume 25/1 framerate */
4240 denom = GST_SECOND / 2500;
4243 gst_value_set_fraction (&framerate, num, denom);
4245 stream->caps = gst_caps_make_writable (stream->caps);
4246 s = gst_caps_get_structure (stream->caps, 0);
4247 gst_structure_set_value (s, "framerate", &framerate);
4248 g_value_unset (&framerate);
4249 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4250 num, denom, ((gdouble) num) / denom);
4253 /* add language info now if we have it */
4254 if (stream->ext_props.lang_idx < demux->num_languages) {
4255 if (stream->pending_tags == NULL)
4256 stream->pending_tags = gst_tag_list_new_empty ();
4257 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4258 demux->languages[stream->ext_props.lang_idx]);
4259 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4260 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4263 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4264 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4268 g_free (esp.payload_extensions);
4275 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4276 g_free (esp.payload_extensions);
4277 return GST_FLOW_OK; /* not absolutely fatal */
4279 expected_stream_object:
4281 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4282 "object: expected embedded stream object, but got %s object instead!",
4283 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4284 g_free (esp.payload_extensions);
4285 return GST_FLOW_OK; /* not absolutely fatal */
4289 GST_WARNING_OBJECT (demux, "Corrupted stream");
4290 g_free (esp.payload_extensions);
4291 return GST_FLOW_ERROR;
4295 static const gchar *
4296 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4300 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4301 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4302 nick += strlen ("ASF_OBJ_");
4304 if (demux->objpath == NULL) {
4305 demux->objpath = g_strdup (nick);
4309 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4310 g_free (demux->objpath);
4311 demux->objpath = newpath;
4314 return (const gchar *) demux->objpath;
4318 gst_asf_demux_pop_obj (GstASFDemux * demux)
4322 if ((s = g_strrstr (demux->objpath, "/"))) {
4325 g_free (demux->objpath);
4326 demux->objpath = NULL;
4331 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4336 /* Parse the queued extended stream property objects and add the info
4337 * to the existing streams or add the new embedded streams, but without
4338 * activating them yet */
4339 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4340 g_slist_length (demux->ext_stream_props));
4342 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4343 GstBuffer *buf = GST_BUFFER (l->data);
4346 gst_buffer_map (buf, &map, GST_MAP_READ);
4348 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4349 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4350 gst_buffer_unmap (buf, &map);
4351 gst_buffer_unref (buf);
4353 g_slist_free (demux->ext_stream_props);
4354 demux->ext_stream_props = NULL;
4359 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4363 for (i = 0; i < demux->num_streams; ++i) {
4368 stream = &demux->stream[i];
4370 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4372 if (stream->active) {
4373 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4378 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4381 /* check for each mutual exclusion whether it affects this stream */
4382 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4383 if (*mes == stream->id) {
4384 /* if yes, check if we've already added streams that are mutually
4385 * exclusive with the stream we're about to add */
4386 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4387 for (j = 0; j < demux->num_streams; ++j) {
4388 /* if the broadcast flag is set, assume the hidden streams aren't
4389 * actually streamed and hide them (or playbin won't work right),
4390 * otherwise assume their data is available */
4391 if (demux->stream[j].id == *mes && demux->broadcast) {
4393 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4394 "mutually exclusive with already existing stream ID %d, "
4395 "hiding stream", stream->id, demux->stream[j].id);
4407 /* FIXME: we should do stream activation based on preroll data in
4408 * streaming mode too */
4409 if (demux->streaming && !is_hidden)
4410 gst_asf_demux_activate_stream (demux, stream);
4415 static GstFlowReturn
4416 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4419 GstFlowReturn ret = GST_FLOW_OK;
4421 guint64 obj_data_size;
4423 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4424 return ASF_FLOW_NEED_MORE_DATA;
4426 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4428 return GST_FLOW_ERROR;
4429 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4431 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4433 if (*p_size < obj_data_size)
4434 return ASF_FLOW_NEED_MORE_DATA;
4436 gst_asf_demux_push_obj (demux, obj.id);
4438 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4441 case ASF_OBJ_STREAM:
4442 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4446 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4448 case ASF_OBJ_HEADER:
4449 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4451 case ASF_OBJ_COMMENT:
4452 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4455 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4457 case ASF_OBJ_BITRATE_PROPS:
4459 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4462 case ASF_OBJ_EXT_CONTENT_DESC:
4464 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4467 case ASF_OBJ_METADATA_OBJECT:
4468 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4470 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4473 /* process these later, we might not have parsed the corresponding
4474 * stream object yet */
4475 GST_LOG ("%s: queued for later parsing", demux->objpath);
4476 buf = gst_buffer_new_and_alloc (obj_data_size);
4477 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4478 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4482 case ASF_OBJ_LANGUAGE_LIST:
4483 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4485 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4486 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4489 case ASF_OBJ_SIMPLE_INDEX:
4490 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4492 case ASF_OBJ_CONTENT_ENCRYPTION:
4493 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4494 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4495 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4496 goto error_encrypted;
4497 case ASF_OBJ_CONCEAL_NONE:
4499 case ASF_OBJ_UNDEFINED:
4500 case ASF_OBJ_CODEC_COMMENT:
4502 case ASF_OBJ_PADDING:
4503 case ASF_OBJ_BITRATE_MUTEX:
4504 case ASF_OBJ_COMPATIBILITY:
4505 case ASF_OBJ_INDEX_PLACEHOLDER:
4506 case ASF_OBJ_INDEX_PARAMETERS:
4507 case ASF_OBJ_STREAM_PRIORITIZATION:
4508 case ASF_OBJ_SCRIPT_COMMAND:
4509 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4511 /* Unknown/unhandled object, skip it and hope for the best */
4512 GST_INFO ("%s: skipping object", demux->objpath);
4517 /* this can't fail, we checked the number of bytes available before */
4518 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4520 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4522 gst_asf_demux_pop_obj (demux);
4529 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4530 return GST_FLOW_ERROR;
4535 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4536 GstBuffer ** p_buffer)
4538 GstBuffer *descrambled_buffer;
4539 GstBuffer *scrambled_buffer;
4540 GstBuffer *sub_buffer;
4547 /* descrambled_buffer is initialised in the first iteration */
4548 descrambled_buffer = NULL;
4549 scrambled_buffer = *p_buffer;
4551 if (gst_buffer_get_size (scrambled_buffer) <
4552 stream->ds_packet_size * stream->span)
4555 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4556 offset += stream->ds_chunk_size) {
4557 off = offset / stream->ds_chunk_size;
4558 row = off / stream->span;
4559 col = off % stream->span;
4560 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4561 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4562 col, off, stream->ds_chunk_size);
4563 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4564 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4565 stream->span, stream->ds_packet_size);
4566 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4567 gst_buffer_get_size (scrambled_buffer));
4569 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4570 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4572 descrambled_buffer = sub_buffer;
4574 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4578 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4579 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4580 GST_BUFFER_DURATION (descrambled_buffer) =
4581 GST_BUFFER_DURATION (scrambled_buffer);
4582 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4583 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4584 GST_BUFFER_OFFSET_END (scrambled_buffer);
4586 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4588 gst_buffer_unref (scrambled_buffer);
4589 *p_buffer = descrambled_buffer;
4593 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4595 GstASFDemux *demux = GST_ASF_DEMUX (element);
4598 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4600 for (i = 0; i < demux->num_streams; ++i) {
4601 gst_event_ref (event);
4602 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4603 GST_OBJECT_CAST (element), event)) {
4604 gst_event_unref (event);
4609 gst_event_unref (event);
4613 /* takes ownership of the passed event */
4615 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4617 gboolean ret = TRUE;
4620 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4621 GST_EVENT_TYPE_NAME (event));
4623 for (i = 0; i < demux->num_streams; ++i) {
4624 gst_event_ref (event);
4625 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4627 gst_event_unref (event);
4632 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4636 gboolean res = FALSE;
4638 demux = GST_ASF_DEMUX (parent);
4640 GST_DEBUG ("handling %s query",
4641 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4643 switch (GST_QUERY_TYPE (query)) {
4644 case GST_QUERY_DURATION:
4648 gst_query_parse_duration (query, &format, NULL);
4650 if (format != GST_FORMAT_TIME) {
4651 GST_LOG ("only support duration queries in TIME format");
4655 res = gst_pad_query_default (pad, parent, query);
4657 GST_OBJECT_LOCK (demux);
4659 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4660 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4661 GST_TIME_ARGS (demux->segment.duration));
4663 gst_query_set_duration (query, GST_FORMAT_TIME,
4664 demux->segment.duration);
4668 GST_LOG ("duration not known yet");
4671 GST_OBJECT_UNLOCK (demux);
4676 case GST_QUERY_POSITION:{
4679 gst_query_parse_position (query, &format, NULL);
4681 if (format != GST_FORMAT_TIME) {
4682 GST_LOG ("only support position queries in TIME format");
4686 GST_OBJECT_LOCK (demux);
4688 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4689 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4690 GST_TIME_ARGS (demux->segment.position));
4692 gst_query_set_position (query, GST_FORMAT_TIME,
4693 demux->segment.position);
4697 GST_LOG ("position not known yet");
4700 GST_OBJECT_UNLOCK (demux);
4704 case GST_QUERY_SEEKING:{
4707 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4708 if (format == GST_FORMAT_TIME) {
4711 GST_OBJECT_LOCK (demux);
4712 duration = demux->segment.duration;
4713 GST_OBJECT_UNLOCK (demux);
4715 if (!demux->streaming || !demux->seekable) {
4716 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4723 /* try upstream first in TIME */
4724 res = gst_pad_query_default (pad, parent, query);
4726 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4727 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4728 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4729 /* if no luck, maybe in BYTES */
4730 if (!seekable || fmt != GST_FORMAT_TIME) {
4733 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4734 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4735 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4736 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4737 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4738 if (fmt != GST_FORMAT_BYTES)
4741 gst_query_unref (q);
4742 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4748 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4752 case GST_QUERY_LATENCY:
4755 GstClockTime min, max;
4757 /* preroll delay does not matter in non-live pipeline,
4758 * but we might end up in a live (rtsp) one ... */
4761 res = gst_pad_query_default (pad, parent, query);
4765 gst_query_parse_latency (query, &live, &min, &max);
4767 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4768 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4769 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4771 GST_OBJECT_LOCK (demux);
4772 min += demux->latency;
4774 max += demux->latency;
4775 GST_OBJECT_UNLOCK (demux);
4777 gst_query_set_latency (query, live, min, max);
4780 case GST_QUERY_SEGMENT:
4785 format = demux->segment.format;
4788 gst_segment_to_stream_time (&demux->segment, format,
4789 demux->segment.start);
4790 if ((stop = demux->segment.stop) == -1)
4791 stop = demux->segment.duration;
4793 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4795 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4800 res = gst_pad_query_default (pad, parent, query);
4807 static GstStateChangeReturn
4808 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4810 GstASFDemux *demux = GST_ASF_DEMUX (element);
4811 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4813 switch (transition) {
4814 case GST_STATE_CHANGE_NULL_TO_READY:{
4815 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4816 demux->need_newsegment = TRUE;
4817 demux->segment_running = FALSE;
4818 demux->keyunit_sync = FALSE;
4819 demux->accurate = FALSE;
4820 demux->adapter = gst_adapter_new ();
4821 demux->metadata = gst_caps_new_empty ();
4822 demux->global_metadata = gst_structure_new_empty ("metadata");
4823 demux->data_size = 0;
4824 demux->data_offset = 0;
4825 demux->index_offset = 0;
4826 demux->base_offset = 0;
4827 demux->flowcombiner = gst_flow_combiner_new ();
4835 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4836 if (ret == GST_STATE_CHANGE_FAILURE)
4839 switch (transition) {
4840 case GST_STATE_CHANGE_PAUSED_TO_READY:
4841 gst_asf_demux_reset (demux, FALSE);
4844 case GST_STATE_CHANGE_READY_TO_NULL:
4845 gst_asf_demux_reset (demux, FALSE);
4846 gst_flow_combiner_free (demux->flowcombiner);
4847 demux->flowcombiner = NULL;