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 if (G_LIKELY (flush)) {
736 /* we now can stop flushing, since we have the stream lock now */
737 fevent = gst_event_new_flush_stop (TRUE);
738 gst_event_set_seqnum (fevent, seqnum);
739 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
740 gst_asf_demux_send_event_unlocked (demux, fevent);
743 /* operating on copy of segment until we know the seek worked */
744 segment = demux->segment;
746 if (G_UNLIKELY (demux->segment_running && !flush)) {
747 GstSegment newsegment;
750 /* create the segment event to close the current segment */
751 gst_segment_copy_into (&segment, &newsegment);
752 newseg = gst_event_new_segment (&newsegment);
753 gst_event_set_seqnum (newseg, seqnum);
755 gst_asf_demux_send_event_unlocked (demux, newseg);
758 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
759 cur, stop_type, stop, &only_need_update);
761 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
762 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
764 if (cur_type != GST_SEEK_TYPE_SET)
765 seek_time = segment.start;
769 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
770 * real start of data and segment_start to indexed time for key unit seek*/
771 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
772 &idx_time, &speed_count, next, &eos))) {
776 demux->packet = demux->num_packets;
780 /* First try to query our source to see if it can convert for us. This is
781 the case when our source is an mms stream, notice that in this case
782 gstmms will do a time based seek to get the byte offset, this is not a
783 problem as the seek to this offset needs to happen anway. */
784 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
785 GST_FORMAT_BYTES, &offset)) {
786 packet = (offset - demux->data_offset) / demux->packet_size;
787 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
788 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
789 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
790 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
791 demux->packet_size, packet);
793 /* FIXME: For streams containing video, seek to an earlier position in
794 * the hope of hitting a keyframe and let the sinks throw away the stuff
795 * before the segment start. For audio-only this is unnecessary as every
797 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
798 && demux->num_video_streams > 0) {
799 seek_time -= 5 * GST_SECOND;
804 packet = (guint) gst_util_uint64_scale (demux->num_packets,
805 seek_time, demux->play_time);
807 if (packet > demux->num_packets)
808 packet = demux->num_packets;
811 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
812 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
813 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
814 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
815 segment.start = idx_time;
816 segment.position = idx_time;
817 segment.time = idx_time;
821 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
823 GST_OBJECT_LOCK (demux);
824 demux->segment = segment;
825 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
826 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
827 stop, demux->play_time);
829 demux->packet = packet;
832 demux->need_newsegment = TRUE;
833 demux->segment_seqnum = seqnum;
834 demux->speed_packets =
835 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
836 gst_asf_demux_reset_stream_state_after_discont (demux);
837 GST_OBJECT_UNLOCK (demux);
840 /* restart our task since it might have been stopped when we did the flush */
841 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
844 /* streaming can continue now */
845 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
851 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
857 demux = GST_ASF_DEMUX (parent);
859 switch (GST_EVENT_TYPE (event)) {
861 GST_LOG_OBJECT (pad, "seek event");
862 ret = gst_asf_demux_handle_seek_event (demux, event);
863 gst_event_unref (event);
866 case GST_EVENT_NAVIGATION:
867 /* just drop these two silently */
868 gst_event_unref (event);
872 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
873 ret = gst_pad_event_default (pad, parent, event);
880 static inline guint32
881 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
885 ret = gst_asf_identify_guid (guids, guid);
887 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
888 gst_asf_get_guid_nick (guids, ret),
889 guid->v1, guid->v2, guid->v3, guid->v4);
901 /* Peek for an object.
903 * Returns FALSE is the object is corrupted (such as the reported
904 * object size being greater than 2**32bits.
907 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
908 guint data_len, AsfObject * object, gboolean expect)
912 /* Callers should have made sure that data_len is big enough */
913 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
915 if (data_len < ASF_OBJECT_HEADER_SIZE)
918 guid.v1 = GST_READ_UINT32_LE (data + 0);
919 guid.v2 = GST_READ_UINT32_LE (data + 4);
920 guid.v3 = GST_READ_UINT32_LE (data + 8);
921 guid.v4 = GST_READ_UINT32_LE (data + 12);
923 /* FIXME: make asf_demux_identify_object_guid() */
924 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
925 if (object->id == ASF_OBJ_UNDEFINED && expect) {
926 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
927 guid.v1, guid.v2, guid.v3, guid.v4);
930 object->size = GST_READ_UINT64_LE (data + 16);
931 if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
932 GST_WARNING_OBJECT (demux,
933 "ASF Object size corrupted (greater than 32bit)");
942 gst_asf_demux_release_old_pads (GstASFDemux * demux)
944 GST_DEBUG_OBJECT (demux, "Releasing old pads");
946 while (demux->old_num_streams > 0) {
947 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
948 gst_event_new_eos ());
949 gst_asf_demux_free_stream (demux,
950 &demux->old_stream[demux->old_num_streams - 1]);
951 --demux->old_num_streams;
953 memset (demux->old_stream, 0, sizeof (demux->old_stream));
954 demux->old_num_streams = 0;
958 gst_asf_demux_chain_headers (GstASFDemux * demux)
961 guint8 *header_data, *data = NULL;
962 const guint8 *cdata = NULL;
964 GstFlowReturn flow = GST_FLOW_OK;
966 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
970 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
972 if (obj.id != ASF_OBJ_HEADER)
975 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
977 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
978 if (gst_adapter_available (demux->adapter) < obj.size + 50)
981 data = gst_adapter_take (demux->adapter, obj.size + 50);
984 header_size = obj.size;
985 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
986 if (flow != GST_FLOW_OK)
989 /* calculate where the packet data starts */
990 demux->data_offset = obj.size + 50;
992 /* now parse the beginning of the ASF_OBJ_DATA object */
993 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
996 if (demux->num_streams == 0)
1005 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1012 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1013 ("This doesn't seem to be an ASF file"));
1015 return GST_FLOW_ERROR;
1020 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1021 ("header parsing failed, or no streams found, flow = %s",
1022 gst_flow_get_name (flow)));
1024 return GST_FLOW_ERROR;
1029 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1030 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1035 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1038 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1040 if (G_LIKELY (p_flow))
1043 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1044 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1045 "+%u", gst_flow_get_name (flow), offset, size);
1050 g_assert (*p_buf != NULL);
1052 buffer_size = gst_buffer_get_size (*p_buf);
1053 if (G_UNLIKELY (buffer_size < size)) {
1054 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1055 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1056 gst_buffer_unref (*p_buf);
1057 if (G_LIKELY (p_flow))
1058 *p_flow = GST_FLOW_EOS;
1066 static GstFlowReturn
1067 gst_asf_demux_pull_indices (GstASFDemux * demux)
1069 GstBuffer *buf = NULL;
1072 GstFlowReturn ret = GST_FLOW_OK;
1074 offset = demux->index_offset;
1076 if (G_UNLIKELY (offset == 0)) {
1077 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1082 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1088 gst_buffer_map (buf, &map, GST_MAP_READ);
1089 g_assert (map.size >= 16 + 8);
1090 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1091 GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
1092 GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
1094 gst_buffer_unmap (buf, &map);
1095 gst_buffer_replace (&buf, NULL);
1096 /* Non-fatal, return */
1099 gst_buffer_unmap (buf, &map);
1100 gst_buffer_replace (&buf, NULL);
1102 /* check for sanity */
1103 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1104 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1108 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1112 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1113 ", size %u", offset, (guint) obj.size);
1115 offset += obj.size; /* increase before _process_object changes it */
1117 gst_buffer_map (buf, &map, GST_MAP_READ);
1118 g_assert (map.size >= obj.size);
1119 bufdata = (guint8 *) map.data;
1120 obj_size = obj.size;
1121 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1122 gst_buffer_unmap (buf, &map);
1123 gst_buffer_replace (&buf, NULL);
1125 if (ret == ASF_FLOW_NEED_MORE_DATA) {
1126 /* Since indices are at the end of the file, if we need more data,
1127 * we consider it as a non-fatal corrupted index */
1132 if (G_UNLIKELY (ret != GST_FLOW_OK))
1138 GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
1139 gst_flow_get_name (ret));
1144 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1148 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1149 GST_WARNING_OBJECT (demux, "Corrupted data");
1152 if (obj.id != ASF_OBJ_DATA) {
1153 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1157 demux->state = GST_ASF_DEMUX_STATE_DATA;
1159 if (!demux->broadcast && obj.size > 50) {
1160 demux->data_size = obj.size - 50;
1161 /* CHECKME: for at least one file this is off by +158 bytes?! */
1162 demux->index_offset = demux->data_offset + demux->data_size;
1164 demux->data_size = 0;
1165 demux->index_offset = 0;
1170 if (!demux->broadcast) {
1171 /* skip object header (24 bytes) and file GUID (16 bytes) */
1172 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1174 demux->num_packets = 0;
1177 if (demux->num_packets == 0)
1178 demux->seekable = FALSE;
1180 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1181 if (demux->data_size == 0 && demux->num_packets > 0) {
1182 demux->data_size = demux->num_packets * demux->packet_size;
1183 demux->index_offset = demux->data_offset + demux->data_size;
1186 /* process pending stream objects and create pads for those */
1187 gst_asf_demux_process_queued_extended_stream_objects (demux);
1189 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1190 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1191 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1192 demux->data_offset, demux->data_size, demux->index_offset);
1198 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1200 GstFlowReturn flow = GST_FLOW_OK;
1202 GstBuffer *buf = NULL;
1207 GST_LOG_OBJECT (demux, "reading headers");
1209 /* pull HEADER object header, so we know its size */
1210 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1213 gst_buffer_map (buf, &map, GST_MAP_READ);
1214 g_assert (map.size >= 16 + 8);
1215 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1216 gst_buffer_unmap (buf, &map);
1217 gst_buffer_replace (&buf, NULL);
1218 flow = GST_FLOW_ERROR;
1221 gst_buffer_unmap (buf, &map);
1222 gst_buffer_replace (&buf, NULL);
1224 if (obj.id != ASF_OBJ_HEADER)
1227 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1229 /* pull HEADER object */
1230 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1234 size = obj.size; /* don't want obj.size changed */
1235 gst_buffer_map (buf, &map, GST_MAP_READ);
1236 g_assert (map.size >= size);
1237 bufdata = (guint8 *) map.data;
1238 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1239 gst_buffer_unmap (buf, &map);
1240 gst_buffer_replace (&buf, NULL);
1242 if (flow != GST_FLOW_OK) {
1243 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1247 /* calculate where the packet data starts */
1248 demux->data_offset = demux->base_offset + obj.size + 50;
1250 /* now pull beginning of DATA object before packet data */
1251 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1255 gst_buffer_map (buf, &map, GST_MAP_READ);
1256 g_assert (map.size >= size);
1257 bufdata = (guint8 *) map.data;
1258 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1261 if (demux->num_streams == 0)
1264 gst_buffer_unmap (buf, &map);
1265 gst_buffer_replace (&buf, NULL);
1273 gst_buffer_unmap (buf, &map);
1274 gst_buffer_replace (&buf, NULL);
1276 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1277 ("This doesn't seem to be an ASF file"));
1278 *pflow = GST_FLOW_ERROR;
1283 flow = GST_FLOW_ERROR;
1284 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1285 ("header parsing failed, or no streams found, flow = %s",
1286 gst_flow_get_name (flow)));
1291 gst_buffer_unmap (buf, &map);
1292 gst_buffer_replace (&buf, NULL);
1293 if (flow == ASF_FLOW_NEED_MORE_DATA)
1294 flow = GST_FLOW_ERROR;
1301 all_streams_prerolled (GstASFDemux * demux)
1303 GstClockTime preroll_time;
1304 guint i, num_no_data = 0;
1305 AsfStreamType prerolled_types = 0, all_types = 0;
1307 /* Allow at least 500ms of preroll_time */
1308 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1310 /* returns TRUE as long as there isn't a stream which (a) has data queued
1311 * and (b) the timestamp of last piece of data queued is < demux->preroll
1312 * AND there is at least one other stream with data queued */
1313 for (i = 0; i < demux->num_streams; ++i) {
1314 AsfPayload *last_payload = NULL;
1318 stream = &demux->stream[i];
1320 all_types |= stream->type;
1322 if (G_UNLIKELY (stream->payloads->len == 0)) {
1324 GST_LOG_OBJECT (stream->pad, "no data queued");
1328 prerolled_types |= stream->type;
1330 /* find last payload with timestamp */
1331 for (last_idx = stream->payloads->len - 1;
1332 last_idx >= 0 && (last_payload == NULL
1333 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1334 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1337 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1338 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1339 GST_TIME_ARGS (preroll_time));
1340 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1341 || last_payload->ts <= preroll_time)) {
1342 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1347 GST_LOG_OBJECT (demux, "all_types:%d prerolled_types:%d",
1348 all_types, prerolled_types);
1350 /* If streams of each present type have prerolled, we are good to go */
1351 if (all_types != 0 && prerolled_types == all_types)
1354 if (G_UNLIKELY (num_no_data > 0))
1362 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1367 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1370 /* check for each mutual exclusion group whether it affects this stream */
1371 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1372 if (*mes == stream->id) {
1373 /* we are in this group; let's check if we've already activated streams
1374 * that are in the same group (and hence mutually exclusive to this
1376 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1379 for (i = 0; i < demux->num_streams; ++i) {
1380 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1381 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1382 "to already active stream with ID %d", stream->id,
1383 demux->stream[i].id);
1388 /* we can only be in this group once, let's break out and move on to
1389 * the next mutual exclusion group */
1400 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1402 /* remember the first queued timestamp for the segment */
1403 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1404 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1405 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1406 GST_TIME_ARGS (demux->first_ts));
1407 demux->segment_ts = payload_ts;
1408 /* always note, but only determines segment when streaming */
1409 if (demux->streaming)
1410 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1411 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1412 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1417 gst_asf_demux_get_first_ts (GstASFDemux * demux)
1419 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1420 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1423 /* go trhough each stream, find smallest timestamp */
1424 for (i = 0; i < demux->num_streams; ++i) {
1427 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1428 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1429 stream = &demux->stream[i];
1431 for (j = 0; j < stream->payloads->len; ++j) {
1432 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1433 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1434 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1435 || stream_min_ts > payload->ts)) {
1436 stream_min_ts = payload->ts;
1438 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1439 payload->ts > stream_min_ts &&
1440 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1441 || stream_min_ts2 > payload->ts)) {
1442 stream_min_ts2 = payload->ts;
1446 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1447 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1448 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1449 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1450 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1452 GST_DEBUG_OBJECT (demux,
1453 "stream #%u stream_min_ts %" GST_TIME_FORMAT " stream_min_ts2 %"
1454 GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (stream_min_ts),
1455 GST_TIME_ARGS (stream_min_ts2));
1457 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1458 stream_min_ts = stream_min_ts2;
1460 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1461 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1462 first_ts = stream_min_ts;
1465 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen */
1468 demux->first_ts = first_ts;
1470 /* update packets queued before we knew first timestamp */
1471 for (i = 0; i < demux->num_streams; ++i) {
1474 stream = &demux->stream[i];
1476 for (j = 0; j < stream->payloads->len; ++j) {
1477 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1478 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1479 if (payload->ts > first_ts)
1480 payload->ts -= first_ts;
1488 gst_asf_demux_check_segment_ts (demux, 0);
1494 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1496 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1497 and often set wrong, inspecting the data is the only way that seem to be working */
1498 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1499 GstCaps *caps = NULL;
1501 GstAdapter *adapter = gst_adapter_new ();
1503 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1505 AsfPayload *payload;
1508 payload = &g_array_index (stream->payloads, AsfPayload, i);
1509 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1510 len = gst_adapter_available (adapter);
1511 data = gst_adapter_map (adapter, len);
1515 #define MIN_LENGTH 128
1517 /* look for the sync points */
1519 if (len < MIN_LENGTH || /* give typefind something to work on */
1520 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1521 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1527 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1530 if (prob < GST_TYPE_FIND_LIKELY) {
1533 if (len > MIN_LENGTH)
1534 /* this wasn't it, look for another sync point */
1538 gst_adapter_unmap (adapter);
1541 gst_object_unref (adapter);
1544 gst_caps_take (&stream->caps, caps);
1552 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1554 guint i, actual_streams = 0;
1556 if (demux->activated_streams)
1559 if (!all_streams_prerolled (demux) && !force) {
1560 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1564 if (G_UNLIKELY (!gst_asf_demux_get_first_ts (demux)))
1567 for (i = 0; i < demux->num_streams; ++i) {
1568 AsfStream *stream = &demux->stream[i];
1570 if (stream->payloads->len > 0) {
1572 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1573 !stream->active && /* do not inspect active streams (caps were already set) */
1574 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1575 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1576 /* try to gather some more data */
1579 /* we don't check mutual exclusion stuff here; either we have data for
1580 * a stream, then we active it, or we don't, then we'll ignore it */
1581 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1582 gst_asf_demux_activate_stream (demux, stream);
1583 actual_streams += 1;
1585 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1589 if (actual_streams == 0) {
1590 /* We don't have any streams activated ! */
1591 GST_ERROR_OBJECT (demux, "No streams activated!");
1595 gst_asf_demux_release_old_pads (demux);
1597 demux->activated_streams = TRUE;
1598 GST_LOG_OBJECT (demux, "signalling no more pads");
1599 gst_element_no_more_pads (GST_ELEMENT (demux));
1603 /* returns the stream that has a complete payload with the lowest timestamp
1604 * queued, or NULL (we push things by timestamp because during the internal
1605 * prerolling we might accumulate more data then the external queues can take,
1606 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1608 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1610 AsfPayload *best_payload = NULL;
1611 AsfStream *best_stream = NULL;
1614 for (i = 0; i < demux->num_streams; ++i) {
1618 stream = &demux->stream[i];
1620 /* Don't push any data until we have at least one payload that falls within
1621 * the current segment. This way we can remove out-of-segment payloads that
1622 * don't need to be decoded after a seek, sending only data from the
1623 * keyframe directly before our segment start */
1624 if (stream->payloads->len > 0) {
1625 AsfPayload *payload = NULL;
1628 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1629 /* Reverse playback */
1631 if (stream->is_video) {
1632 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1633 if (stream->reverse_kf_ready) {
1635 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1636 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1637 /* TODO : remove payload from the list? */
1644 /* find first complete payload with timestamp */
1645 for (j = stream->payloads->len - 1;
1646 j >= 0 && (payload == NULL
1647 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1648 payload = &g_array_index (stream->payloads, AsfPayload, j);
1651 /* If there's a complete payload queued for this stream */
1652 if (!gst_asf_payload_is_complete (payload))
1658 /* find last payload with timestamp */
1659 for (last_idx = stream->payloads->len - 1;
1660 last_idx >= 0 && (payload == NULL
1661 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1662 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1665 /* if this is first payload after seek we might need to update the segment */
1666 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1667 gst_asf_demux_check_segment_ts (demux, payload->ts);
1669 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1670 (payload->ts < demux->segment.start))) {
1671 if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
1672 && payload->keyframe)) {
1673 GST_DEBUG_OBJECT (stream->pad,
1674 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1675 GST_TIME_ARGS (payload->ts));
1676 demux->segment.start = payload->ts;
1677 demux->segment.time = payload->ts;
1679 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1680 GST_TIME_FORMAT " which is before our segment start %"
1681 GST_TIME_FORMAT ", not pushing yet",
1682 GST_TIME_ARGS (payload->ts),
1683 GST_TIME_ARGS (demux->segment.start));
1688 /* find first complete payload with timestamp */
1690 j < stream->payloads->len && (payload == NULL
1691 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1692 payload = &g_array_index (stream->payloads, AsfPayload, j);
1695 /* Now see if there's a complete payload queued for this stream */
1696 if (!gst_asf_payload_is_complete (payload))
1700 /* ... and whether its timestamp is lower than the current best */
1701 if (best_stream == NULL || best_payload->ts > payload->ts) {
1702 best_stream = stream;
1703 best_payload = payload;
1711 static GstFlowReturn
1712 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1715 GstFlowReturn ret = GST_FLOW_OK;
1717 if (G_UNLIKELY (!demux->activated_streams)) {
1718 if (!gst_asf_demux_check_activate_streams (demux, force))
1720 /* streams are now activated */
1723 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1724 AsfPayload *payload;
1725 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1726 GstClockTime duration = GST_CLOCK_TIME_NONE;
1728 /* wait until we had a chance to "lock on" some payload's timestamp */
1729 if (G_UNLIKELY (demux->need_newsegment
1730 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1733 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1734 && stream->payloads->len) {
1735 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1737 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1740 /* do we need to send a newsegment event */
1741 if ((G_UNLIKELY (demux->need_newsegment))) {
1742 GstEvent *segment_event;
1744 /* safe default if insufficient upstream info */
1745 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1748 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1749 demux->segment.duration > 0) {
1750 /* slight HACK; prevent clipping of last bit */
1751 demux->segment.stop = demux->segment.duration + demux->in_gap;
1754 /* FIXME : only if ACCURATE ! */
1755 if (G_LIKELY (demux->keyunit_sync && !demux->accurate
1756 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1757 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1758 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1759 GST_TIME_ARGS (payload->ts));
1760 demux->segment.start = payload->ts;
1761 demux->segment.time = payload->ts;
1764 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1767 /* note: we fix up all timestamps to start from 0, so this should be ok */
1768 segment_event = gst_event_new_segment (&demux->segment);
1769 if (demux->segment_seqnum)
1770 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1771 gst_asf_demux_send_event_unlocked (demux, segment_event);
1773 /* now post any global tags we may have found */
1774 if (demux->taglist == NULL) {
1775 demux->taglist = gst_tag_list_new_empty ();
1776 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1779 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1780 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1782 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1783 gst_asf_demux_send_event_unlocked (demux,
1784 gst_event_new_tag (demux->taglist));
1785 demux->taglist = NULL;
1787 demux->need_newsegment = FALSE;
1788 demux->segment_seqnum = 0;
1789 demux->segment_running = TRUE;
1792 /* Do we have tags pending for this stream? */
1793 if (G_UNLIKELY (stream->pending_tags)) {
1794 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1795 gst_pad_push_event (stream->pad,
1796 gst_event_new_tag (stream->pending_tags));
1797 stream->pending_tags = NULL;
1800 /* We have the whole packet now so we should push the packet to
1801 * the src pad now. First though we should check if we need to do
1803 if (G_UNLIKELY (stream->span > 1)) {
1804 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1807 payload->buf = gst_buffer_make_writable (payload->buf);
1809 if (G_LIKELY (!payload->keyframe)) {
1810 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1813 if (G_UNLIKELY (stream->discont)) {
1814 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1815 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1816 stream->discont = FALSE;
1819 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1820 (payload->par_x != stream->par_x) &&
1821 (payload->par_y != stream->par_y))) {
1822 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1823 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1824 stream->par_x = payload->par_x;
1825 stream->par_y = payload->par_y;
1826 stream->caps = gst_caps_make_writable (stream->caps);
1827 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1828 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1829 gst_pad_set_caps (stream->pad, stream->caps);
1832 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1833 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1834 payload->interlaced);
1835 stream->interlaced = payload->interlaced;
1836 stream->caps = gst_caps_make_writable (stream->caps);
1837 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1838 (stream->interlaced ? "mixed" : "progressive"), NULL);
1839 gst_pad_set_caps (stream->pad, stream->caps);
1842 /* (sort of) interpolate timestamps using upstream "frame of reference",
1843 * typically useful for live src, but might (unavoidably) mess with
1844 * position reporting if a live src is playing not so live content
1845 * (e.g. rtspsrc taking some time to fall back to tcp) */
1846 timestamp = payload->ts;
1847 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1848 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1849 timestamp += demux->in_gap;
1851 /* Check if we're after the segment already, if so no need to push
1853 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1854 GST_DEBUG_OBJECT (stream->pad,
1855 "Payload after segment stop %" GST_TIME_FORMAT,
1856 GST_TIME_ARGS (demux->segment.stop));
1858 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1860 gst_buffer_unref (payload->buf);
1861 payload->buf = NULL;
1862 g_array_remove_index (stream->payloads, 0);
1863 /* Break out as soon as we have an issue */
1864 if (G_UNLIKELY (ret != GST_FLOW_OK))
1871 GST_BUFFER_PTS (payload->buf) = timestamp;
1873 if (payload->duration == GST_CLOCK_TIME_NONE
1874 && stream->ext_props.avg_time_per_frame != 0) {
1875 duration = stream->ext_props.avg_time_per_frame * 100;
1877 duration = payload->duration;
1879 GST_BUFFER_DURATION (payload->buf) = duration;
1881 /* FIXME: we should really set durations on buffers if we can */
1883 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1886 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1887 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1888 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1890 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1891 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1895 if (stream->active) {
1896 if (G_UNLIKELY (stream->first_buffer)) {
1897 if (stream->streamheader != NULL) {
1898 GST_DEBUG_OBJECT (stream->pad,
1899 "Pushing streamheader before first buffer");
1900 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1902 stream->first_buffer = FALSE;
1905 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1906 && timestamp > demux->segment.position) {
1907 demux->segment.position = timestamp;
1908 if (GST_CLOCK_TIME_IS_VALID (duration))
1909 demux->segment.position += timestamp;
1912 ret = gst_pad_push (stream->pad, payload->buf);
1914 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1917 gst_buffer_unref (payload->buf);
1920 payload->buf = NULL;
1921 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1922 && stream->reverse_kf_ready) {
1923 g_array_remove_index (stream->payloads, stream->kf_pos);
1926 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1928 stream->reverse_kf_ready = FALSE;
1931 g_array_remove_index (stream->payloads, 0);
1934 /* Break out as soon as we have an issue */
1935 if (G_UNLIKELY (ret != GST_FLOW_OK))
1943 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1948 g_assert (buf != NULL);
1950 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1952 gst_buffer_map (buf, &map, GST_MAP_READ);
1954 /* we return false on buffer too small */
1955 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1956 gst_buffer_unmap (buf, &map);
1960 /* check if it is a header */
1962 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1964 gst_buffer_unmap (buf, &map);
1965 if (valid && obj.id == ASF_OBJ_HEADER) {
1972 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1974 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1975 GstFlowReturn ret = GST_FLOW_OK;
1976 GstBuffer *buf = NULL;
1977 gboolean header = FALSE;
1979 /* TODO maybe we should skip index objects after the data and look
1980 * further for a new header */
1981 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1982 g_assert (buf != NULL);
1983 /* check if it is a header */
1984 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1985 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1986 demux->base_offset = off;
1990 gst_buffer_unref (buf);
1997 gst_asf_demux_loop (GstASFDemux * demux)
1999 GstFlowReturn flow = GST_FLOW_OK;
2000 GstBuffer *buf = NULL;
2003 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
2004 if (!gst_asf_demux_pull_headers (demux, &flow)) {
2008 flow = gst_asf_demux_pull_indices (demux);
2009 if (flow != GST_FLOW_OK)
2013 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
2015 if (G_UNLIKELY (demux->num_packets != 0
2016 && demux->packet >= demux->num_packets))
2019 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2020 (guint) demux->num_packets);
2022 off = demux->data_offset + (demux->packet * demux->packet_size);
2024 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2025 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2026 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2027 if (flow == GST_FLOW_EOS) {
2029 } else if (flow == GST_FLOW_FLUSHING) {
2030 GST_DEBUG_OBJECT (demux, "Not fatal");
2037 if (G_LIKELY (demux->speed_packets == 1)) {
2038 GstAsfDemuxParsePacketError err;
2039 err = gst_asf_demux_parse_packet (demux, buf);
2040 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2041 /* when we don't know when the data object ends, we should check
2042 * for a chained asf */
2043 if (demux->num_packets == 0) {
2044 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2045 GST_INFO_OBJECT (demux, "Chained asf found");
2046 demux->base_offset = off;
2047 gst_asf_demux_reset (demux, TRUE);
2048 gst_buffer_unref (buf);
2052 /* FIXME: We should tally up fatal errors and error out only
2053 * after a few broken packets in a row? */
2055 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2056 gst_buffer_unref (buf);
2058 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2059 && !demux->seek_to_cur_pos) {
2061 if (demux->packet < 0) {
2071 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2073 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2074 && !demux->seek_to_cur_pos) {
2076 if (demux->packet < 0) {
2085 for (n = 0; n < demux->speed_packets; n++) {
2087 GstAsfDemuxParsePacketError err;
2090 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2091 n * demux->packet_size, demux->packet_size);
2092 err = gst_asf_demux_parse_packet (demux, sub);
2093 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2094 /* when we don't know when the data object ends, we should check
2095 * for a chained asf */
2096 if (demux->num_packets == 0) {
2097 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2098 GST_INFO_OBJECT (demux, "Chained asf found");
2099 demux->base_offset = off + n * demux->packet_size;
2100 gst_asf_demux_reset (demux, TRUE);
2101 gst_buffer_unref (sub);
2102 gst_buffer_unref (buf);
2106 /* FIXME: We should tally up fatal errors and error out only
2107 * after a few broken packets in a row? */
2109 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2113 gst_buffer_unref (sub);
2115 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2116 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2122 /* reset speed pull */
2123 demux->speed_packets = 1;
2126 gst_buffer_unref (buf);
2128 if (G_UNLIKELY ((demux->num_packets > 0
2129 && demux->packet >= demux->num_packets)
2130 || flow == GST_FLOW_EOS)) {
2131 GST_LOG_OBJECT (demux, "reached EOS");
2135 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2136 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2140 /* check if we're at the end of the configured segment */
2141 /* FIXME: check if segment end reached etc. */
2147 /* if we haven't activated our streams yet, this might be because we have
2148 * less data queued than required for preroll; force stream activation and
2149 * send any pending payloads before sending EOS */
2150 if (!demux->activated_streams)
2151 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2153 /* we want to push an eos or post a segment-done in any case */
2154 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2157 /* for segment playback we need to post when (in stream time)
2158 * we stopped, this is either stop (when set) or the duration. */
2159 if ((stop = demux->segment.stop) == -1)
2160 stop = demux->segment.duration;
2162 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2163 gst_element_post_message (GST_ELEMENT_CAST (demux),
2164 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2166 gst_asf_demux_send_event_unlocked (demux,
2167 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2168 } else if (flow != GST_FLOW_EOS) {
2169 /* check if we have a chained asf, in case, we don't eos yet */
2170 if (gst_asf_demux_check_chained_asf (demux)) {
2171 GST_INFO_OBJECT (demux, "Chained ASF starting");
2172 gst_asf_demux_reset (demux, TRUE);
2177 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2178 if (demux->activated_streams) {
2179 /* normal playback, send EOS to all linked pads */
2180 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2181 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2183 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2184 flow = GST_FLOW_EOS;
2187 /* ... and fall through to pause */
2191 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2192 gst_flow_get_name (flow));
2193 demux->segment_running = FALSE;
2194 gst_pad_pause_task (demux->sinkpad);
2196 /* For the error cases */
2197 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2198 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2199 ("This doesn't seem to be an ASF file"));
2200 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2201 /* Post an error. Hopefully something else already has, but if not... */
2202 GST_ELEMENT_FLOW_ERROR (demux, flow);
2203 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2212 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2213 flow = GST_FLOW_EOS;
2217 /* See FIXMEs above */
2220 gst_buffer_unref (buf);
2221 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2222 ("Error parsing ASF packet %u", (guint) demux->packet));
2223 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2224 flow = GST_FLOW_ERROR;
2230 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2231 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2232 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2235 gst_asf_demux_check_header (GstASFDemux * demux)
2238 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2239 ASF_OBJECT_HEADER_SIZE);
2240 if (cdata == NULL) /* need more data */
2241 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2243 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
2244 && obj.id == ASF_OBJ_HEADER) {
2245 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2248 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2251 static GstFlowReturn
2252 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2254 GstFlowReturn ret = GST_FLOW_OK;
2257 demux = GST_ASF_DEMUX (parent);
2259 GST_LOG_OBJECT (demux,
2260 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2261 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2262 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2264 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2265 GST_DEBUG_OBJECT (demux, "received DISCONT");
2266 gst_asf_demux_mark_discont (demux);
2269 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2270 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2271 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2272 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2273 ", interpolation gap: %" GST_TIME_FORMAT,
2274 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2277 gst_adapter_push (demux->adapter, buf);
2279 switch (demux->state) {
2280 case GST_ASF_DEMUX_STATE_INDEX:{
2281 gint result = gst_asf_demux_check_header (demux);
2282 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2285 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2286 /* we don't care about this, probably an index */
2287 /* TODO maybe would be smarter to skip all the indices
2288 * until we got a new header or EOS to decide */
2289 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2292 GST_INFO_OBJECT (demux, "Chained asf starting");
2293 /* cleanup and get ready for a chained asf */
2294 gst_asf_demux_reset (demux, TRUE);
2298 case GST_ASF_DEMUX_STATE_HEADER:{
2299 ret = gst_asf_demux_chain_headers (demux);
2300 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2302 /* otherwise fall through */
2304 case GST_ASF_DEMUX_STATE_DATA:
2308 data_size = demux->packet_size;
2310 while (gst_adapter_available (demux->adapter) >= data_size) {
2312 GstAsfDemuxParsePacketError err;
2314 /* we don't know the length of the stream
2315 * check for a chained asf everytime */
2316 if (demux->num_packets == 0) {
2317 gint result = gst_asf_demux_check_header (demux);
2319 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2320 GST_INFO_OBJECT (demux, "Chained asf starting");
2321 /* cleanup and get ready for a chained asf */
2322 gst_asf_demux_reset (demux, TRUE);
2325 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2326 && demux->packet >= demux->num_packets)) {
2327 /* do not overshoot data section when streaming */
2331 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2333 /* FIXME: We should tally up fatal errors and error out only
2334 * after a few broken packets in a row? */
2335 err = gst_asf_demux_parse_packet (demux, buf);
2337 gst_buffer_unref (buf);
2339 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2340 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2342 GST_WARNING_OBJECT (demux, "Parse error");
2344 if (demux->packet >= 0)
2347 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2348 && demux->packet >= demux->num_packets)) {
2349 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2354 g_assert_not_reached ();
2358 if (ret != GST_FLOW_OK)
2359 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2365 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2371 static inline gboolean
2372 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2374 if (*p_size < num_bytes)
2377 *p_data += num_bytes;
2378 *p_size -= num_bytes;
2382 static inline guint8
2383 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2387 g_assert (*p_size >= 1);
2388 ret = GST_READ_UINT8 (*p_data);
2389 *p_data += sizeof (guint8);
2390 *p_size -= sizeof (guint8);
2394 static inline guint16
2395 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2399 g_assert (*p_size >= 2);
2400 ret = GST_READ_UINT16_LE (*p_data);
2401 *p_data += sizeof (guint16);
2402 *p_size -= sizeof (guint16);
2406 static inline guint32
2407 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2411 g_assert (*p_size >= 4);
2412 ret = GST_READ_UINT32_LE (*p_data);
2413 *p_data += sizeof (guint32);
2414 *p_size -= sizeof (guint32);
2418 static inline guint64
2419 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2423 g_assert (*p_size >= 8);
2424 ret = GST_READ_UINT64_LE (*p_data);
2425 *p_data += sizeof (guint64);
2426 *p_size -= sizeof (guint64);
2431 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2432 guint8 ** p_data, guint64 * p_size)
2436 if (*p_size < num_bytes_to_read)
2439 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2440 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2442 *p_data += num_bytes_to_read;
2443 *p_size -= num_bytes_to_read;
2449 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2450 guint8 ** p_data, guint64 * p_size)
2454 if (*p_size < num_bytes_to_read)
2457 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2458 *p_data += num_bytes_to_read;
2459 *p_size -= num_bytes_to_read;
2464 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2465 guint8 ** p_data, guint64 * p_size)
2475 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2478 *p_strlen = s_length;
2480 if (s_length == 0) {
2481 GST_WARNING ("zero-length string");
2482 *p_str = g_strdup ("");
2486 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2489 g_assert (s != NULL);
2491 /* just because They don't exist doesn't
2492 * mean They are not out to get you ... */
2493 if (s[s_length - 1] != '\0') {
2494 s = g_realloc (s, s_length + 1);
2498 *p_str = (gchar *) s;
2504 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2506 g_assert (*p_size >= 4 * sizeof (guint32));
2508 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2509 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2510 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2511 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2515 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2518 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2521 /* WAVEFORMATEX Structure */
2522 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2523 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2524 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2525 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2526 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2527 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2528 /* Codec specific data size */
2529 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2530 if (audio->size > *p_size) {
2531 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2532 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2539 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2542 if (*p_size < (4 + 4 + 1 + 2))
2545 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2546 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2547 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2548 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2553 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2554 guint8 ** p_data, guint64 * p_size)
2556 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2559 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2561 if (fmt->size < 40) {
2562 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2565 if ((guint64) fmt->size - 4 > *p_size) {
2566 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2569 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2570 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2571 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2572 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2573 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2574 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2575 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2576 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2577 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2578 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2583 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2587 for (i = 0; i < demux->num_streams; i++) {
2588 if (demux->stream[i].id == id)
2589 return &demux->stream[i];
2592 if (gst_asf_demux_is_unknown_stream (demux, id))
2593 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2598 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2599 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2604 gst_pad_use_fixed_caps (src_pad);
2605 gst_pad_set_caps (src_pad, caps);
2607 gst_pad_set_event_function (src_pad,
2608 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2609 gst_pad_set_query_function (src_pad,
2610 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2612 stream = &demux->stream[demux->num_streams];
2613 stream->caps = caps;
2614 stream->pad = src_pad;
2616 stream->fps_known = !is_video; /* bit hacky for audio */
2617 stream->is_video = is_video;
2618 stream->pending_tags = tags;
2619 stream->discont = TRUE;
2620 stream->first_buffer = TRUE;
2621 stream->streamheader = streamheader;
2622 if (stream->streamheader) {
2623 stream->streamheader = gst_buffer_make_writable (streamheader);
2624 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2629 st = gst_caps_get_structure (caps, 0);
2630 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2631 par_x > 0 && par_y > 0) {
2632 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2633 stream->par_x = par_x;
2634 stream->par_y = par_y;
2638 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2640 /* TODO: create this array during reverse play? */
2641 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2643 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2644 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2646 ++demux->num_streams;
2648 stream->active = FALSE;
2654 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2655 GstBuffer * buffer, GstStructure * structure)
2657 GValue arr_val = G_VALUE_INIT;
2658 GValue buf_val = G_VALUE_INIT;
2660 g_value_init (&arr_val, GST_TYPE_ARRAY);
2661 g_value_init (&buf_val, GST_TYPE_BUFFER);
2663 gst_value_set_buffer (&buf_val, buffer);
2664 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2666 gst_structure_take_value (structure, "streamheader", &arr_val);
2670 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2671 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2673 GstTagList *tags = NULL;
2674 GstBuffer *extradata = NULL;
2677 guint16 size_left = 0;
2678 gchar *codec_name = NULL;
2681 size_left = audio->size;
2683 /* Create the audio pad */
2684 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2686 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2689 /* Swallow up any left over data and set up the
2690 * standard properties from the header info */
2692 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2693 "codec specific data", size_left);
2695 g_assert (size_left <= *p_size);
2696 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2699 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2700 * additional two bytes indicating extradata. */
2701 /* FIXME: Handle the channel reorder map here */
2702 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2703 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2706 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2707 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2710 /* Informing about that audio format we just added */
2712 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2713 g_free (codec_name);
2716 if (audio->byte_rate > 0) {
2717 /* Some ASF files have no bitrate props object (often seen with
2718 * ASF files that contain raw audio data). Example files can
2719 * be generated with FFmpeg (tested with v2.8.6), like this:
2721 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2723 * In this case, if audio->byte_rate is nonzero, use that as
2726 guint bitrate = audio->byte_rate * 8;
2729 tags = gst_tag_list_new_empty ();
2731 /* Add bitrate, but only if there is none set already, since
2732 * this is just a fallback in case there is no bitrate tag
2733 * already present */
2734 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2738 gst_buffer_unref (extradata);
2740 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2741 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2742 audio->codec_tag, tags);
2744 ++demux->num_audio_streams;
2746 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2750 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2751 asf_stream_video_format * video, guint16 id,
2752 guint8 ** p_data, guint64 * p_size)
2754 GstTagList *tags = NULL;
2755 GstStructure *caps_s;
2756 GstBuffer *extradata = NULL;
2761 gchar *codec_name = NULL;
2762 guint64 size_left = video->size - 40;
2763 GstBuffer *streamheader = NULL;
2764 guint par_w = 1, par_h = 1;
2766 /* Create the video pad */
2767 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2768 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2771 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2773 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2774 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2776 g_assert (size_left <= *p_size);
2777 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2780 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2782 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2783 caps = gst_riff_create_video_caps (video->tag, NULL,
2784 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2787 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2788 G_TYPE_UINT, video->tag, NULL);
2793 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2794 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2795 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2798 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2802 /* retry with the global metadata */
2803 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2804 demux->global_metadata);
2805 s = demux->global_metadata;
2806 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2807 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2808 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2809 if (ax > 0 && ay > 0) {
2812 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2817 s = gst_caps_get_structure (caps, 0);
2818 gst_structure_remove_field (s, "framerate");
2821 caps_s = gst_caps_get_structure (caps, 0);
2823 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2824 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2825 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2826 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2829 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2830 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2831 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2833 GstBuffer *buf = gst_value_get_buffer (value);
2836 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2837 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2838 /* this looks like a bytestream start */
2839 streamheader = gst_buffer_ref (buf);
2840 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2841 gst_structure_remove_field (caps_s, "codec_data");
2842 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING,
2843 "byte-stream", NULL);
2845 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "avc",
2849 gst_buffer_unmap (buf, &mapinfo);
2852 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "byte-stream",
2857 /* For a 3D video, set multiview information into the caps based on
2858 * what was detected during object parsing */
2859 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2860 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2861 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2862 const gchar *mview_mode_str;
2864 switch (demux->asf_3D_mode) {
2865 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2866 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2868 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2869 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2870 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2872 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2873 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2875 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2876 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2877 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2879 case GST_ASF_3D_DUAL_STREAM:{
2880 gboolean is_right_view = FALSE;
2881 /* if Advanced_Mutual_Exclusion object exists, use it
2882 * to figure out which is the left view (lower ID) */
2883 if (demux->mut_ex_streams != NULL) {
2887 length = g_slist_length (demux->mut_ex_streams);
2889 for (i = 0; i < length; i++) {
2892 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2894 GST_DEBUG_OBJECT (demux,
2895 "has Mutual_Exclusion object. stream id in object is %d",
2896 GPOINTER_TO_INT (v_s_id));
2898 if (id > GPOINTER_TO_INT (v_s_id))
2899 is_right_view = TRUE;
2902 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2903 * first video stream encountered has the lower ID */
2904 if (demux->num_video_streams > 0) {
2905 /* This is not the first video stream, assuming right eye view */
2906 is_right_view = TRUE;
2910 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2912 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2919 GST_INFO_OBJECT (demux,
2920 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2923 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2924 if (mview_mode_str != NULL) {
2925 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2926 video->height, par_w, par_h))
2927 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2929 gst_caps_set_simple (caps,
2930 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2931 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2932 GST_FLAG_SET_MASK_EXACT, NULL);
2937 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2938 g_free (codec_name);
2942 gst_buffer_unref (extradata);
2944 GST_INFO ("Adding video stream #%u, id %u, codec %"
2945 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2946 GST_FOURCC_ARGS (video->tag), video->tag);
2948 ++demux->num_video_streams;
2950 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2951 streamheader, tags);
2955 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2957 if (!stream->active) {
2961 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2962 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2963 gst_pad_set_active (stream->pad, TRUE);
2966 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2967 "%03u", stream->id);
2970 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2972 if (gst_event_parse_group_id (event, &demux->group_id))
2973 demux->have_group_id = TRUE;
2975 demux->have_group_id = FALSE;
2976 gst_event_unref (event);
2977 } else if (!demux->have_group_id) {
2978 demux->have_group_id = TRUE;
2979 demux->group_id = gst_util_group_id_next ();
2982 event = gst_event_new_stream_start (stream_id);
2983 if (demux->have_group_id)
2984 gst_event_set_group_id (event, demux->group_id);
2986 gst_pad_push_event (stream->pad, event);
2988 gst_pad_set_caps (stream->pad, stream->caps);
2990 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2991 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2992 stream->active = TRUE;
2997 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
3000 AsfCorrectionType correction_type;
3001 AsfStreamType stream_type;
3002 GstClockTime time_offset;
3003 gboolean is_encrypted G_GNUC_UNUSED;
3007 guint stream_specific_size;
3008 guint type_specific_size G_GNUC_UNUSED;
3009 guint unknown G_GNUC_UNUSED;
3010 gboolean inspect_payload = FALSE;
3011 AsfStream *stream = NULL;
3013 /* Get the rest of the header's header */
3014 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
3015 goto not_enough_data;
3017 gst_asf_demux_get_guid (&guid, &data, &size);
3018 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
3020 gst_asf_demux_get_guid (&guid, &data, &size);
3021 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
3023 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
3025 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3026 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3028 flags = gst_asf_demux_get_uint16 (&data, &size);
3029 stream_id = flags & 0x7f;
3030 is_encrypted = ! !(flags & 0x8000);
3031 unknown = gst_asf_demux_get_uint32 (&data, &size);
3033 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3034 stream_id, GST_TIME_ARGS (time_offset));
3036 /* dvr-ms has audio stream declared in stream specific data */
3037 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3038 AsfExtStreamType ext_stream_type;
3039 gst_asf_demux_get_guid (&guid, &data, &size);
3040 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3042 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3043 inspect_payload = TRUE;
3045 gst_asf_demux_get_guid (&guid, &data, &size);
3046 gst_asf_demux_get_uint32 (&data, &size);
3047 gst_asf_demux_get_uint32 (&data, &size);
3048 gst_asf_demux_get_uint32 (&data, &size);
3049 gst_asf_demux_get_guid (&guid, &data, &size);
3050 gst_asf_demux_get_uint32 (&data, &size);
3051 stream_type = ASF_STREAM_AUDIO;
3055 switch (stream_type) {
3056 case ASF_STREAM_AUDIO:{
3057 asf_stream_audio audio_object;
3059 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3060 goto not_enough_data;
3062 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3065 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3068 switch (correction_type) {
3069 case ASF_CORRECTION_ON:{
3070 guint span, packet_size, chunk_size, data_size, silence_data;
3072 GST_INFO ("Using error correction");
3074 if (size < (1 + 2 + 2 + 2 + 1))
3075 goto not_enough_data;
3077 span = gst_asf_demux_get_uint8 (&data, &size);
3078 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3079 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3080 data_size = gst_asf_demux_get_uint16 (&data, &size);
3081 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3083 stream->span = span;
3085 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3086 packet_size, chunk_size, data_size, span, silence_data);
3088 if (stream->span > 1) {
3089 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3090 /* Disable descrambling */
3093 /* FIXME: this else branch was added for
3094 * weird_al_yankovic - the saga begins.asf */
3095 stream->ds_packet_size = packet_size;
3096 stream->ds_chunk_size = chunk_size;
3099 /* Descambling is enabled */
3100 stream->ds_packet_size = packet_size;
3101 stream->ds_chunk_size = chunk_size;
3104 /* Now skip the rest of the silence data */
3106 gst_bytestream_flush (demux->bs, data_size - 1);
3108 /* FIXME: CHECKME. And why -1? */
3109 if (data_size > 1) {
3110 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3111 goto not_enough_data;
3117 case ASF_CORRECTION_OFF:{
3118 GST_INFO ("Error correction off");
3119 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3120 goto not_enough_data;
3124 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3125 ("Audio stream using unknown error correction"));
3132 case ASF_STREAM_VIDEO:{
3133 asf_stream_video_format video_format_object;
3134 asf_stream_video video_object;
3137 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3138 goto not_enough_data;
3140 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3142 GST_INFO ("object is a video stream with %u bytes of "
3143 "additional data", vsize);
3145 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3147 goto not_enough_data;
3150 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3151 stream_id, &data, &size);
3157 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3159 demux->other_streams =
3160 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3165 stream->inspect_payload = inspect_payload;
3166 stream->type = stream_type;
3172 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3173 /* we'll error out later if we found no streams */
3178 static const gchar *
3179 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3183 const gchar *asf_name;
3184 const gchar *gst_name;
3187 "WM/Genre", GST_TAG_GENRE}, {
3188 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3189 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3190 "WM/Picture", GST_TAG_IMAGE}, {
3191 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3192 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3193 "WM/Year", GST_TAG_DATE_TIME}
3194 /* { "WM/Composer", GST_TAG_COMPOSER } */
3199 if (name_utf8 == NULL) {
3200 GST_WARNING ("Failed to convert name to UTF8, skipping");
3204 out = strlen (name_utf8);
3206 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3207 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3208 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3209 return tags[i].gst_name;
3216 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3218 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3222 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3224 if (taglist == NULL)
3227 if (gst_tag_list_is_empty (taglist)) {
3228 gst_tag_list_unref (taglist);
3232 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3233 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3235 gst_tag_list_unref (demux->taglist);
3236 gst_tag_list_unref (taglist);
3238 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3241 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3242 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3243 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3244 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3247 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3251 const guint8 *img_data = NULL;
3252 guint32 img_data_len = 0;
3253 guint8 pic_type = 0;
3255 gst_byte_reader_init (&r, tag_data, tag_data_len);
3257 /* skip mime type string (we don't trust it and do our own typefinding),
3258 * and also skip the description string, since we don't use it */
3259 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3260 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3261 !gst_byte_reader_skip_string_utf16 (&r) ||
3262 !gst_byte_reader_skip_string_utf16 (&r) ||
3263 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3264 goto not_enough_data;
3268 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3269 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3275 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3276 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3281 /* Extended Content Description Object */
3282 static GstFlowReturn
3283 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3286 /* Other known (and unused) 'text/unicode' metadata available :
3289 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3290 * WMFSDKVersion = 9.00.00.2980
3291 * WMFSDKNeeded = 0.0.0.0000
3292 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3293 * WM/Publisher = 4AD
3295 * WM/ProviderRating = 8
3296 * WM/ProviderStyle = Rock (similar to WM/Genre)
3297 * WM/GenreID (similar to WM/Genre)
3298 * WM/TrackNumber (same as WM/Track but as a string)
3300 * Other known (and unused) 'non-text' metadata available :
3306 * We might want to read WM/TrackNumber and use atoi() if we don't have
3310 GstTagList *taglist;
3311 guint16 blockcount, i;
3312 gboolean content3D = FALSE;
3316 const gchar *interleave_name;
3317 GstASF3DMode interleaving_type;
3318 } stereoscopic_layout_map[] = {
3320 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3321 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3322 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3323 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3324 "DualStream", GST_ASF_3D_DUAL_STREAM}
3326 GST_INFO_OBJECT (demux, "object is an extended content description");
3328 taglist = gst_tag_list_new_empty ();
3330 /* Content Descriptor Count */
3332 goto not_enough_data;
3334 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3336 for (i = 1; i <= blockcount; ++i) {
3337 const gchar *gst_tag_name;
3341 GValue tag_value = { 0, };
3344 gchar *name_utf8 = NULL;
3348 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3349 goto not_enough_data;
3353 goto not_enough_data;
3355 /* Descriptor Value Data Type */
3356 datatype = gst_asf_demux_get_uint16 (&data, &size);
3358 /* Descriptor Value (not really a string, but same thing reading-wise) */
3359 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3361 goto not_enough_data;
3365 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3367 if (name_utf8 != NULL) {
3368 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3370 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3371 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3374 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3377 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3380 /* get rid of tags with empty value */
3381 if (value_utf8 != NULL && *value_utf8 != '\0') {
3382 GST_DEBUG ("string value %s", value_utf8);
3384 value_utf8[out] = '\0';
3386 if (gst_tag_name != NULL) {
3387 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3388 guint year = atoi (value_utf8);
3391 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3392 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3394 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3395 guint id3v1_genre_id;
3396 const gchar *genre_str;
3398 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3399 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3400 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3401 g_free (value_utf8);
3402 value_utf8 = g_strdup (genre_str);
3407 /* convert tag from string to other type if required */
3408 tag_type = gst_tag_get_type (gst_tag_name);
3409 g_value_init (&tag_value, tag_type);
3410 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3411 GValue from_val = { 0, };
3413 g_value_init (&from_val, G_TYPE_STRING);
3414 g_value_set_string (&from_val, value_utf8);
3415 if (!g_value_transform (&from_val, &tag_value)) {
3416 GST_WARNING_OBJECT (demux,
3417 "Could not transform string tag to " "%s tag type %s",
3418 gst_tag_name, g_type_name (tag_type));
3419 g_value_unset (&tag_value);
3421 g_value_unset (&from_val);
3426 GST_DEBUG ("Setting metadata");
3427 g_value_init (&tag_value, G_TYPE_STRING);
3428 g_value_set_string (&tag_value, value_utf8);
3429 /* If we found a stereoscopic marker, look for StereoscopicLayout
3433 if (strncmp ("StereoscopicLayout", name_utf8,
3434 strlen (name_utf8)) == 0) {
3435 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3436 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3438 demux->asf_3D_mode =
3439 stereoscopic_layout_map[i].interleaving_type;
3440 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3444 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3446 demux->asf_3D_mode = GST_ASF_3D_NONE;
3447 GST_INFO_OBJECT (demux, "None 3d type");
3450 } else if (value_utf8 == NULL) {
3451 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3453 GST_DEBUG ("Skipping empty string value for %s",
3454 GST_STR_NULL (gst_tag_name));
3456 g_free (value_utf8);
3459 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3461 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3462 GST_FIXME ("Unhandled byte array tag %s",
3463 GST_STR_NULL (gst_tag_name));
3466 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3472 case ASF_DEMUX_DATA_TYPE_DWORD:{
3478 uint_val = GST_READ_UINT32_LE (value);
3480 /* this is the track number */
3481 g_value_init (&tag_value, G_TYPE_UINT);
3483 /* WM/Track counts from 0 */
3484 if (!strcmp (name_utf8, "WM/Track"))
3487 g_value_set_uint (&tag_value, uint_val);
3491 case ASF_DEMUX_DATA_TYPE_BOOL:{
3497 bool_val = GST_READ_UINT32_LE (value);
3499 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3501 GST_INFO_OBJECT (demux, "This is 3D contents");
3504 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3512 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3517 if (G_IS_VALUE (&tag_value)) {
3519 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3521 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3522 * is supposed to have a 0 base but is often wrongly written to start
3523 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3524 * replace the value added earlier from WM/Track or put it first in
3525 * the list, so that it will get picked up by _get_uint() */
3526 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3527 merge_mode = GST_TAG_MERGE_REPLACE;
3529 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3532 GST_DEBUG ("Setting global metadata %s", name_utf8);
3533 gst_structure_set_value (demux->global_metadata, name_utf8,
3537 g_value_unset (&tag_value);
3546 gst_asf_demux_add_global_tags (demux, taglist);
3553 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3554 gst_tag_list_unref (taglist);
3555 return GST_FLOW_OK; /* not really fatal */
3559 static GstStructure *
3560 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3565 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3567 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3570 s = gst_caps_get_structure (demux->metadata, i);
3571 if (gst_structure_has_name (s, sname))
3575 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3577 /* try lookup again; demux->metadata took ownership of the structure, so we
3578 * can't really make any assumptions about what happened to it, so we can't
3579 * just return it directly after appending it */
3580 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3583 static GstFlowReturn
3584 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3587 guint16 blockcount, i;
3589 GST_INFO_OBJECT (demux, "object is a metadata object");
3591 /* Content Descriptor Count */
3593 goto not_enough_data;
3595 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3597 for (i = 0; i < blockcount; ++i) {
3599 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3600 guint32 data_len, ival;
3603 if (size < (2 + 2 + 2 + 2 + 4))
3604 goto not_enough_data;
3606 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3607 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3608 name_len = gst_asf_demux_get_uint16 (&data, &size);
3609 data_type = gst_asf_demux_get_uint16 (&data, &size);
3610 data_len = gst_asf_demux_get_uint32 (&data, &size);
3612 if (size < name_len + data_len)
3613 goto not_enough_data;
3615 /* convert name to UTF-8 */
3616 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3618 gst_asf_demux_skip_bytes (name_len, &data, &size);
3620 if (name_utf8 == NULL) {
3621 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3622 gst_asf_demux_skip_bytes (data_len, &data, &size);
3626 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3627 gst_asf_demux_skip_bytes (data_len, &data, &size);
3635 goto not_enough_data;
3638 ival = gst_asf_demux_get_uint32 (&data, &size);
3640 /* skip anything else there may be, just in case */
3641 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3643 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3644 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3648 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3654 GST_WARNING ("Unexpected end of data parsing metadata object");
3655 return GST_FLOW_OK; /* not really fatal */
3659 static GstFlowReturn
3660 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3662 GstFlowReturn ret = GST_FLOW_OK;
3663 guint32 i, num_objects;
3664 guint8 unknown G_GNUC_UNUSED;
3666 /* Get the rest of the header's header */
3667 if (size < (4 + 1 + 1))
3668 goto not_enough_data;
3670 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3671 unknown = gst_asf_demux_get_uint8 (&data, &size);
3672 unknown = gst_asf_demux_get_uint8 (&data, &size);
3674 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3675 demux->saw_file_header = FALSE;
3676 /* Loop through the header's objects, processing those */
3677 for (i = 0; i < num_objects; ++i) {
3678 GST_INFO_OBJECT (demux, "reading header part %u", i);
3679 ret = gst_asf_demux_process_object (demux, &data, &size);
3680 if (ret != GST_FLOW_OK) {
3681 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3685 if (!demux->saw_file_header) {
3686 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3687 ("Header does not have mandatory FILE section"));
3688 return GST_FLOW_ERROR;
3695 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3696 ("short read parsing HEADER object"));
3697 return GST_FLOW_ERROR;
3701 static GstFlowReturn
3702 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3704 guint64 creation_time G_GNUC_UNUSED;
3705 guint64 file_size G_GNUC_UNUSED;
3706 guint64 send_time G_GNUC_UNUSED;
3707 guint64 packets_count, play_time, preroll;
3708 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3710 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3711 goto not_enough_data;
3713 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3714 file_size = gst_asf_demux_get_uint64 (&data, &size);
3715 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3716 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3717 play_time = gst_asf_demux_get_uint64 (&data, &size);
3718 send_time = gst_asf_demux_get_uint64 (&data, &size);
3719 preroll = gst_asf_demux_get_uint64 (&data, &size);
3720 flags = gst_asf_demux_get_uint32 (&data, &size);
3721 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3722 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3723 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3725 demux->broadcast = ! !(flags & 0x01);
3726 demux->seekable = ! !(flags & 0x02);
3728 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3729 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3730 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3732 if (demux->broadcast) {
3733 /* these fields are invalid if the broadcast flag is set */
3738 if (min_pktsize != max_pktsize)
3739 goto non_fixed_packet_size;
3741 demux->packet_size = max_pktsize;
3743 /* FIXME: do we need send_time as well? what is it? */
3744 if ((play_time * 100) >= (preroll * GST_MSECOND))
3745 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3747 demux->play_time = 0;
3749 demux->preroll = preroll * GST_MSECOND;
3751 /* initial latency */
3752 demux->latency = demux->preroll;
3754 if (demux->play_time == 0)
3755 demux->seekable = FALSE;
3757 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3758 GST_TIME_ARGS (demux->play_time));
3759 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3760 GST_TIME_ARGS (demux->preroll));
3762 if (demux->play_time > 0) {
3763 demux->segment.duration = demux->play_time;
3766 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3768 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3770 demux->saw_file_header = TRUE;
3775 non_fixed_packet_size:
3777 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3778 ("packet size must be fixed"));
3779 return GST_FLOW_ERROR;
3783 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3784 ("short read parsing FILE object"));
3785 return GST_FLOW_ERROR;
3789 /* Content Description Object */
3790 static GstFlowReturn
3791 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3795 const gchar *gst_tag;
3800 GST_TAG_TITLE, 0, NULL}, {
3801 GST_TAG_ARTIST, 0, NULL}, {
3802 GST_TAG_COPYRIGHT, 0, NULL}, {
3803 GST_TAG_DESCRIPTION, 0, NULL}, {
3804 GST_TAG_COMMENT, 0, NULL}
3806 GstTagList *taglist;
3807 GValue value = { 0 };
3811 GST_INFO_OBJECT (demux, "object is a comment");
3813 if (size < (2 + 2 + 2 + 2 + 2))
3814 goto not_enough_data;
3816 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3817 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3818 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3819 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3820 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3822 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3823 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3824 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3826 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3827 if (size < tags[i].val_length)
3828 goto not_enough_data;
3830 /* might be just '/0', '/0'... */
3831 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3832 /* convert to UTF-8 */
3833 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3834 "UTF-8", "UTF-16LE", &in, &out, NULL);
3836 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3839 /* parse metadata into taglist */
3840 taglist = gst_tag_list_new_empty ();
3841 g_value_init (&value, G_TYPE_STRING);
3842 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3843 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3844 g_value_set_string (&value, tags[i].val_utf8);
3845 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3846 tags[i].gst_tag, &value, NULL);
3849 g_value_unset (&value);
3851 gst_asf_demux_add_global_tags (demux, taglist);
3853 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3854 g_free (tags[i].val_utf8);
3860 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3861 "comment tag section %d, skipping comment object", i);
3862 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3863 g_free (tags[i].val_utf8);
3864 return GST_FLOW_OK; /* not really fatal */
3868 static GstFlowReturn
3869 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3872 guint16 num_streams, i;
3876 goto not_enough_data;
3878 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3880 GST_INFO ("object is a bitrate properties object with %u streams",
3883 if (size < (num_streams * (2 + 4)))
3884 goto not_enough_data;
3886 for (i = 0; i < num_streams; ++i) {
3890 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3891 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3893 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3894 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3895 stream = gst_asf_demux_get_stream (demux, stream_id);
3897 if (stream->pending_tags == NULL)
3898 stream->pending_tags = gst_tag_list_new_empty ();
3899 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3900 GST_TAG_BITRATE, bitrate, NULL);
3902 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3905 GST_WARNING ("stream id %u is too large", stream_id);
3913 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3914 return GST_FLOW_OK; /* not really fatal */
3918 static GstFlowReturn
3919 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3922 GstFlowReturn ret = GST_FLOW_OK;
3925 /* Get the rest of the header's header */
3926 if (size < (16 + 2 + 4))
3927 goto not_enough_data;
3929 /* skip GUID and two other bytes */
3930 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3931 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3933 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3935 /* FIXME: does data_size include the rest of the header that we have read? */
3936 if (hdr_size > size)
3937 goto not_enough_data;
3939 while (hdr_size > 0) {
3940 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3941 if (ret != GST_FLOW_OK)
3949 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3950 ("short read parsing extended header object"));
3951 return GST_FLOW_ERROR;
3955 static GstFlowReturn
3956 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3962 goto not_enough_data;
3964 if (demux->languages) {
3965 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3966 g_strfreev (demux->languages);
3967 demux->languages = NULL;
3968 demux->num_languages = 0;
3971 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3972 GST_LOG ("%u languages:", demux->num_languages);
3974 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3975 for (i = 0; i < demux->num_languages; ++i) {
3976 guint8 len, *lang_data = NULL;
3979 goto not_enough_data;
3980 len = gst_asf_demux_get_uint8 (&data, &size);
3981 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3984 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3987 /* truncate "en-us" etc. to just "en" */
3988 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3991 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3992 demux->languages[i] = utf8;
3995 goto not_enough_data;
4003 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
4004 g_free (demux->languages);
4005 demux->languages = NULL;
4006 demux->num_languages = 0;
4007 return GST_FLOW_OK; /* not fatal */
4011 static GstFlowReturn
4012 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
4015 GstClockTime interval;
4018 if (size < (16 + 8 + 4 + 4))
4019 goto not_enough_data;
4022 gst_asf_demux_skip_bytes (16, &data, &size);
4023 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
4024 gst_asf_demux_skip_bytes (4, &data, &size);
4025 count = gst_asf_demux_get_uint32 (&data, &size);
4027 demux->sidx_interval = interval;
4028 demux->sidx_num_entries = count;
4029 g_free (demux->sidx_entries);
4030 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
4032 for (i = 0; i < count; ++i) {
4033 if (G_UNLIKELY (size < 6)) {
4034 /* adjust for broken files, to avoid having entries at the end
4035 * of the parsed index that point to time=0. Resulting in seeking to
4036 * the end of the file leading back to the beginning */
4037 demux->sidx_num_entries -= (count - i);
4040 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4041 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4042 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4043 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4044 demux->sidx_entries[i].count);
4047 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4054 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4055 return GST_FLOW_OK; /* not fatal */
4059 static GstFlowReturn
4060 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4061 guint8 * data, guint64 size)
4066 if (size < 16 + 2 + (2 * 2))
4067 goto not_enough_data;
4069 gst_asf_demux_get_guid (&guid, &data, &size);
4070 num = gst_asf_demux_get_uint16 (&data, &size);
4073 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4077 if (size < (num * sizeof (guint16)))
4078 goto not_enough_data;
4080 /* read mutually exclusive stream numbers */
4081 for (i = 0; i < num; ++i) {
4083 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4084 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4086 demux->mut_ex_streams =
4087 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4096 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4097 return GST_FLOW_OK; /* not absolutely fatal */
4102 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4104 return g_slist_find (demux->other_streams,
4105 GINT_TO_POINTER (stream_num)) == NULL;
4108 static GstFlowReturn
4109 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4112 AsfStreamExtProps esp;
4113 AsfStream *stream = NULL;
4114 AsfObject stream_obj;
4115 guint16 stream_name_count;
4116 guint16 num_payload_ext;
4118 guint8 *stream_obj_data = NULL;
4121 guint i, stream_num;
4124 obj_size = (guint) size;
4126 esp.payload_extensions = NULL;
4129 goto not_enough_data;
4132 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4133 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4134 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4135 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4136 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4137 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4138 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4139 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4140 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4141 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4142 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4143 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4144 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4145 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4146 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4148 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4149 GST_TIME_ARGS (esp.start_time));
4150 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4151 GST_TIME_ARGS (esp.end_time));
4152 GST_INFO ("flags = %08x", esp.flags);
4153 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4154 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4155 GST_INFO ("stream number = %u", stream_num);
4156 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4157 (esp.lang_idx < demux->num_languages) ?
4158 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4159 GST_INFO ("stream name count = %u", stream_name_count);
4161 /* read stream names */
4162 for (i = 0; i < stream_name_count; ++i) {
4163 guint16 stream_lang_idx G_GNUC_UNUSED;
4164 gchar *stream_name = NULL;
4167 goto not_enough_data;
4168 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4169 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4170 goto not_enough_data;
4171 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4172 g_free (stream_name); /* TODO: store names in struct */
4175 /* read payload extension systems stuff */
4176 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4178 if (num_payload_ext > 0)
4179 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4181 for (i = 0; i < num_payload_ext; ++i) {
4182 AsfPayloadExtension ext;
4184 guint32 sys_info_len;
4186 if (size < 16 + 2 + 4)
4187 goto not_enough_data;
4189 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4190 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4191 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4193 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4194 GST_LOG ("payload systems info len = %u", sys_info_len);
4195 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4196 goto not_enough_data;
4198 esp.payload_extensions[i] = ext;
4201 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4203 /* there might be an optional STREAM_INFO object here now; if not, we
4204 * should have parsed the corresponding stream info object already (since
4205 * we are parsing the extended stream properties objects delayed) */
4207 stream = gst_asf_demux_get_stream (demux, stream_num);
4211 if (size < ASF_OBJECT_HEADER_SIZE)
4212 goto not_enough_data;
4214 /* get size of the stream object */
4215 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4216 goto corrupted_stream;
4218 if (stream_obj.id != ASF_OBJ_STREAM)
4219 goto expected_stream_object;
4221 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4222 stream_obj.size > (10 * 1024 * 1024))
4223 goto not_enough_data;
4225 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4227 /* process this stream object later after all the other 'normal' ones
4228 * have been processed (since the others are more important/non-hidden) */
4229 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4230 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4231 goto not_enough_data;
4233 /* parse stream object */
4234 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4235 g_free (stream_obj_data);
4240 stream->ext_props = esp;
4242 /* try to set the framerate */
4243 if (stream->is_video && stream->caps) {
4244 GValue framerate = { 0 };
4248 g_value_init (&framerate, GST_TYPE_FRACTION);
4250 num = GST_SECOND / 100;
4251 denom = esp.avg_time_per_frame;
4253 /* avoid division by 0, assume 25/1 framerate */
4254 denom = GST_SECOND / 2500;
4257 gst_value_set_fraction (&framerate, num, denom);
4259 stream->caps = gst_caps_make_writable (stream->caps);
4260 s = gst_caps_get_structure (stream->caps, 0);
4261 gst_structure_set_value (s, "framerate", &framerate);
4262 g_value_unset (&framerate);
4263 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4264 num, denom, ((gdouble) num) / denom);
4267 /* add language info now if we have it */
4268 if (stream->ext_props.lang_idx < demux->num_languages) {
4269 if (stream->pending_tags == NULL)
4270 stream->pending_tags = gst_tag_list_new_empty ();
4271 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4272 demux->languages[stream->ext_props.lang_idx]);
4273 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4274 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4277 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4278 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4282 g_free (esp.payload_extensions);
4289 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4290 g_free (esp.payload_extensions);
4291 return GST_FLOW_OK; /* not absolutely fatal */
4293 expected_stream_object:
4295 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4296 "object: expected embedded stream object, but got %s object instead!",
4297 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4298 g_free (esp.payload_extensions);
4299 return GST_FLOW_OK; /* not absolutely fatal */
4303 GST_WARNING_OBJECT (demux, "Corrupted stream");
4304 g_free (esp.payload_extensions);
4305 return GST_FLOW_ERROR;
4309 static const gchar *
4310 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4314 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4315 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4316 nick += strlen ("ASF_OBJ_");
4318 if (demux->objpath == NULL) {
4319 demux->objpath = g_strdup (nick);
4323 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4324 g_free (demux->objpath);
4325 demux->objpath = newpath;
4328 return (const gchar *) demux->objpath;
4332 gst_asf_demux_pop_obj (GstASFDemux * demux)
4336 if ((s = g_strrstr (demux->objpath, "/"))) {
4339 g_free (demux->objpath);
4340 demux->objpath = NULL;
4345 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4350 /* Parse the queued extended stream property objects and add the info
4351 * to the existing streams or add the new embedded streams, but without
4352 * activating them yet */
4353 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4354 g_slist_length (demux->ext_stream_props));
4356 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4357 GstBuffer *buf = GST_BUFFER (l->data);
4360 gst_buffer_map (buf, &map, GST_MAP_READ);
4362 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4363 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4364 gst_buffer_unmap (buf, &map);
4365 gst_buffer_unref (buf);
4367 g_slist_free (demux->ext_stream_props);
4368 demux->ext_stream_props = NULL;
4373 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4377 for (i = 0; i < demux->num_streams; ++i) {
4382 stream = &demux->stream[i];
4384 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4386 if (stream->active) {
4387 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4392 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4395 /* check for each mutual exclusion whether it affects this stream */
4396 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4397 if (*mes == stream->id) {
4398 /* if yes, check if we've already added streams that are mutually
4399 * exclusive with the stream we're about to add */
4400 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4401 for (j = 0; j < demux->num_streams; ++j) {
4402 /* if the broadcast flag is set, assume the hidden streams aren't
4403 * actually streamed and hide them (or playbin won't work right),
4404 * otherwise assume their data is available */
4405 if (demux->stream[j].id == *mes && demux->broadcast) {
4407 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4408 "mutually exclusive with already existing stream ID %d, "
4409 "hiding stream", stream->id, demux->stream[j].id);
4421 /* FIXME: we should do stream activation based on preroll data in
4422 * streaming mode too */
4423 if (demux->streaming && !is_hidden)
4424 gst_asf_demux_activate_stream (demux, stream);
4429 static GstFlowReturn
4430 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4433 GstFlowReturn ret = GST_FLOW_OK;
4435 guint64 obj_data_size;
4437 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4438 return ASF_FLOW_NEED_MORE_DATA;
4440 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4442 return GST_FLOW_ERROR;
4443 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4445 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4447 if (*p_size < obj_data_size)
4448 return ASF_FLOW_NEED_MORE_DATA;
4450 gst_asf_demux_push_obj (demux, obj.id);
4452 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4455 case ASF_OBJ_STREAM:
4456 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4460 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4462 case ASF_OBJ_HEADER:
4463 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4465 case ASF_OBJ_COMMENT:
4466 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4469 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4471 case ASF_OBJ_BITRATE_PROPS:
4473 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4476 case ASF_OBJ_EXT_CONTENT_DESC:
4478 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4481 case ASF_OBJ_METADATA_OBJECT:
4482 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4484 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4487 /* process these later, we might not have parsed the corresponding
4488 * stream object yet */
4489 GST_LOG ("%s: queued for later parsing", demux->objpath);
4490 buf = gst_buffer_new_and_alloc (obj_data_size);
4491 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4492 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4496 case ASF_OBJ_LANGUAGE_LIST:
4497 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4499 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4500 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4503 case ASF_OBJ_SIMPLE_INDEX:
4504 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4506 case ASF_OBJ_CONTENT_ENCRYPTION:
4507 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4508 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4509 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4510 goto error_encrypted;
4511 case ASF_OBJ_CONCEAL_NONE:
4513 case ASF_OBJ_UNDEFINED:
4514 case ASF_OBJ_CODEC_COMMENT:
4516 case ASF_OBJ_PADDING:
4517 case ASF_OBJ_BITRATE_MUTEX:
4518 case ASF_OBJ_COMPATIBILITY:
4519 case ASF_OBJ_INDEX_PLACEHOLDER:
4520 case ASF_OBJ_INDEX_PARAMETERS:
4521 case ASF_OBJ_STREAM_PRIORITIZATION:
4522 case ASF_OBJ_SCRIPT_COMMAND:
4523 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4525 /* Unknown/unhandled object, skip it and hope for the best */
4526 GST_INFO ("%s: skipping object", demux->objpath);
4531 /* this can't fail, we checked the number of bytes available before */
4532 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4534 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4536 gst_asf_demux_pop_obj (demux);
4543 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4544 return GST_FLOW_ERROR;
4549 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4550 GstBuffer ** p_buffer)
4552 GstBuffer *descrambled_buffer;
4553 GstBuffer *scrambled_buffer;
4554 GstBuffer *sub_buffer;
4561 /* descrambled_buffer is initialised in the first iteration */
4562 descrambled_buffer = NULL;
4563 scrambled_buffer = *p_buffer;
4565 if (gst_buffer_get_size (scrambled_buffer) <
4566 stream->ds_packet_size * stream->span)
4569 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4570 offset += stream->ds_chunk_size) {
4571 off = offset / stream->ds_chunk_size;
4572 row = off / stream->span;
4573 col = off % stream->span;
4574 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4575 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4576 col, off, stream->ds_chunk_size);
4577 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4578 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4579 stream->span, stream->ds_packet_size);
4580 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4581 gst_buffer_get_size (scrambled_buffer));
4583 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4584 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4586 descrambled_buffer = sub_buffer;
4588 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4592 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4593 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4594 GST_BUFFER_DURATION (descrambled_buffer) =
4595 GST_BUFFER_DURATION (scrambled_buffer);
4596 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4597 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4598 GST_BUFFER_OFFSET_END (scrambled_buffer);
4600 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4602 gst_buffer_unref (scrambled_buffer);
4603 *p_buffer = descrambled_buffer;
4607 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4609 GstASFDemux *demux = GST_ASF_DEMUX (element);
4612 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4614 for (i = 0; i < demux->num_streams; ++i) {
4615 gst_event_ref (event);
4616 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4617 GST_OBJECT_CAST (element), event)) {
4618 gst_event_unref (event);
4623 gst_event_unref (event);
4627 /* takes ownership of the passed event */
4629 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4631 gboolean ret = TRUE;
4634 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4635 GST_EVENT_TYPE_NAME (event));
4637 for (i = 0; i < demux->num_streams; ++i) {
4638 gst_event_ref (event);
4639 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4641 gst_event_unref (event);
4646 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4650 gboolean res = FALSE;
4652 demux = GST_ASF_DEMUX (parent);
4654 GST_DEBUG ("handling %s query",
4655 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4657 switch (GST_QUERY_TYPE (query)) {
4658 case GST_QUERY_DURATION:
4662 gst_query_parse_duration (query, &format, NULL);
4664 if (format != GST_FORMAT_TIME) {
4665 GST_LOG ("only support duration queries in TIME format");
4669 res = gst_pad_query_default (pad, parent, query);
4671 GST_OBJECT_LOCK (demux);
4673 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4674 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4675 GST_TIME_ARGS (demux->segment.duration));
4677 gst_query_set_duration (query, GST_FORMAT_TIME,
4678 demux->segment.duration);
4682 GST_LOG ("duration not known yet");
4685 GST_OBJECT_UNLOCK (demux);
4690 case GST_QUERY_POSITION:{
4693 gst_query_parse_position (query, &format, NULL);
4695 if (format != GST_FORMAT_TIME) {
4696 GST_LOG ("only support position queries in TIME format");
4700 GST_OBJECT_LOCK (demux);
4702 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4703 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4704 GST_TIME_ARGS (demux->segment.position));
4706 gst_query_set_position (query, GST_FORMAT_TIME,
4707 demux->segment.position);
4711 GST_LOG ("position not known yet");
4714 GST_OBJECT_UNLOCK (demux);
4718 case GST_QUERY_SEEKING:{
4721 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4722 if (format == GST_FORMAT_TIME) {
4725 GST_OBJECT_LOCK (demux);
4726 duration = demux->segment.duration;
4727 GST_OBJECT_UNLOCK (demux);
4729 if (!demux->streaming || !demux->seekable) {
4730 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4737 /* try upstream first in TIME */
4738 res = gst_pad_query_default (pad, parent, query);
4740 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4741 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4742 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4743 /* if no luck, maybe in BYTES */
4744 if (!seekable || fmt != GST_FORMAT_TIME) {
4747 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4748 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4749 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4750 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4751 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4752 if (fmt != GST_FORMAT_BYTES)
4755 gst_query_unref (q);
4756 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4762 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4766 case GST_QUERY_LATENCY:
4769 GstClockTime min, max;
4771 /* preroll delay does not matter in non-live pipeline,
4772 * but we might end up in a live (rtsp) one ... */
4775 res = gst_pad_query_default (pad, parent, query);
4779 gst_query_parse_latency (query, &live, &min, &max);
4781 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4782 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4783 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4785 GST_OBJECT_LOCK (demux);
4786 min += demux->latency;
4788 max += demux->latency;
4789 GST_OBJECT_UNLOCK (demux);
4791 gst_query_set_latency (query, live, min, max);
4794 case GST_QUERY_SEGMENT:
4799 format = demux->segment.format;
4802 gst_segment_to_stream_time (&demux->segment, format,
4803 demux->segment.start);
4804 if ((stop = demux->segment.stop) == -1)
4805 stop = demux->segment.duration;
4807 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4809 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4814 res = gst_pad_query_default (pad, parent, query);
4821 static GstStateChangeReturn
4822 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4824 GstASFDemux *demux = GST_ASF_DEMUX (element);
4825 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4827 switch (transition) {
4828 case GST_STATE_CHANGE_NULL_TO_READY:{
4829 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4830 demux->need_newsegment = TRUE;
4831 demux->segment_running = FALSE;
4832 demux->keyunit_sync = FALSE;
4833 demux->accurate = FALSE;
4834 demux->adapter = gst_adapter_new ();
4835 demux->metadata = gst_caps_new_empty ();
4836 demux->global_metadata = gst_structure_new_empty ("metadata");
4837 demux->data_size = 0;
4838 demux->data_offset = 0;
4839 demux->index_offset = 0;
4840 demux->base_offset = 0;
4841 demux->flowcombiner = gst_flow_combiner_new ();
4849 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4850 if (ret == GST_STATE_CHANGE_FAILURE)
4853 switch (transition) {
4854 case GST_STATE_CHANGE_PAUSED_TO_READY:
4855 gst_asf_demux_reset (demux, FALSE);
4858 case GST_STATE_CHANGE_READY_TO_NULL:
4859 gst_asf_demux_reset (demux, FALSE);
4860 gst_flow_combiner_free (demux->flowcombiner);
4861 demux->flowcombiner = NULL;