1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <gst/video/video.h>
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS ("video/x-ms-asf")
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE (16+8)
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA 99
76 #define gst_asf_get_flow_name(flow) \
77 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
78 "need-more-data" : gst_flow_get_name (flow)
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83 GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89 GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98 GstObject * parent, GstPadMode mode, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
103 GstFlowReturn * pflow);
104 static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109 AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
123 GstElementClass *gstelement_class;
125 gstelement_class = (GstElementClass *) klass;
127 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
129 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 gst_element_class_add_static_pad_template (gstelement_class,
132 &audio_src_template);
133 gst_element_class_add_static_pad_template (gstelement_class,
134 &video_src_template);
135 gst_element_class_add_static_pad_template (gstelement_class,
136 &gst_asf_demux_sink_template);
138 gstelement_class->change_state =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140 gstelement_class->send_event =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 gst_caps_replace (&stream->caps, NULL);
148 if (stream->pending_tags) {
149 gst_tag_list_unref (stream->pending_tags);
150 stream->pending_tags = NULL;
152 if (stream->streamheader) {
153 gst_buffer_unref (stream->streamheader);
154 stream->streamheader = NULL;
157 if (stream->active) {
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
161 gst_object_unref (stream->pad);
165 if (stream->payloads) {
166 while (stream->payloads->len > 0) {
170 last = stream->payloads->len - 1;
171 payload = &g_array_index (stream->payloads, AsfPayload, last);
172 gst_buffer_replace (&payload->buf, NULL);
173 g_array_remove_index (stream->payloads, last);
175 g_array_free (stream->payloads, TRUE);
176 stream->payloads = NULL;
179 if (stream->payloads_rev) {
180 while (stream->payloads_rev->len > 0) {
184 last = stream->payloads_rev->len - 1;
185 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186 gst_buffer_replace (&payload->buf, NULL);
187 g_array_remove_index (stream->payloads_rev, last);
189 g_array_free (stream->payloads_rev, TRUE);
190 stream->payloads_rev = NULL;
193 if (stream->ext_props.valid) {
194 g_free (stream->ext_props.payload_extensions);
195 stream->ext_props.payload_extensions = NULL;
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
202 GST_LOG_OBJECT (demux, "resetting");
204 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205 demux->segment_running = FALSE;
206 if (demux->adapter && !chain_reset) {
207 gst_adapter_clear (demux->adapter);
208 g_object_unref (demux->adapter);
209 demux->adapter = NULL;
211 if (demux->taglist) {
212 gst_tag_list_unref (demux->taglist);
213 demux->taglist = NULL;
215 if (demux->metadata) {
216 gst_caps_unref (demux->metadata);
217 demux->metadata = NULL;
219 if (demux->global_metadata) {
220 gst_structure_free (demux->global_metadata);
221 demux->global_metadata = NULL;
223 if (demux->mut_ex_streams) {
224 g_slist_free (demux->mut_ex_streams);
225 demux->mut_ex_streams = NULL;
228 demux->state = GST_ASF_DEMUX_STATE_HEADER;
229 g_free (demux->objpath);
230 demux->objpath = NULL;
231 g_strfreev (demux->languages);
232 demux->languages = NULL;
233 demux->num_languages = 0;
234 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
236 g_slist_free (demux->ext_stream_props);
237 demux->ext_stream_props = NULL;
239 while (demux->old_num_streams > 0) {
240 gst_asf_demux_free_stream (demux,
241 &demux->old_stream[demux->old_num_streams - 1]);
242 --demux->old_num_streams;
244 memset (demux->old_stream, 0, sizeof (demux->old_stream));
245 demux->old_num_streams = 0;
247 /* when resetting for a new chained asf, we don't want to remove the pads
248 * before adding the new ones */
250 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251 demux->old_num_streams = demux->num_streams;
252 demux->num_streams = 0;
255 while (demux->num_streams > 0) {
256 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257 --demux->num_streams;
259 memset (demux->stream, 0, sizeof (demux->stream));
261 /* do not remove those for not adding pads with same name */
262 demux->num_audio_streams = 0;
263 demux->num_video_streams = 0;
264 demux->have_group_id = FALSE;
265 demux->group_id = G_MAXUINT;
267 demux->num_streams = 0;
268 demux->activated_streams = FALSE;
269 demux->first_ts = GST_CLOCK_TIME_NONE;
270 demux->segment_ts = GST_CLOCK_TIME_NONE;
273 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274 demux->state = GST_ASF_DEMUX_STATE_HEADER;
275 demux->seekable = FALSE;
276 demux->broadcast = FALSE;
277 demux->sidx_interval = 0;
278 demux->sidx_num_entries = 0;
279 g_free (demux->sidx_entries);
280 demux->sidx_entries = NULL;
282 demux->speed_packets = 1;
284 demux->asf_3D_mode = GST_ASF_3D_NONE;
287 GST_LOG_OBJECT (demux, "Restarting");
288 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289 demux->need_newsegment = TRUE;
290 demux->segment_seqnum = 0;
291 demux->segment_running = FALSE;
292 demux->keyunit_sync = FALSE;
293 demux->accurate = FALSE;
294 demux->metadata = gst_caps_new_empty ();
295 demux->global_metadata = gst_structure_new_empty ("metadata");
296 demux->data_size = 0;
297 demux->data_offset = 0;
298 demux->index_offset = 0;
300 demux->base_offset = 0;
303 g_slist_free (demux->other_streams);
304 demux->other_streams = NULL;
308 gst_asf_demux_init (GstASFDemux * demux)
311 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312 gst_pad_set_chain_function (demux->sinkpad,
313 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314 gst_pad_set_event_function (demux->sinkpad,
315 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316 gst_pad_set_activate_function (demux->sinkpad,
317 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318 gst_pad_set_activatemode_function (demux->sinkpad,
319 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
322 /* set initial state */
323 gst_asf_demux_reset (demux, FALSE);
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
332 query = gst_query_new_scheduling ();
334 if (!gst_pad_peer_query (sinkpad, query)) {
335 gst_query_unref (query);
339 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341 gst_query_unref (query);
346 GST_DEBUG_OBJECT (sinkpad, "activating pull");
347 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
351 GST_DEBUG_OBJECT (sinkpad, "activating push");
352 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358 GstPadMode mode, gboolean active)
363 demux = GST_ASF_DEMUX (parent);
366 case GST_PAD_MODE_PUSH:
367 demux->state = GST_ASF_DEMUX_STATE_HEADER;
368 demux->streaming = TRUE;
371 case GST_PAD_MODE_PULL:
373 demux->state = GST_ASF_DEMUX_STATE_HEADER;
374 demux->streaming = FALSE;
376 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
379 res = gst_pad_stop_task (sinkpad);
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
395 demux = GST_ASF_DEMUX (parent);
397 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398 switch (GST_EVENT_TYPE (event)) {
399 case GST_EVENT_SEGMENT:{
400 const GstSegment *segment;
402 gst_event_parse_segment (event, &segment);
404 if (segment->format == GST_FORMAT_BYTES) {
405 if (demux->packet_size && segment->start > demux->data_offset)
406 demux->packet = (segment->start - demux->data_offset) /
410 } else if (segment->format == GST_FORMAT_TIME) {
411 /* do not know packet position, not really a problem */
414 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415 gst_event_unref (event);
419 /* record upstream segment for interpolation */
420 if (segment->format != demux->in_segment.format)
421 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422 gst_segment_copy_into (segment, &demux->in_segment);
424 /* in either case, clear some state and generate newsegment later on */
425 GST_OBJECT_LOCK (demux);
426 demux->segment_ts = GST_CLOCK_TIME_NONE;
427 demux->in_gap = GST_CLOCK_TIME_NONE;
428 demux->need_newsegment = TRUE;
429 demux->segment_seqnum = gst_event_get_seqnum (event);
430 gst_asf_demux_reset_stream_state_after_discont (demux);
431 /* if we seek back after reaching EOS, go back to packet reading state */
432 if (demux->data_offset > 0 && segment->start >= demux->data_offset
433 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
434 demux->state = GST_ASF_DEMUX_STATE_DATA;
436 GST_OBJECT_UNLOCK (demux);
438 gst_event_unref (event);
444 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
446 (_("This stream contains no data.")),
447 ("got eos and didn't receive a complete header object"));
450 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
451 if (!demux->activated_streams) {
452 /* If we still haven't got activated streams, the file is most likely corrupt */
453 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
454 (_("This stream contains no data.")),
455 ("got eos and didn't receive a complete header object"));
458 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
459 GST_ELEMENT_FLOW_ERROR (demux, flow);
463 GST_OBJECT_LOCK (demux);
464 gst_adapter_clear (demux->adapter);
465 GST_OBJECT_UNLOCK (demux);
466 gst_asf_demux_send_event_unlocked (demux, event);
470 case GST_EVENT_FLUSH_STOP:
471 GST_OBJECT_LOCK (demux);
472 gst_asf_demux_reset_stream_state_after_discont (demux);
473 GST_OBJECT_UNLOCK (demux);
474 gst_asf_demux_send_event_unlocked (demux, event);
475 /* upon activation, latency is no longer introduced, e.g. after seek */
476 if (demux->activated_streams)
481 ret = gst_pad_event_default (pad, parent, event);
489 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
490 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
491 gboolean next, gboolean * eos)
493 GstClockTime idx_time;
499 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
502 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
505 /* if we want the next keyframe, we have to go forward till we find
506 a different packet number */
508 if (idx >= demux->sidx_num_entries - 1) {
509 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
514 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
515 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
522 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
528 *packet = demux->sidx_entries[idx].packet;
530 *speed = demux->sidx_entries[idx].count;
532 /* so we get closer to the actual time of the packet ... actually, let's not
533 * do this, since we throw away superfluous payloads before the seek position
534 * anyway; this way, our key unit seek 'snap resolution' is a bit better
535 * (ie. same as index resolution) */
537 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
541 idx_time = demux->sidx_interval * idx;
542 if (G_LIKELY (idx_time >= demux->preroll))
543 idx_time -= demux->preroll;
545 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
546 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
547 GST_TIME_ARGS (idx_time));
549 if (G_LIKELY (p_idx_time))
550 *p_idx_time = idx_time;
556 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
560 gst_adapter_clear (demux->adapter);
562 GST_DEBUG_OBJECT (demux, "reset stream state");
564 gst_flow_combiner_reset (demux->flowcombiner);
565 for (n = 0; n < demux->num_streams; n++) {
566 demux->stream[n].discont = TRUE;
567 demux->stream[n].first_buffer = TRUE;
569 while (demux->stream[n].payloads->len > 0) {
573 last = demux->stream[n].payloads->len - 1;
574 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
575 gst_buffer_replace (&payload->buf, NULL);
576 g_array_remove_index (demux->stream[n].payloads, last);
582 gst_asf_demux_mark_discont (GstASFDemux * demux)
586 GST_DEBUG_OBJECT (demux, "Mark stream discont");
588 for (n = 0; n < demux->num_streams; n++)
589 demux->stream[n].discont = TRUE;
592 /* do a seek in push based mode */
594 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
599 GstSeekType cur_type, stop_type;
603 GstEvent *byte_event;
605 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
608 stop_type = GST_SEEK_TYPE_NONE;
611 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
613 /* determine packet, by index or by estimation */
614 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
617 (guint) gst_util_uint64_scale (demux->num_packets, cur,
621 if (packet > demux->num_packets) {
622 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
627 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
629 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
631 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
632 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
633 /* BYTE seek event */
634 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
635 cur, stop_type, stop);
636 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
637 res = gst_pad_push_event (demux->sinkpad, byte_event);
643 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
645 GstClockTime idx_time;
648 GstSeekType cur_type, stop_type;
650 gboolean only_need_update;
651 gboolean after, before, next;
656 guint packet, speed_count = 1;
662 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
665 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
666 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
670 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
671 * so first try to let it handle the seek event. */
672 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
675 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
676 demux->num_packets == 0 || demux->play_time == 0)) {
677 GST_LOG_OBJECT (demux, "stream is not seekable");
681 if (G_UNLIKELY (!demux->activated_streams)) {
682 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
686 if (G_UNLIKELY (rate <= 0.0)) {
687 GST_LOG_OBJECT (demux, "backward playback");
688 demux->seek_to_cur_pos = TRUE;
689 for (i = 0; i < demux->num_streams; i++) {
690 demux->stream[i].reverse_kf_ready = FALSE;
694 seqnum = gst_event_get_seqnum (event);
695 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
697 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
698 demux->keyunit_sync =
699 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
700 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
701 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
702 next = after && !before;
704 if (G_UNLIKELY (demux->streaming)) {
705 /* support it safely needs more segment handling, e.g. closing etc */
707 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
710 /* we can (re)construct the start later on, but not the end */
711 if (stop_type != GST_SEEK_TYPE_NONE &&
712 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
713 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
716 return gst_asf_demux_handle_seek_push (demux, event);
719 /* unlock the streaming thread */
720 if (G_LIKELY (flush)) {
721 fevent = gst_event_new_flush_start ();
723 gst_event_set_seqnum (fevent, seqnum);
724 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
725 gst_asf_demux_send_event_unlocked (demux, fevent);
727 gst_pad_pause_task (demux->sinkpad);
730 /* grab the stream lock so that streaming cannot continue, for
731 * non flushing seeks when the element is in PAUSED this could block
733 GST_PAD_STREAM_LOCK (demux->sinkpad);
735 /* we now can stop flushing, since we have the stream lock now */
736 fevent = gst_event_new_flush_stop (TRUE);
737 gst_event_set_seqnum (fevent, seqnum);
738 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
740 if (G_LIKELY (flush))
741 gst_asf_demux_send_event_unlocked (demux, fevent);
743 gst_event_unref (fevent);
745 /* operating on copy of segment until we know the seek worked */
746 segment = demux->segment;
748 if (G_UNLIKELY (demux->segment_running && !flush)) {
749 GstSegment newsegment;
752 /* create the segment event to close the current segment */
753 gst_segment_copy_into (&segment, &newsegment);
754 newseg = gst_event_new_segment (&newsegment);
755 gst_event_set_seqnum (newseg, seqnum);
757 gst_asf_demux_send_event_unlocked (demux, newseg);
760 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
761 cur, stop_type, stop, &only_need_update);
763 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
764 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
766 if (cur_type != GST_SEEK_TYPE_SET)
767 seek_time = segment.start;
771 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
772 * real start of data and segment_start to indexed time for key unit seek*/
773 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
774 &idx_time, &speed_count, next, &eos))) {
778 demux->packet = demux->num_packets;
782 /* First try to query our source to see if it can convert for us. This is
783 the case when our source is an mms stream, notice that in this case
784 gstmms will do a time based seek to get the byte offset, this is not a
785 problem as the seek to this offset needs to happen anway. */
786 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
787 GST_FORMAT_BYTES, &offset)) {
788 packet = (offset - demux->data_offset) / demux->packet_size;
789 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
790 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
791 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
792 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
793 demux->packet_size, packet);
795 /* FIXME: For streams containing video, seek to an earlier position in
796 * the hope of hitting a keyframe and let the sinks throw away the stuff
797 * before the segment start. For audio-only this is unnecessary as every
799 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
800 && demux->num_video_streams > 0) {
801 seek_time -= 5 * GST_SECOND;
806 packet = (guint) gst_util_uint64_scale (demux->num_packets,
807 seek_time, demux->play_time);
809 if (packet > demux->num_packets)
810 packet = demux->num_packets;
813 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
814 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
815 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
816 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
817 segment.start = idx_time;
818 segment.position = idx_time;
819 segment.time = idx_time;
823 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
825 GST_OBJECT_LOCK (demux);
826 demux->segment = segment;
827 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
828 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
829 stop, demux->play_time);
831 demux->packet = packet;
834 demux->need_newsegment = TRUE;
835 demux->segment_seqnum = seqnum;
836 demux->speed_packets =
837 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
838 gst_asf_demux_reset_stream_state_after_discont (demux);
839 GST_OBJECT_UNLOCK (demux);
842 /* restart our task since it might have been stopped when we did the flush */
843 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
846 /* streaming can continue now */
847 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
853 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
859 demux = GST_ASF_DEMUX (parent);
861 switch (GST_EVENT_TYPE (event)) {
863 GST_LOG_OBJECT (pad, "seek event");
864 ret = gst_asf_demux_handle_seek_event (demux, event);
865 gst_event_unref (event);
868 case GST_EVENT_NAVIGATION:
869 /* just drop these two silently */
870 gst_event_unref (event);
874 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
875 ret = gst_pad_event_default (pad, parent, event);
882 static inline guint32
883 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
887 ret = gst_asf_identify_guid (guids, guid);
889 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
890 gst_asf_get_guid_nick (guids, ret),
891 guid->v1, guid->v2, guid->v3, guid->v4);
903 /* Peek for an object.
905 * Returns FALSE is the object is corrupted (such as the reported
906 * object size being greater than 2**32bits.
909 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
910 guint data_len, AsfObject * object, gboolean expect)
914 /* Callers should have made sure that data_len is big enough */
915 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
917 if (data_len < ASF_OBJECT_HEADER_SIZE)
920 guid.v1 = GST_READ_UINT32_LE (data + 0);
921 guid.v2 = GST_READ_UINT32_LE (data + 4);
922 guid.v3 = GST_READ_UINT32_LE (data + 8);
923 guid.v4 = GST_READ_UINT32_LE (data + 12);
925 /* FIXME: make asf_demux_identify_object_guid() */
926 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
927 if (object->id == ASF_OBJ_UNDEFINED && expect) {
928 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
929 guid.v1, guid.v2, guid.v3, guid.v4);
932 object->size = GST_READ_UINT64_LE (data + 16);
933 if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
934 GST_WARNING_OBJECT (demux,
935 "ASF Object size corrupted (greater than 32bit)");
944 gst_asf_demux_release_old_pads (GstASFDemux * demux)
946 GST_DEBUG_OBJECT (demux, "Releasing old pads");
948 while (demux->old_num_streams > 0) {
949 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
950 gst_event_new_eos ());
951 gst_asf_demux_free_stream (demux,
952 &demux->old_stream[demux->old_num_streams - 1]);
953 --demux->old_num_streams;
955 memset (demux->old_stream, 0, sizeof (demux->old_stream));
956 demux->old_num_streams = 0;
960 gst_asf_demux_chain_headers (GstASFDemux * demux)
963 guint8 *header_data, *data = NULL;
964 const guint8 *cdata = NULL;
966 GstFlowReturn flow = GST_FLOW_OK;
968 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
972 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
974 if (obj.id != ASF_OBJ_HEADER)
977 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
979 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
980 if (gst_adapter_available (demux->adapter) < obj.size + 50)
983 data = gst_adapter_take (demux->adapter, obj.size + 50);
986 header_size = obj.size;
987 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
988 if (flow != GST_FLOW_OK)
991 /* calculate where the packet data starts */
992 demux->data_offset = obj.size + 50;
994 /* now parse the beginning of the ASF_OBJ_DATA object */
995 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
998 if (demux->num_streams == 0)
1007 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1014 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1015 ("This doesn't seem to be an ASF file"));
1017 return GST_FLOW_ERROR;
1022 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1023 ("header parsing failed, or no streams found, flow = %s",
1024 gst_flow_get_name (flow)));
1026 return GST_FLOW_ERROR;
1031 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1032 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1037 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1040 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1042 if (G_LIKELY (p_flow))
1045 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1046 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1047 "+%u", gst_flow_get_name (flow), offset, size);
1052 g_assert (*p_buf != NULL);
1054 buffer_size = gst_buffer_get_size (*p_buf);
1055 if (G_UNLIKELY (buffer_size < size)) {
1056 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1057 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1058 gst_buffer_unref (*p_buf);
1059 if (G_LIKELY (p_flow))
1060 *p_flow = GST_FLOW_EOS;
1068 static GstFlowReturn
1069 gst_asf_demux_pull_indices (GstASFDemux * demux)
1071 GstBuffer *buf = NULL;
1074 GstFlowReturn ret = GST_FLOW_OK;
1076 offset = demux->index_offset;
1078 if (G_UNLIKELY (offset == 0)) {
1079 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1084 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1090 gst_buffer_map (buf, &map, GST_MAP_READ);
1091 g_assert (map.size >= 16 + 8);
1092 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1093 GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
1094 GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
1096 gst_buffer_unmap (buf, &map);
1097 gst_buffer_replace (&buf, NULL);
1098 /* Non-fatal, return */
1101 gst_buffer_unmap (buf, &map);
1102 gst_buffer_replace (&buf, NULL);
1104 /* check for sanity */
1105 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1106 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1110 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1114 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1115 ", size %u", offset, (guint) obj.size);
1117 offset += obj.size; /* increase before _process_object changes it */
1119 gst_buffer_map (buf, &map, GST_MAP_READ);
1120 g_assert (map.size >= obj.size);
1121 bufdata = (guint8 *) map.data;
1122 obj_size = obj.size;
1123 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1124 gst_buffer_unmap (buf, &map);
1125 gst_buffer_replace (&buf, NULL);
1127 if (ret == ASF_FLOW_NEED_MORE_DATA) {
1128 /* Since indices are at the end of the file, if we need more data,
1129 * we consider it as a non-fatal corrupted index */
1134 if (G_UNLIKELY (ret != GST_FLOW_OK))
1140 GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
1141 gst_flow_get_name (ret));
1146 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1150 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1151 GST_WARNING_OBJECT (demux, "Corrupted data");
1154 if (obj.id != ASF_OBJ_DATA) {
1155 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1159 demux->state = GST_ASF_DEMUX_STATE_DATA;
1161 if (!demux->broadcast && obj.size > 50) {
1162 demux->data_size = obj.size - 50;
1163 /* CHECKME: for at least one file this is off by +158 bytes?! */
1164 demux->index_offset = demux->data_offset + demux->data_size;
1166 demux->data_size = 0;
1167 demux->index_offset = 0;
1172 if (!demux->broadcast) {
1173 /* skip object header (24 bytes) and file GUID (16 bytes) */
1174 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1176 demux->num_packets = 0;
1179 if (demux->num_packets == 0)
1180 demux->seekable = FALSE;
1182 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1183 if (demux->data_size == 0 && demux->num_packets > 0) {
1184 demux->data_size = demux->num_packets * demux->packet_size;
1185 demux->index_offset = demux->data_offset + demux->data_size;
1188 /* process pending stream objects and create pads for those */
1189 gst_asf_demux_process_queued_extended_stream_objects (demux);
1191 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1192 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1193 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1194 demux->data_offset, demux->data_size, demux->index_offset);
1200 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1202 GstFlowReturn flow = GST_FLOW_OK;
1204 GstBuffer *buf = NULL;
1209 GST_LOG_OBJECT (demux, "reading headers");
1211 /* pull HEADER object header, so we know its size */
1212 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1215 gst_buffer_map (buf, &map, GST_MAP_READ);
1216 g_assert (map.size >= 16 + 8);
1217 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1218 gst_buffer_unmap (buf, &map);
1219 gst_buffer_replace (&buf, NULL);
1220 flow = GST_FLOW_ERROR;
1223 gst_buffer_unmap (buf, &map);
1224 gst_buffer_replace (&buf, NULL);
1226 if (obj.id != ASF_OBJ_HEADER)
1229 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1231 /* pull HEADER object */
1232 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1236 size = obj.size; /* don't want obj.size changed */
1237 gst_buffer_map (buf, &map, GST_MAP_READ);
1238 g_assert (map.size >= size);
1239 bufdata = (guint8 *) map.data;
1240 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1241 gst_buffer_unmap (buf, &map);
1242 gst_buffer_replace (&buf, NULL);
1244 if (flow != GST_FLOW_OK) {
1245 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1249 /* calculate where the packet data starts */
1250 demux->data_offset = demux->base_offset + obj.size + 50;
1252 /* now pull beginning of DATA object before packet data */
1253 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1257 gst_buffer_map (buf, &map, GST_MAP_READ);
1258 g_assert (map.size >= size);
1259 bufdata = (guint8 *) map.data;
1260 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1263 if (demux->num_streams == 0)
1266 gst_buffer_unmap (buf, &map);
1267 gst_buffer_replace (&buf, NULL);
1275 gst_buffer_unmap (buf, &map);
1276 gst_buffer_replace (&buf, NULL);
1278 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1279 ("This doesn't seem to be an ASF file"));
1280 *pflow = GST_FLOW_ERROR;
1285 flow = GST_FLOW_ERROR;
1286 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1287 ("header parsing failed, or no streams found, flow = %s",
1288 gst_flow_get_name (flow)));
1293 gst_buffer_unmap (buf, &map);
1294 gst_buffer_replace (&buf, NULL);
1295 if (flow == ASF_FLOW_NEED_MORE_DATA)
1296 flow = GST_FLOW_ERROR;
1303 all_streams_prerolled (GstASFDemux * demux)
1305 GstClockTime preroll_time;
1306 guint i, num_no_data = 0;
1307 AsfStreamType prerolled_types = 0, all_types = 0;
1309 /* Allow at least 500ms of preroll_time */
1310 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1312 /* returns TRUE as long as there isn't a stream which (a) has data queued
1313 * and (b) the timestamp of last piece of data queued is < demux->preroll
1314 * AND there is at least one other stream with data queued */
1315 for (i = 0; i < demux->num_streams; ++i) {
1316 AsfPayload *last_payload = NULL;
1320 stream = &demux->stream[i];
1322 all_types |= stream->type;
1324 if (G_UNLIKELY (stream->payloads->len == 0)) {
1326 GST_LOG_OBJECT (stream->pad, "no data queued");
1330 prerolled_types |= stream->type;
1332 /* find last payload with timestamp */
1333 for (last_idx = stream->payloads->len - 1;
1334 last_idx >= 0 && (last_payload == NULL
1335 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1336 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1339 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1340 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1341 GST_TIME_ARGS (preroll_time));
1342 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1343 || last_payload->ts <= preroll_time)) {
1344 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1349 GST_LOG_OBJECT (demux, "all_types:%d prerolled_types:%d",
1350 all_types, prerolled_types);
1352 /* If streams of each present type have prerolled, we are good to go */
1353 if (all_types != 0 && prerolled_types == all_types)
1356 if (G_UNLIKELY (num_no_data > 0))
1364 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1369 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1372 /* check for each mutual exclusion group whether it affects this stream */
1373 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1374 if (*mes == stream->id) {
1375 /* we are in this group; let's check if we've already activated streams
1376 * that are in the same group (and hence mutually exclusive to this
1378 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1381 for (i = 0; i < demux->num_streams; ++i) {
1382 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1383 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1384 "to already active stream with ID %d", stream->id,
1385 demux->stream[i].id);
1390 /* we can only be in this group once, let's break out and move on to
1391 * the next mutual exclusion group */
1402 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1404 /* remember the first queued timestamp for the segment */
1405 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1406 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1407 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1408 GST_TIME_ARGS (demux->first_ts));
1409 demux->segment_ts = payload_ts;
1410 /* always note, but only determines segment when streaming */
1411 if (demux->streaming)
1412 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1413 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1414 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1419 gst_asf_demux_get_first_ts (GstASFDemux * demux)
1421 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1422 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1425 /* go trhough each stream, find smallest timestamp */
1426 for (i = 0; i < demux->num_streams; ++i) {
1429 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1430 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1431 stream = &demux->stream[i];
1433 for (j = 0; j < stream->payloads->len; ++j) {
1434 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1435 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1436 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1437 || stream_min_ts > payload->ts)) {
1438 stream_min_ts = payload->ts;
1440 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1441 payload->ts > stream_min_ts &&
1442 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1443 || stream_min_ts2 > payload->ts)) {
1444 stream_min_ts2 = payload->ts;
1448 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1449 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1450 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1451 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1452 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1454 GST_DEBUG_OBJECT (demux,
1455 "stream #%u stream_min_ts %" GST_TIME_FORMAT " stream_min_ts2 %"
1456 GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (stream_min_ts),
1457 GST_TIME_ARGS (stream_min_ts2));
1459 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1460 stream_min_ts = stream_min_ts2;
1462 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1463 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1464 first_ts = stream_min_ts;
1467 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen */
1470 demux->first_ts = first_ts;
1472 /* update packets queued before we knew first timestamp */
1473 for (i = 0; i < demux->num_streams; ++i) {
1476 stream = &demux->stream[i];
1478 for (j = 0; j < stream->payloads->len; ++j) {
1479 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1480 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1481 if (payload->ts > first_ts)
1482 payload->ts -= first_ts;
1490 gst_asf_demux_check_segment_ts (demux, 0);
1496 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1498 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1499 and often set wrong, inspecting the data is the only way that seem to be working */
1500 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1501 GstCaps *caps = NULL;
1503 GstAdapter *adapter = gst_adapter_new ();
1505 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1507 AsfPayload *payload;
1510 payload = &g_array_index (stream->payloads, AsfPayload, i);
1511 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1512 len = gst_adapter_available (adapter);
1513 data = gst_adapter_map (adapter, len);
1517 #define MIN_LENGTH 128
1519 /* look for the sync points */
1521 if (len < MIN_LENGTH || /* give typefind something to work on */
1522 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1523 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1529 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1532 if (prob < GST_TYPE_FIND_LIKELY) {
1535 if (len > MIN_LENGTH)
1536 /* this wasn't it, look for another sync point */
1540 gst_adapter_unmap (adapter);
1543 gst_object_unref (adapter);
1546 gst_caps_take (&stream->caps, caps);
1554 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1556 guint i, actual_streams = 0;
1558 if (demux->activated_streams)
1561 if (!all_streams_prerolled (demux) && !force) {
1562 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1566 if (G_UNLIKELY (!gst_asf_demux_get_first_ts (demux)))
1569 for (i = 0; i < demux->num_streams; ++i) {
1570 AsfStream *stream = &demux->stream[i];
1572 if (stream->payloads->len > 0) {
1574 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1575 !stream->active && /* do not inspect active streams (caps were already set) */
1576 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1577 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1578 /* try to gather some more data */
1581 /* we don't check mutual exclusion stuff here; either we have data for
1582 * a stream, then we active it, or we don't, then we'll ignore it */
1583 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1584 gst_asf_demux_activate_stream (demux, stream);
1585 actual_streams += 1;
1587 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1591 if (actual_streams == 0) {
1592 /* We don't have any streams activated ! */
1593 GST_ERROR_OBJECT (demux, "No streams activated!");
1597 gst_asf_demux_release_old_pads (demux);
1599 demux->activated_streams = TRUE;
1600 GST_LOG_OBJECT (demux, "signalling no more pads");
1601 gst_element_no_more_pads (GST_ELEMENT (demux));
1605 /* returns the stream that has a complete payload with the lowest timestamp
1606 * queued, or NULL (we push things by timestamp because during the internal
1607 * prerolling we might accumulate more data then the external queues can take,
1608 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1610 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1612 AsfPayload *best_payload = NULL;
1613 AsfStream *best_stream = NULL;
1616 for (i = 0; i < demux->num_streams; ++i) {
1620 stream = &demux->stream[i];
1622 /* Don't push any data until we have at least one payload that falls within
1623 * the current segment. This way we can remove out-of-segment payloads that
1624 * don't need to be decoded after a seek, sending only data from the
1625 * keyframe directly before our segment start */
1626 if (stream->payloads->len > 0) {
1627 AsfPayload *payload = NULL;
1630 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1631 /* Reverse playback */
1633 if (stream->is_video) {
1634 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1635 if (stream->reverse_kf_ready) {
1637 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1638 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1639 /* TODO : remove payload from the list? */
1646 /* find first complete payload with timestamp */
1647 for (j = stream->payloads->len - 1;
1648 j >= 0 && (payload == NULL
1649 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1650 payload = &g_array_index (stream->payloads, AsfPayload, j);
1653 /* If there's a complete payload queued for this stream */
1654 if (!gst_asf_payload_is_complete (payload))
1660 /* find last payload with timestamp */
1661 for (last_idx = stream->payloads->len - 1;
1662 last_idx >= 0 && (payload == NULL
1663 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1664 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1667 /* if this is first payload after seek we might need to update the segment */
1668 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1669 gst_asf_demux_check_segment_ts (demux, payload->ts);
1671 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1672 (payload->ts < demux->segment.start))) {
1673 if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
1674 && payload->keyframe)) {
1675 GST_DEBUG_OBJECT (stream->pad,
1676 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1677 GST_TIME_ARGS (payload->ts));
1678 demux->segment.start = payload->ts;
1679 demux->segment.time = payload->ts;
1681 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1682 GST_TIME_FORMAT " which is before our segment start %"
1683 GST_TIME_FORMAT ", not pushing yet",
1684 GST_TIME_ARGS (payload->ts),
1685 GST_TIME_ARGS (demux->segment.start));
1690 /* find first complete payload with timestamp */
1692 j < stream->payloads->len && (payload == NULL
1693 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1694 payload = &g_array_index (stream->payloads, AsfPayload, j);
1697 /* Now see if there's a complete payload queued for this stream */
1698 if (!gst_asf_payload_is_complete (payload))
1702 /* ... and whether its timestamp is lower than the current best */
1703 if (best_stream == NULL || best_payload->ts > payload->ts) {
1704 best_stream = stream;
1705 best_payload = payload;
1713 static GstFlowReturn
1714 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1717 GstFlowReturn ret = GST_FLOW_OK;
1719 if (G_UNLIKELY (!demux->activated_streams)) {
1720 if (!gst_asf_demux_check_activate_streams (demux, force))
1722 /* streams are now activated */
1725 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1726 AsfPayload *payload;
1727 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1728 GstClockTime duration = GST_CLOCK_TIME_NONE;
1730 /* wait until we had a chance to "lock on" some payload's timestamp */
1731 if (G_UNLIKELY (demux->need_newsegment
1732 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1735 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1736 && stream->payloads->len) {
1737 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1739 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1742 /* do we need to send a newsegment event */
1743 if ((G_UNLIKELY (demux->need_newsegment))) {
1744 GstEvent *segment_event;
1746 /* safe default if insufficient upstream info */
1747 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1750 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1751 demux->segment.duration > 0) {
1752 /* slight HACK; prevent clipping of last bit */
1753 demux->segment.stop = demux->segment.duration + demux->in_gap;
1756 /* FIXME : only if ACCURATE ! */
1757 if (G_LIKELY (demux->keyunit_sync && !demux->accurate
1758 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1759 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1760 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1761 GST_TIME_ARGS (payload->ts));
1762 demux->segment.start = payload->ts;
1763 demux->segment.time = payload->ts;
1766 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1769 /* note: we fix up all timestamps to start from 0, so this should be ok */
1770 segment_event = gst_event_new_segment (&demux->segment);
1771 if (demux->segment_seqnum)
1772 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1773 gst_asf_demux_send_event_unlocked (demux, segment_event);
1775 /* now post any global tags we may have found */
1776 if (demux->taglist == NULL) {
1777 demux->taglist = gst_tag_list_new_empty ();
1778 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1781 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1782 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1784 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1785 gst_asf_demux_send_event_unlocked (demux,
1786 gst_event_new_tag (demux->taglist));
1787 demux->taglist = NULL;
1789 demux->need_newsegment = FALSE;
1790 demux->segment_seqnum = 0;
1791 demux->segment_running = TRUE;
1794 /* Do we have tags pending for this stream? */
1795 if (G_UNLIKELY (stream->pending_tags)) {
1796 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1797 gst_pad_push_event (stream->pad,
1798 gst_event_new_tag (stream->pending_tags));
1799 stream->pending_tags = NULL;
1802 /* We have the whole packet now so we should push the packet to
1803 * the src pad now. First though we should check if we need to do
1805 if (G_UNLIKELY (stream->span > 1)) {
1806 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1809 payload->buf = gst_buffer_make_writable (payload->buf);
1811 if (G_LIKELY (!payload->keyframe)) {
1812 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1815 if (G_UNLIKELY (stream->discont)) {
1816 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1817 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1818 stream->discont = FALSE;
1821 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1822 (payload->par_x != stream->par_x) &&
1823 (payload->par_y != stream->par_y))) {
1824 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1825 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1826 stream->par_x = payload->par_x;
1827 stream->par_y = payload->par_y;
1828 stream->caps = gst_caps_make_writable (stream->caps);
1829 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1830 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1831 gst_pad_set_caps (stream->pad, stream->caps);
1834 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1835 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1836 payload->interlaced);
1837 stream->interlaced = payload->interlaced;
1838 stream->caps = gst_caps_make_writable (stream->caps);
1839 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1840 (stream->interlaced ? "mixed" : "progressive"), NULL);
1841 gst_pad_set_caps (stream->pad, stream->caps);
1844 /* (sort of) interpolate timestamps using upstream "frame of reference",
1845 * typically useful for live src, but might (unavoidably) mess with
1846 * position reporting if a live src is playing not so live content
1847 * (e.g. rtspsrc taking some time to fall back to tcp) */
1848 timestamp = payload->ts;
1849 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1850 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1851 timestamp += demux->in_gap;
1853 /* Check if we're after the segment already, if so no need to push
1855 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1856 GST_DEBUG_OBJECT (stream->pad,
1857 "Payload after segment stop %" GST_TIME_FORMAT,
1858 GST_TIME_ARGS (demux->segment.stop));
1860 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1862 gst_buffer_unref (payload->buf);
1863 payload->buf = NULL;
1864 g_array_remove_index (stream->payloads, 0);
1865 /* Break out as soon as we have an issue */
1866 if (G_UNLIKELY (ret != GST_FLOW_OK))
1873 GST_BUFFER_PTS (payload->buf) = timestamp;
1875 if (payload->duration == GST_CLOCK_TIME_NONE
1876 && stream->ext_props.avg_time_per_frame != 0) {
1877 duration = stream->ext_props.avg_time_per_frame * 100;
1879 duration = payload->duration;
1881 GST_BUFFER_DURATION (payload->buf) = duration;
1883 /* FIXME: we should really set durations on buffers if we can */
1885 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1888 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1889 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1890 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1892 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1893 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1897 if (stream->active) {
1898 if (G_UNLIKELY (stream->first_buffer)) {
1899 if (stream->streamheader != NULL) {
1900 GST_DEBUG_OBJECT (stream->pad,
1901 "Pushing streamheader before first buffer");
1902 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1904 stream->first_buffer = FALSE;
1907 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1908 && timestamp > demux->segment.position) {
1909 demux->segment.position = timestamp;
1910 if (GST_CLOCK_TIME_IS_VALID (duration))
1911 demux->segment.position += timestamp;
1914 ret = gst_pad_push (stream->pad, payload->buf);
1916 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1919 gst_buffer_unref (payload->buf);
1922 payload->buf = NULL;
1923 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1924 && stream->reverse_kf_ready) {
1925 g_array_remove_index (stream->payloads, stream->kf_pos);
1928 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1930 stream->reverse_kf_ready = FALSE;
1933 g_array_remove_index (stream->payloads, 0);
1936 /* Break out as soon as we have an issue */
1937 if (G_UNLIKELY (ret != GST_FLOW_OK))
1945 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1950 g_assert (buf != NULL);
1952 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1954 gst_buffer_map (buf, &map, GST_MAP_READ);
1956 /* we return false on buffer too small */
1957 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1958 gst_buffer_unmap (buf, &map);
1962 /* check if it is a header */
1964 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1966 gst_buffer_unmap (buf, &map);
1967 if (valid && obj.id == ASF_OBJ_HEADER) {
1974 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1976 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1977 GstFlowReturn ret = GST_FLOW_OK;
1978 GstBuffer *buf = NULL;
1979 gboolean header = FALSE;
1981 /* TODO maybe we should skip index objects after the data and look
1982 * further for a new header */
1983 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1984 g_assert (buf != NULL);
1985 /* check if it is a header */
1986 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1987 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1988 demux->base_offset = off;
1992 gst_buffer_unref (buf);
1999 gst_asf_demux_loop (GstASFDemux * demux)
2001 GstFlowReturn flow = GST_FLOW_OK;
2002 GstBuffer *buf = NULL;
2005 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
2006 if (!gst_asf_demux_pull_headers (demux, &flow)) {
2010 flow = gst_asf_demux_pull_indices (demux);
2011 if (flow != GST_FLOW_OK)
2015 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
2017 if (G_UNLIKELY (demux->num_packets != 0
2018 && demux->packet >= demux->num_packets))
2021 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2022 (guint) demux->num_packets);
2024 off = demux->data_offset + (demux->packet * demux->packet_size);
2026 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2027 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2028 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2029 if (flow == GST_FLOW_EOS) {
2031 } else if (flow == GST_FLOW_FLUSHING) {
2032 GST_DEBUG_OBJECT (demux, "Not fatal");
2039 if (G_LIKELY (demux->speed_packets == 1)) {
2040 GstAsfDemuxParsePacketError err;
2041 err = gst_asf_demux_parse_packet (demux, buf);
2042 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2043 /* when we don't know when the data object ends, we should check
2044 * for a chained asf */
2045 if (demux->num_packets == 0) {
2046 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2047 GST_INFO_OBJECT (demux, "Chained asf found");
2048 demux->base_offset = off;
2049 gst_asf_demux_reset (demux, TRUE);
2050 gst_buffer_unref (buf);
2054 /* FIXME: We should tally up fatal errors and error out only
2055 * after a few broken packets in a row? */
2057 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2058 gst_buffer_unref (buf);
2060 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2061 && !demux->seek_to_cur_pos) {
2063 if (demux->packet < 0) {
2073 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2075 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2076 && !demux->seek_to_cur_pos) {
2078 if (demux->packet < 0) {
2087 for (n = 0; n < demux->speed_packets; n++) {
2089 GstAsfDemuxParsePacketError err;
2092 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2093 n * demux->packet_size, demux->packet_size);
2094 err = gst_asf_demux_parse_packet (demux, sub);
2095 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2096 /* when we don't know when the data object ends, we should check
2097 * for a chained asf */
2098 if (demux->num_packets == 0) {
2099 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2100 GST_INFO_OBJECT (demux, "Chained asf found");
2101 demux->base_offset = off + n * demux->packet_size;
2102 gst_asf_demux_reset (demux, TRUE);
2103 gst_buffer_unref (sub);
2104 gst_buffer_unref (buf);
2108 /* FIXME: We should tally up fatal errors and error out only
2109 * after a few broken packets in a row? */
2111 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2115 gst_buffer_unref (sub);
2117 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2118 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2124 /* reset speed pull */
2125 demux->speed_packets = 1;
2128 gst_buffer_unref (buf);
2130 if (G_UNLIKELY ((demux->num_packets > 0
2131 && demux->packet >= demux->num_packets)
2132 || flow == GST_FLOW_EOS)) {
2133 GST_LOG_OBJECT (demux, "reached EOS");
2137 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2138 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2142 /* check if we're at the end of the configured segment */
2143 /* FIXME: check if segment end reached etc. */
2149 /* if we haven't activated our streams yet, this might be because we have
2150 * less data queued than required for preroll; force stream activation and
2151 * send any pending payloads before sending EOS */
2152 if (!demux->activated_streams)
2153 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2155 /* we want to push an eos or post a segment-done in any case */
2156 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2159 /* for segment playback we need to post when (in stream time)
2160 * we stopped, this is either stop (when set) or the duration. */
2161 if ((stop = demux->segment.stop) == -1)
2162 stop = demux->segment.duration;
2164 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2165 gst_element_post_message (GST_ELEMENT_CAST (demux),
2166 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2168 gst_asf_demux_send_event_unlocked (demux,
2169 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2170 } else if (flow != GST_FLOW_EOS) {
2171 /* check if we have a chained asf, in case, we don't eos yet */
2172 if (gst_asf_demux_check_chained_asf (demux)) {
2173 GST_INFO_OBJECT (demux, "Chained ASF starting");
2174 gst_asf_demux_reset (demux, TRUE);
2179 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2180 if (demux->activated_streams) {
2181 /* normal playback, send EOS to all linked pads */
2182 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2183 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2185 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2186 flow = GST_FLOW_EOS;
2189 /* ... and fall through to pause */
2193 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2194 gst_flow_get_name (flow));
2195 demux->segment_running = FALSE;
2196 gst_pad_pause_task (demux->sinkpad);
2198 /* For the error cases */
2199 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2200 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2201 ("This doesn't seem to be an ASF file"));
2202 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2203 /* Post an error. Hopefully something else already has, but if not... */
2204 GST_ELEMENT_FLOW_ERROR (demux, flow);
2205 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2214 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2215 flow = GST_FLOW_EOS;
2219 /* See FIXMEs above */
2222 gst_buffer_unref (buf);
2223 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2224 ("Error parsing ASF packet %u", (guint) demux->packet));
2225 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2226 flow = GST_FLOW_ERROR;
2232 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2233 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2234 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2237 gst_asf_demux_check_header (GstASFDemux * demux)
2240 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2241 ASF_OBJECT_HEADER_SIZE);
2242 if (cdata == NULL) /* need more data */
2243 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2245 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
2246 && obj.id == ASF_OBJ_HEADER) {
2247 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2250 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2253 static GstFlowReturn
2254 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2256 GstFlowReturn ret = GST_FLOW_OK;
2259 demux = GST_ASF_DEMUX (parent);
2261 GST_LOG_OBJECT (demux,
2262 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2263 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2264 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2266 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2267 GST_DEBUG_OBJECT (demux, "received DISCONT");
2268 gst_asf_demux_mark_discont (demux);
2271 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2272 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2273 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2274 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2275 ", interpolation gap: %" GST_TIME_FORMAT,
2276 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2279 gst_adapter_push (demux->adapter, buf);
2281 switch (demux->state) {
2282 case GST_ASF_DEMUX_STATE_INDEX:{
2283 gint result = gst_asf_demux_check_header (demux);
2284 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2287 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2288 /* we don't care about this, probably an index */
2289 /* TODO maybe would be smarter to skip all the indices
2290 * until we got a new header or EOS to decide */
2291 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2294 GST_INFO_OBJECT (demux, "Chained asf starting");
2295 /* cleanup and get ready for a chained asf */
2296 gst_asf_demux_reset (demux, TRUE);
2300 case GST_ASF_DEMUX_STATE_HEADER:{
2301 ret = gst_asf_demux_chain_headers (demux);
2302 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2304 /* otherwise fall through */
2306 case GST_ASF_DEMUX_STATE_DATA:
2310 data_size = demux->packet_size;
2312 while (gst_adapter_available (demux->adapter) >= data_size) {
2314 GstAsfDemuxParsePacketError err;
2316 /* we don't know the length of the stream
2317 * check for a chained asf everytime */
2318 if (demux->num_packets == 0) {
2319 gint result = gst_asf_demux_check_header (demux);
2321 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2322 GST_INFO_OBJECT (demux, "Chained asf starting");
2323 /* cleanup and get ready for a chained asf */
2324 gst_asf_demux_reset (demux, TRUE);
2327 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2328 && demux->packet >= demux->num_packets)) {
2329 /* do not overshoot data section when streaming */
2333 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2335 /* FIXME: We should tally up fatal errors and error out only
2336 * after a few broken packets in a row? */
2337 err = gst_asf_demux_parse_packet (demux, buf);
2339 gst_buffer_unref (buf);
2341 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2342 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2344 GST_WARNING_OBJECT (demux, "Parse error");
2346 if (demux->packet >= 0)
2349 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2350 && demux->packet >= demux->num_packets)) {
2351 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2356 g_assert_not_reached ();
2360 if (ret != GST_FLOW_OK)
2361 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2367 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2373 static inline gboolean
2374 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2376 if (*p_size < num_bytes)
2379 *p_data += num_bytes;
2380 *p_size -= num_bytes;
2384 static inline guint8
2385 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2389 g_assert (*p_size >= 1);
2390 ret = GST_READ_UINT8 (*p_data);
2391 *p_data += sizeof (guint8);
2392 *p_size -= sizeof (guint8);
2396 static inline guint16
2397 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2401 g_assert (*p_size >= 2);
2402 ret = GST_READ_UINT16_LE (*p_data);
2403 *p_data += sizeof (guint16);
2404 *p_size -= sizeof (guint16);
2408 static inline guint32
2409 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2413 g_assert (*p_size >= 4);
2414 ret = GST_READ_UINT32_LE (*p_data);
2415 *p_data += sizeof (guint32);
2416 *p_size -= sizeof (guint32);
2420 static inline guint64
2421 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2425 g_assert (*p_size >= 8);
2426 ret = GST_READ_UINT64_LE (*p_data);
2427 *p_data += sizeof (guint64);
2428 *p_size -= sizeof (guint64);
2433 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2434 guint8 ** p_data, guint64 * p_size)
2438 if (*p_size < num_bytes_to_read)
2441 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2442 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2444 *p_data += num_bytes_to_read;
2445 *p_size -= num_bytes_to_read;
2451 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2452 guint8 ** p_data, guint64 * p_size)
2456 if (*p_size < num_bytes_to_read)
2459 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2460 *p_data += num_bytes_to_read;
2461 *p_size -= num_bytes_to_read;
2466 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2467 guint8 ** p_data, guint64 * p_size)
2477 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2480 *p_strlen = s_length;
2482 if (s_length == 0) {
2483 GST_WARNING ("zero-length string");
2484 *p_str = g_strdup ("");
2488 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2491 g_assert (s != NULL);
2493 /* just because They don't exist doesn't
2494 * mean They are not out to get you ... */
2495 if (s[s_length - 1] != '\0') {
2496 s = g_realloc (s, s_length + 1);
2500 *p_str = (gchar *) s;
2506 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2508 g_assert (*p_size >= 4 * sizeof (guint32));
2510 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2511 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2512 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2513 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2517 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2520 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2523 /* WAVEFORMATEX Structure */
2524 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2525 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2526 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2527 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2528 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2529 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2530 /* Codec specific data size */
2531 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2532 if (audio->size > *p_size) {
2533 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2534 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2541 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2544 if (*p_size < (4 + 4 + 1 + 2))
2547 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2548 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2549 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2550 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2555 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2556 guint8 ** p_data, guint64 * p_size)
2558 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2561 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2563 if (fmt->size < 40) {
2564 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2567 if ((guint64) fmt->size - 4 > *p_size) {
2568 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2571 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2572 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2573 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2574 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2575 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2576 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2577 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2578 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2579 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2580 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2585 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2589 for (i = 0; i < demux->num_streams; i++) {
2590 if (demux->stream[i].id == id)
2591 return &demux->stream[i];
2594 if (gst_asf_demux_is_unknown_stream (demux, id))
2595 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2600 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2601 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2606 gst_pad_use_fixed_caps (src_pad);
2607 gst_pad_set_caps (src_pad, caps);
2609 gst_pad_set_event_function (src_pad,
2610 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2611 gst_pad_set_query_function (src_pad,
2612 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2614 stream = &demux->stream[demux->num_streams];
2615 stream->caps = caps;
2616 stream->pad = src_pad;
2618 stream->fps_known = !is_video; /* bit hacky for audio */
2619 stream->is_video = is_video;
2620 stream->pending_tags = tags;
2621 stream->discont = TRUE;
2622 stream->first_buffer = TRUE;
2623 stream->streamheader = streamheader;
2624 if (stream->streamheader) {
2625 stream->streamheader = gst_buffer_make_writable (streamheader);
2626 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2631 st = gst_caps_get_structure (caps, 0);
2632 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2633 par_x > 0 && par_y > 0) {
2634 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2635 stream->par_x = par_x;
2636 stream->par_y = par_y;
2640 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2642 /* TODO: create this array during reverse play? */
2643 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2645 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2646 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2648 ++demux->num_streams;
2650 stream->active = FALSE;
2656 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2657 GstBuffer * buffer, GstStructure * structure)
2659 GValue arr_val = G_VALUE_INIT;
2660 GValue buf_val = G_VALUE_INIT;
2662 g_value_init (&arr_val, GST_TYPE_ARRAY);
2663 g_value_init (&buf_val, GST_TYPE_BUFFER);
2665 gst_value_set_buffer (&buf_val, buffer);
2666 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2668 gst_structure_take_value (structure, "streamheader", &arr_val);
2672 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2673 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2675 GstTagList *tags = NULL;
2676 GstBuffer *extradata = NULL;
2679 guint16 size_left = 0;
2680 gchar *codec_name = NULL;
2683 size_left = audio->size;
2685 /* Create the audio pad */
2686 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2688 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2691 /* Swallow up any left over data and set up the
2692 * standard properties from the header info */
2694 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2695 "codec specific data", size_left);
2697 g_assert (size_left <= *p_size);
2698 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2701 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2702 * additional two bytes indicating extradata. */
2703 /* FIXME: Handle the channel reorder map here */
2704 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2705 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2708 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2709 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2712 /* Informing about that audio format we just added */
2714 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2715 g_free (codec_name);
2718 if (audio->byte_rate > 0) {
2719 /* Some ASF files have no bitrate props object (often seen with
2720 * ASF files that contain raw audio data). Example files can
2721 * be generated with FFmpeg (tested with v2.8.6), like this:
2723 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2725 * In this case, if audio->byte_rate is nonzero, use that as
2728 guint bitrate = audio->byte_rate * 8;
2731 tags = gst_tag_list_new_empty ();
2733 /* Add bitrate, but only if there is none set already, since
2734 * this is just a fallback in case there is no bitrate tag
2735 * already present */
2736 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2740 gst_buffer_unref (extradata);
2742 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2743 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2744 audio->codec_tag, tags);
2746 ++demux->num_audio_streams;
2748 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2752 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2753 asf_stream_video_format * video, guint16 id,
2754 guint8 ** p_data, guint64 * p_size)
2756 GstTagList *tags = NULL;
2757 GstStructure *caps_s;
2758 GstBuffer *extradata = NULL;
2763 gchar *codec_name = NULL;
2764 guint64 size_left = video->size - 40;
2765 GstBuffer *streamheader = NULL;
2766 guint par_w = 1, par_h = 1;
2768 /* Create the video pad */
2769 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2770 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2773 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2775 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2776 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2778 g_assert (size_left <= *p_size);
2779 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2782 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2784 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2785 caps = gst_riff_create_video_caps (video->tag, NULL,
2786 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2789 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2790 G_TYPE_UINT, video->tag, NULL);
2795 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2796 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2797 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2800 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2804 /* retry with the global metadata */
2805 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2806 demux->global_metadata);
2807 s = demux->global_metadata;
2808 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2809 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2810 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2811 if (ax > 0 && ay > 0) {
2814 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2819 s = gst_caps_get_structure (caps, 0);
2820 gst_structure_remove_field (s, "framerate");
2823 caps_s = gst_caps_get_structure (caps, 0);
2825 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2826 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2827 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2828 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2831 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2832 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2833 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2835 GstBuffer *buf = gst_value_get_buffer (value);
2838 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2839 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2840 /* this looks like a bytestream start */
2841 streamheader = gst_buffer_ref (buf);
2842 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2843 gst_structure_remove_field (caps_s, "codec_data");
2844 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING,
2845 "byte-stream", NULL);
2847 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "avc",
2851 gst_buffer_unmap (buf, &mapinfo);
2854 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "byte-stream",
2859 /* For a 3D video, set multiview information into the caps based on
2860 * what was detected during object parsing */
2861 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2862 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2863 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2864 const gchar *mview_mode_str;
2866 switch (demux->asf_3D_mode) {
2867 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2868 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2870 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2871 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2872 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2874 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2875 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2877 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2878 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2879 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2881 case GST_ASF_3D_DUAL_STREAM:{
2882 gboolean is_right_view = FALSE;
2883 /* if Advanced_Mutual_Exclusion object exists, use it
2884 * to figure out which is the left view (lower ID) */
2885 if (demux->mut_ex_streams != NULL) {
2889 length = g_slist_length (demux->mut_ex_streams);
2891 for (i = 0; i < length; i++) {
2894 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2896 GST_DEBUG_OBJECT (demux,
2897 "has Mutual_Exclusion object. stream id in object is %d",
2898 GPOINTER_TO_INT (v_s_id));
2900 if (id > GPOINTER_TO_INT (v_s_id))
2901 is_right_view = TRUE;
2904 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2905 * first video stream encountered has the lower ID */
2906 if (demux->num_video_streams > 0) {
2907 /* This is not the first video stream, assuming right eye view */
2908 is_right_view = TRUE;
2912 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2914 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2921 GST_INFO_OBJECT (demux,
2922 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2925 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2926 if (mview_mode_str != NULL) {
2927 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2928 video->height, par_w, par_h))
2929 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2931 gst_caps_set_simple (caps,
2932 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2933 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2934 GST_FLAG_SET_MASK_EXACT, NULL);
2939 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2940 g_free (codec_name);
2944 gst_buffer_unref (extradata);
2946 GST_INFO ("Adding video stream #%u, id %u, codec %"
2947 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2948 GST_FOURCC_ARGS (video->tag), video->tag);
2950 ++demux->num_video_streams;
2952 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2953 streamheader, tags);
2957 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2959 if (!stream->active) {
2963 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2964 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2965 gst_pad_set_active (stream->pad, TRUE);
2968 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2969 "%03u", stream->id);
2972 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2974 if (gst_event_parse_group_id (event, &demux->group_id))
2975 demux->have_group_id = TRUE;
2977 demux->have_group_id = FALSE;
2978 gst_event_unref (event);
2979 } else if (!demux->have_group_id) {
2980 demux->have_group_id = TRUE;
2981 demux->group_id = gst_util_group_id_next ();
2984 event = gst_event_new_stream_start (stream_id);
2985 if (demux->have_group_id)
2986 gst_event_set_group_id (event, demux->group_id);
2988 gst_pad_push_event (stream->pad, event);
2990 gst_pad_set_caps (stream->pad, stream->caps);
2992 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2993 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2994 stream->active = TRUE;
2999 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
3002 AsfCorrectionType correction_type;
3003 AsfStreamType stream_type;
3004 GstClockTime time_offset;
3005 gboolean is_encrypted G_GNUC_UNUSED;
3009 guint stream_specific_size;
3010 guint type_specific_size G_GNUC_UNUSED;
3011 guint unknown G_GNUC_UNUSED;
3012 gboolean inspect_payload = FALSE;
3013 AsfStream *stream = NULL;
3015 /* Get the rest of the header's header */
3016 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
3017 goto not_enough_data;
3019 gst_asf_demux_get_guid (&guid, &data, &size);
3020 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
3022 gst_asf_demux_get_guid (&guid, &data, &size);
3023 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
3025 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
3027 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3028 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3030 flags = gst_asf_demux_get_uint16 (&data, &size);
3031 stream_id = flags & 0x7f;
3032 is_encrypted = ! !(flags & 0x8000);
3033 unknown = gst_asf_demux_get_uint32 (&data, &size);
3035 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3036 stream_id, GST_TIME_ARGS (time_offset));
3038 /* dvr-ms has audio stream declared in stream specific data */
3039 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3040 AsfExtStreamType ext_stream_type;
3041 gst_asf_demux_get_guid (&guid, &data, &size);
3042 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3044 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3045 inspect_payload = TRUE;
3047 gst_asf_demux_get_guid (&guid, &data, &size);
3048 gst_asf_demux_get_uint32 (&data, &size);
3049 gst_asf_demux_get_uint32 (&data, &size);
3050 gst_asf_demux_get_uint32 (&data, &size);
3051 gst_asf_demux_get_guid (&guid, &data, &size);
3052 gst_asf_demux_get_uint32 (&data, &size);
3053 stream_type = ASF_STREAM_AUDIO;
3057 switch (stream_type) {
3058 case ASF_STREAM_AUDIO:{
3059 asf_stream_audio audio_object;
3061 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3062 goto not_enough_data;
3064 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3067 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3070 switch (correction_type) {
3071 case ASF_CORRECTION_ON:{
3072 guint span, packet_size, chunk_size, data_size, silence_data;
3074 GST_INFO ("Using error correction");
3076 if (size < (1 + 2 + 2 + 2 + 1))
3077 goto not_enough_data;
3079 span = gst_asf_demux_get_uint8 (&data, &size);
3080 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3081 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3082 data_size = gst_asf_demux_get_uint16 (&data, &size);
3083 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3085 stream->span = span;
3087 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3088 packet_size, chunk_size, data_size, span, silence_data);
3090 if (stream->span > 1) {
3091 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3092 /* Disable descrambling */
3095 /* FIXME: this else branch was added for
3096 * weird_al_yankovic - the saga begins.asf */
3097 stream->ds_packet_size = packet_size;
3098 stream->ds_chunk_size = chunk_size;
3101 /* Descambling is enabled */
3102 stream->ds_packet_size = packet_size;
3103 stream->ds_chunk_size = chunk_size;
3106 /* Now skip the rest of the silence data */
3108 gst_bytestream_flush (demux->bs, data_size - 1);
3110 /* FIXME: CHECKME. And why -1? */
3111 if (data_size > 1) {
3112 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3113 goto not_enough_data;
3119 case ASF_CORRECTION_OFF:{
3120 GST_INFO ("Error correction off");
3121 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3122 goto not_enough_data;
3126 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3127 ("Audio stream using unknown error correction"));
3134 case ASF_STREAM_VIDEO:{
3135 asf_stream_video_format video_format_object;
3136 asf_stream_video video_object;
3139 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3140 goto not_enough_data;
3142 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3144 GST_INFO ("object is a video stream with %u bytes of "
3145 "additional data", vsize);
3147 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3149 goto not_enough_data;
3152 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3153 stream_id, &data, &size);
3159 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3161 demux->other_streams =
3162 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3167 stream->inspect_payload = inspect_payload;
3168 stream->type = stream_type;
3174 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3175 /* we'll error out later if we found no streams */
3180 static const gchar *
3181 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3185 const gchar *asf_name;
3186 const gchar *gst_name;
3189 "WM/Genre", GST_TAG_GENRE}, {
3190 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3191 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3192 "WM/Picture", GST_TAG_IMAGE}, {
3193 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3194 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3195 "WM/Year", GST_TAG_DATE_TIME}
3196 /* { "WM/Composer", GST_TAG_COMPOSER } */
3201 if (name_utf8 == NULL) {
3202 GST_WARNING ("Failed to convert name to UTF8, skipping");
3206 out = strlen (name_utf8);
3208 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3209 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3210 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3211 return tags[i].gst_name;
3218 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3220 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3224 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3226 if (taglist == NULL)
3229 if (gst_tag_list_is_empty (taglist)) {
3230 gst_tag_list_unref (taglist);
3234 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3235 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3237 gst_tag_list_unref (demux->taglist);
3238 gst_tag_list_unref (taglist);
3240 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3243 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3244 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3245 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3246 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3249 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3253 const guint8 *img_data = NULL;
3254 guint32 img_data_len = 0;
3255 guint8 pic_type = 0;
3257 gst_byte_reader_init (&r, tag_data, tag_data_len);
3259 /* skip mime type string (we don't trust it and do our own typefinding),
3260 * and also skip the description string, since we don't use it */
3261 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3262 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3263 !gst_byte_reader_skip_string_utf16 (&r) ||
3264 !gst_byte_reader_skip_string_utf16 (&r) ||
3265 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3266 goto not_enough_data;
3270 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3271 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3277 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3278 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3283 /* Extended Content Description Object */
3284 static GstFlowReturn
3285 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3288 /* Other known (and unused) 'text/unicode' metadata available :
3291 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3292 * WMFSDKVersion = 9.00.00.2980
3293 * WMFSDKNeeded = 0.0.0.0000
3294 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3295 * WM/Publisher = 4AD
3297 * WM/ProviderRating = 8
3298 * WM/ProviderStyle = Rock (similar to WM/Genre)
3299 * WM/GenreID (similar to WM/Genre)
3300 * WM/TrackNumber (same as WM/Track but as a string)
3302 * Other known (and unused) 'non-text' metadata available :
3308 * We might want to read WM/TrackNumber and use atoi() if we don't have
3312 GstTagList *taglist;
3313 guint16 blockcount, i;
3314 gboolean content3D = FALSE;
3318 const gchar *interleave_name;
3319 GstASF3DMode interleaving_type;
3320 } stereoscopic_layout_map[] = {
3322 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3323 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3324 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3325 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3326 "DualStream", GST_ASF_3D_DUAL_STREAM}
3328 GST_INFO_OBJECT (demux, "object is an extended content description");
3330 taglist = gst_tag_list_new_empty ();
3332 /* Content Descriptor Count */
3334 goto not_enough_data;
3336 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3338 for (i = 1; i <= blockcount; ++i) {
3339 const gchar *gst_tag_name;
3343 GValue tag_value = { 0, };
3346 gchar *name_utf8 = NULL;
3350 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3351 goto not_enough_data;
3355 goto not_enough_data;
3357 /* Descriptor Value Data Type */
3358 datatype = gst_asf_demux_get_uint16 (&data, &size);
3360 /* Descriptor Value (not really a string, but same thing reading-wise) */
3361 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3363 goto not_enough_data;
3367 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3369 if (name_utf8 != NULL) {
3370 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3372 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3373 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3376 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3379 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3382 /* get rid of tags with empty value */
3383 if (value_utf8 != NULL && *value_utf8 != '\0') {
3384 GST_DEBUG ("string value %s", value_utf8);
3386 value_utf8[out] = '\0';
3388 if (gst_tag_name != NULL) {
3389 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3390 guint year = atoi (value_utf8);
3393 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3394 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3396 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3397 guint id3v1_genre_id;
3398 const gchar *genre_str;
3400 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3401 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3402 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3403 g_free (value_utf8);
3404 value_utf8 = g_strdup (genre_str);
3409 /* convert tag from string to other type if required */
3410 tag_type = gst_tag_get_type (gst_tag_name);
3411 g_value_init (&tag_value, tag_type);
3412 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3413 GValue from_val = { 0, };
3415 g_value_init (&from_val, G_TYPE_STRING);
3416 g_value_set_string (&from_val, value_utf8);
3417 if (!g_value_transform (&from_val, &tag_value)) {
3418 GST_WARNING_OBJECT (demux,
3419 "Could not transform string tag to " "%s tag type %s",
3420 gst_tag_name, g_type_name (tag_type));
3421 g_value_unset (&tag_value);
3423 g_value_unset (&from_val);
3428 GST_DEBUG ("Setting metadata");
3429 g_value_init (&tag_value, G_TYPE_STRING);
3430 g_value_set_string (&tag_value, value_utf8);
3431 /* If we found a stereoscopic marker, look for StereoscopicLayout
3435 if (strncmp ("StereoscopicLayout", name_utf8,
3436 strlen (name_utf8)) == 0) {
3437 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3438 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3440 demux->asf_3D_mode =
3441 stereoscopic_layout_map[i].interleaving_type;
3442 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3446 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3448 demux->asf_3D_mode = GST_ASF_3D_NONE;
3449 GST_INFO_OBJECT (demux, "None 3d type");
3452 } else if (value_utf8 == NULL) {
3453 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3455 GST_DEBUG ("Skipping empty string value for %s",
3456 GST_STR_NULL (gst_tag_name));
3458 g_free (value_utf8);
3461 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3463 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3464 GST_FIXME ("Unhandled byte array tag %s",
3465 GST_STR_NULL (gst_tag_name));
3468 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3474 case ASF_DEMUX_DATA_TYPE_DWORD:{
3480 uint_val = GST_READ_UINT32_LE (value);
3482 /* this is the track number */
3483 g_value_init (&tag_value, G_TYPE_UINT);
3485 /* WM/Track counts from 0 */
3486 if (!strcmp (name_utf8, "WM/Track"))
3489 g_value_set_uint (&tag_value, uint_val);
3493 case ASF_DEMUX_DATA_TYPE_BOOL:{
3499 bool_val = GST_READ_UINT32_LE (value);
3501 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3503 GST_INFO_OBJECT (demux, "This is 3D contents");
3506 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3514 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3519 if (G_IS_VALUE (&tag_value)) {
3521 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3523 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3524 * is supposed to have a 0 base but is often wrongly written to start
3525 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3526 * replace the value added earlier from WM/Track or put it first in
3527 * the list, so that it will get picked up by _get_uint() */
3528 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3529 merge_mode = GST_TAG_MERGE_REPLACE;
3531 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3534 GST_DEBUG ("Setting global metadata %s", name_utf8);
3535 gst_structure_set_value (demux->global_metadata, name_utf8,
3539 g_value_unset (&tag_value);
3548 gst_asf_demux_add_global_tags (demux, taglist);
3555 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3556 gst_tag_list_unref (taglist);
3557 return GST_FLOW_OK; /* not really fatal */
3561 static GstStructure *
3562 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3567 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3569 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3572 s = gst_caps_get_structure (demux->metadata, i);
3573 if (gst_structure_has_name (s, sname))
3577 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3579 /* try lookup again; demux->metadata took ownership of the structure, so we
3580 * can't really make any assumptions about what happened to it, so we can't
3581 * just return it directly after appending it */
3582 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3585 static GstFlowReturn
3586 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3589 guint16 blockcount, i;
3591 GST_INFO_OBJECT (demux, "object is a metadata object");
3593 /* Content Descriptor Count */
3595 goto not_enough_data;
3597 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3599 for (i = 0; i < blockcount; ++i) {
3601 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3602 guint32 data_len, ival;
3605 if (size < (2 + 2 + 2 + 2 + 4))
3606 goto not_enough_data;
3608 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3609 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3610 name_len = gst_asf_demux_get_uint16 (&data, &size);
3611 data_type = gst_asf_demux_get_uint16 (&data, &size);
3612 data_len = gst_asf_demux_get_uint32 (&data, &size);
3614 if (size < name_len + data_len)
3615 goto not_enough_data;
3617 /* convert name to UTF-8 */
3618 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3620 gst_asf_demux_skip_bytes (name_len, &data, &size);
3622 if (name_utf8 == NULL) {
3623 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3624 gst_asf_demux_skip_bytes (data_len, &data, &size);
3628 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3629 gst_asf_demux_skip_bytes (data_len, &data, &size);
3637 goto not_enough_data;
3640 ival = gst_asf_demux_get_uint32 (&data, &size);
3642 /* skip anything else there may be, just in case */
3643 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3645 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3646 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3650 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3656 GST_WARNING ("Unexpected end of data parsing metadata object");
3657 return GST_FLOW_OK; /* not really fatal */
3661 static GstFlowReturn
3662 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3664 GstFlowReturn ret = GST_FLOW_OK;
3665 guint32 i, num_objects;
3666 guint8 unknown G_GNUC_UNUSED;
3668 /* Get the rest of the header's header */
3669 if (size < (4 + 1 + 1))
3670 goto not_enough_data;
3672 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3673 unknown = gst_asf_demux_get_uint8 (&data, &size);
3674 unknown = gst_asf_demux_get_uint8 (&data, &size);
3676 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3677 demux->saw_file_header = FALSE;
3678 /* Loop through the header's objects, processing those */
3679 for (i = 0; i < num_objects; ++i) {
3680 GST_INFO_OBJECT (demux, "reading header part %u", i);
3681 ret = gst_asf_demux_process_object (demux, &data, &size);
3682 if (ret != GST_FLOW_OK) {
3683 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3687 if (!demux->saw_file_header) {
3688 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3689 ("Header does not have mandatory FILE section"));
3690 return GST_FLOW_ERROR;
3697 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3698 ("short read parsing HEADER object"));
3699 return GST_FLOW_ERROR;
3703 static GstFlowReturn
3704 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3706 guint64 creation_time G_GNUC_UNUSED;
3707 guint64 file_size G_GNUC_UNUSED;
3708 guint64 send_time G_GNUC_UNUSED;
3709 guint64 packets_count, play_time, preroll;
3710 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3712 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3713 goto not_enough_data;
3715 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3716 file_size = gst_asf_demux_get_uint64 (&data, &size);
3717 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3718 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3719 play_time = gst_asf_demux_get_uint64 (&data, &size);
3720 send_time = gst_asf_demux_get_uint64 (&data, &size);
3721 preroll = gst_asf_demux_get_uint64 (&data, &size);
3722 flags = gst_asf_demux_get_uint32 (&data, &size);
3723 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3724 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3725 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3727 demux->broadcast = ! !(flags & 0x01);
3728 demux->seekable = ! !(flags & 0x02);
3730 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3731 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3732 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3734 if (demux->broadcast) {
3735 /* these fields are invalid if the broadcast flag is set */
3740 if (min_pktsize != max_pktsize)
3741 goto non_fixed_packet_size;
3743 demux->packet_size = max_pktsize;
3745 /* FIXME: do we need send_time as well? what is it? */
3746 if ((play_time * 100) >= (preroll * GST_MSECOND))
3747 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3749 demux->play_time = 0;
3751 demux->preroll = preroll * GST_MSECOND;
3753 /* initial latency */
3754 demux->latency = demux->preroll;
3756 if (demux->play_time == 0)
3757 demux->seekable = FALSE;
3759 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3760 GST_TIME_ARGS (demux->play_time));
3761 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3762 GST_TIME_ARGS (demux->preroll));
3764 if (demux->play_time > 0) {
3765 demux->segment.duration = demux->play_time;
3768 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3770 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3772 demux->saw_file_header = TRUE;
3777 non_fixed_packet_size:
3779 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3780 ("packet size must be fixed"));
3781 return GST_FLOW_ERROR;
3785 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3786 ("short read parsing FILE object"));
3787 return GST_FLOW_ERROR;
3791 /* Content Description Object */
3792 static GstFlowReturn
3793 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3797 const gchar *gst_tag;
3802 GST_TAG_TITLE, 0, NULL}, {
3803 GST_TAG_ARTIST, 0, NULL}, {
3804 GST_TAG_COPYRIGHT, 0, NULL}, {
3805 GST_TAG_DESCRIPTION, 0, NULL}, {
3806 GST_TAG_COMMENT, 0, NULL}
3808 GstTagList *taglist;
3809 GValue value = { 0 };
3813 GST_INFO_OBJECT (demux, "object is a comment");
3815 if (size < (2 + 2 + 2 + 2 + 2))
3816 goto not_enough_data;
3818 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3819 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3820 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3821 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3822 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3824 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3825 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3826 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3828 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3829 if (size < tags[i].val_length)
3830 goto not_enough_data;
3832 /* might be just '/0', '/0'... */
3833 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3834 /* convert to UTF-8 */
3835 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3836 "UTF-8", "UTF-16LE", &in, &out, NULL);
3838 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3841 /* parse metadata into taglist */
3842 taglist = gst_tag_list_new_empty ();
3843 g_value_init (&value, G_TYPE_STRING);
3844 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3845 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3846 g_value_set_string (&value, tags[i].val_utf8);
3847 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3848 tags[i].gst_tag, &value, NULL);
3851 g_value_unset (&value);
3853 gst_asf_demux_add_global_tags (demux, taglist);
3855 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3856 g_free (tags[i].val_utf8);
3862 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3863 "comment tag section %d, skipping comment object", i);
3864 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3865 g_free (tags[i].val_utf8);
3866 return GST_FLOW_OK; /* not really fatal */
3870 static GstFlowReturn
3871 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3874 guint16 num_streams, i;
3878 goto not_enough_data;
3880 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3882 GST_INFO ("object is a bitrate properties object with %u streams",
3885 if (size < (num_streams * (2 + 4)))
3886 goto not_enough_data;
3888 for (i = 0; i < num_streams; ++i) {
3892 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3893 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3895 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3896 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3897 stream = gst_asf_demux_get_stream (demux, stream_id);
3899 if (stream->pending_tags == NULL)
3900 stream->pending_tags = gst_tag_list_new_empty ();
3901 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3902 GST_TAG_BITRATE, bitrate, NULL);
3904 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3907 GST_WARNING ("stream id %u is too large", stream_id);
3915 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3916 return GST_FLOW_OK; /* not really fatal */
3920 static GstFlowReturn
3921 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3924 GstFlowReturn ret = GST_FLOW_OK;
3927 /* Get the rest of the header's header */
3928 if (size < (16 + 2 + 4))
3929 goto not_enough_data;
3931 /* skip GUID and two other bytes */
3932 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3933 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3935 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3937 /* FIXME: does data_size include the rest of the header that we have read? */
3938 if (hdr_size > size)
3939 goto not_enough_data;
3941 while (hdr_size > 0) {
3942 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3943 if (ret != GST_FLOW_OK)
3951 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3952 ("short read parsing extended header object"));
3953 return GST_FLOW_ERROR;
3957 static GstFlowReturn
3958 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3964 goto not_enough_data;
3966 if (demux->languages) {
3967 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3968 g_strfreev (demux->languages);
3969 demux->languages = NULL;
3970 demux->num_languages = 0;
3973 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3974 GST_LOG ("%u languages:", demux->num_languages);
3976 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3977 for (i = 0; i < demux->num_languages; ++i) {
3978 guint8 len, *lang_data = NULL;
3981 goto not_enough_data;
3982 len = gst_asf_demux_get_uint8 (&data, &size);
3983 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3986 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3989 /* truncate "en-us" etc. to just "en" */
3990 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3993 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3994 demux->languages[i] = utf8;
3997 goto not_enough_data;
4005 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
4006 g_free (demux->languages);
4007 demux->languages = NULL;
4008 demux->num_languages = 0;
4009 return GST_FLOW_OK; /* not fatal */
4013 static GstFlowReturn
4014 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
4017 GstClockTime interval;
4020 if (size < (16 + 8 + 4 + 4))
4021 goto not_enough_data;
4024 gst_asf_demux_skip_bytes (16, &data, &size);
4025 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
4026 gst_asf_demux_skip_bytes (4, &data, &size);
4027 count = gst_asf_demux_get_uint32 (&data, &size);
4029 demux->sidx_interval = interval;
4030 demux->sidx_num_entries = count;
4031 g_free (demux->sidx_entries);
4032 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
4034 for (i = 0; i < count; ++i) {
4035 if (G_UNLIKELY (size < 6)) {
4036 /* adjust for broken files, to avoid having entries at the end
4037 * of the parsed index that point to time=0. Resulting in seeking to
4038 * the end of the file leading back to the beginning */
4039 demux->sidx_num_entries -= (count - i);
4042 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4043 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4044 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4045 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4046 demux->sidx_entries[i].count);
4049 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4056 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4057 return GST_FLOW_OK; /* not fatal */
4061 static GstFlowReturn
4062 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4063 guint8 * data, guint64 size)
4068 if (size < 16 + 2 + (2 * 2))
4069 goto not_enough_data;
4071 gst_asf_demux_get_guid (&guid, &data, &size);
4072 num = gst_asf_demux_get_uint16 (&data, &size);
4075 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4079 if (size < (num * sizeof (guint16)))
4080 goto not_enough_data;
4082 /* read mutually exclusive stream numbers */
4083 for (i = 0; i < num; ++i) {
4085 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4086 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4088 demux->mut_ex_streams =
4089 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4098 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4099 return GST_FLOW_OK; /* not absolutely fatal */
4104 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4106 return g_slist_find (demux->other_streams,
4107 GINT_TO_POINTER (stream_num)) == NULL;
4110 static GstFlowReturn
4111 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4114 AsfStreamExtProps esp;
4115 AsfStream *stream = NULL;
4116 AsfObject stream_obj;
4117 guint16 stream_name_count;
4118 guint16 num_payload_ext;
4120 guint8 *stream_obj_data = NULL;
4123 guint i, stream_num;
4126 obj_size = (guint) size;
4128 esp.payload_extensions = NULL;
4131 goto not_enough_data;
4134 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4135 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4136 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4137 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4138 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4139 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4140 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4141 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4142 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4143 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4144 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4145 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4146 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4147 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4148 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4150 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4151 GST_TIME_ARGS (esp.start_time));
4152 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4153 GST_TIME_ARGS (esp.end_time));
4154 GST_INFO ("flags = %08x", esp.flags);
4155 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4156 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4157 GST_INFO ("stream number = %u", stream_num);
4158 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4159 (esp.lang_idx < demux->num_languages) ?
4160 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4161 GST_INFO ("stream name count = %u", stream_name_count);
4163 /* read stream names */
4164 for (i = 0; i < stream_name_count; ++i) {
4165 guint16 stream_lang_idx G_GNUC_UNUSED;
4166 gchar *stream_name = NULL;
4169 goto not_enough_data;
4170 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4171 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4172 goto not_enough_data;
4173 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4174 g_free (stream_name); /* TODO: store names in struct */
4177 /* read payload extension systems stuff */
4178 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4180 if (num_payload_ext > 0)
4181 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4183 for (i = 0; i < num_payload_ext; ++i) {
4184 AsfPayloadExtension ext;
4186 guint32 sys_info_len;
4188 if (size < 16 + 2 + 4)
4189 goto not_enough_data;
4191 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4192 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4193 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4195 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4196 GST_LOG ("payload systems info len = %u", sys_info_len);
4197 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4198 goto not_enough_data;
4200 esp.payload_extensions[i] = ext;
4203 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4205 /* there might be an optional STREAM_INFO object here now; if not, we
4206 * should have parsed the corresponding stream info object already (since
4207 * we are parsing the extended stream properties objects delayed) */
4209 stream = gst_asf_demux_get_stream (demux, stream_num);
4213 if (size < ASF_OBJECT_HEADER_SIZE)
4214 goto not_enough_data;
4216 /* get size of the stream object */
4217 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4218 goto corrupted_stream;
4220 if (stream_obj.id != ASF_OBJ_STREAM)
4221 goto expected_stream_object;
4223 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4224 stream_obj.size > (10 * 1024 * 1024))
4225 goto not_enough_data;
4227 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4229 /* process this stream object later after all the other 'normal' ones
4230 * have been processed (since the others are more important/non-hidden) */
4231 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4232 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4233 goto not_enough_data;
4235 /* parse stream object */
4236 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4237 g_free (stream_obj_data);
4242 stream->ext_props = esp;
4244 /* try to set the framerate */
4245 if (stream->is_video && stream->caps) {
4246 GValue framerate = { 0 };
4250 g_value_init (&framerate, GST_TYPE_FRACTION);
4252 num = GST_SECOND / 100;
4253 denom = esp.avg_time_per_frame;
4255 /* avoid division by 0, assume 25/1 framerate */
4256 denom = GST_SECOND / 2500;
4259 gst_value_set_fraction (&framerate, num, denom);
4261 stream->caps = gst_caps_make_writable (stream->caps);
4262 s = gst_caps_get_structure (stream->caps, 0);
4263 gst_structure_set_value (s, "framerate", &framerate);
4264 g_value_unset (&framerate);
4265 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4266 num, denom, ((gdouble) num) / denom);
4269 /* add language info now if we have it */
4270 if (stream->ext_props.lang_idx < demux->num_languages) {
4271 if (stream->pending_tags == NULL)
4272 stream->pending_tags = gst_tag_list_new_empty ();
4273 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4274 demux->languages[stream->ext_props.lang_idx]);
4275 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4276 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4279 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4280 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4284 g_free (esp.payload_extensions);
4291 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4292 g_free (esp.payload_extensions);
4293 return GST_FLOW_OK; /* not absolutely fatal */
4295 expected_stream_object:
4297 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4298 "object: expected embedded stream object, but got %s object instead!",
4299 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4300 g_free (esp.payload_extensions);
4301 return GST_FLOW_OK; /* not absolutely fatal */
4305 GST_WARNING_OBJECT (demux, "Corrupted stream");
4306 g_free (esp.payload_extensions);
4307 return GST_FLOW_ERROR;
4311 static const gchar *
4312 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4316 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4317 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4318 nick += strlen ("ASF_OBJ_");
4320 if (demux->objpath == NULL) {
4321 demux->objpath = g_strdup (nick);
4325 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4326 g_free (demux->objpath);
4327 demux->objpath = newpath;
4330 return (const gchar *) demux->objpath;
4334 gst_asf_demux_pop_obj (GstASFDemux * demux)
4338 if ((s = g_strrstr (demux->objpath, "/"))) {
4341 g_free (demux->objpath);
4342 demux->objpath = NULL;
4347 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4352 /* Parse the queued extended stream property objects and add the info
4353 * to the existing streams or add the new embedded streams, but without
4354 * activating them yet */
4355 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4356 g_slist_length (demux->ext_stream_props));
4358 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4359 GstBuffer *buf = GST_BUFFER (l->data);
4362 gst_buffer_map (buf, &map, GST_MAP_READ);
4364 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4365 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4366 gst_buffer_unmap (buf, &map);
4367 gst_buffer_unref (buf);
4369 g_slist_free (demux->ext_stream_props);
4370 demux->ext_stream_props = NULL;
4375 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4379 for (i = 0; i < demux->num_streams; ++i) {
4384 stream = &demux->stream[i];
4386 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4388 if (stream->active) {
4389 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4394 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4397 /* check for each mutual exclusion whether it affects this stream */
4398 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4399 if (*mes == stream->id) {
4400 /* if yes, check if we've already added streams that are mutually
4401 * exclusive with the stream we're about to add */
4402 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4403 for (j = 0; j < demux->num_streams; ++j) {
4404 /* if the broadcast flag is set, assume the hidden streams aren't
4405 * actually streamed and hide them (or playbin won't work right),
4406 * otherwise assume their data is available */
4407 if (demux->stream[j].id == *mes && demux->broadcast) {
4409 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4410 "mutually exclusive with already existing stream ID %d, "
4411 "hiding stream", stream->id, demux->stream[j].id);
4423 /* FIXME: we should do stream activation based on preroll data in
4424 * streaming mode too */
4425 if (demux->streaming && !is_hidden)
4426 gst_asf_demux_activate_stream (demux, stream);
4431 static GstFlowReturn
4432 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4435 GstFlowReturn ret = GST_FLOW_OK;
4437 guint64 obj_data_size;
4439 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4440 return ASF_FLOW_NEED_MORE_DATA;
4442 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4444 return GST_FLOW_ERROR;
4445 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4447 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4449 if (*p_size < obj_data_size)
4450 return ASF_FLOW_NEED_MORE_DATA;
4452 gst_asf_demux_push_obj (demux, obj.id);
4454 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4457 case ASF_OBJ_STREAM:
4458 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4462 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4464 case ASF_OBJ_HEADER:
4465 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4467 case ASF_OBJ_COMMENT:
4468 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4471 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4473 case ASF_OBJ_BITRATE_PROPS:
4475 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4478 case ASF_OBJ_EXT_CONTENT_DESC:
4480 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4483 case ASF_OBJ_METADATA_OBJECT:
4484 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4486 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4489 /* process these later, we might not have parsed the corresponding
4490 * stream object yet */
4491 GST_LOG ("%s: queued for later parsing", demux->objpath);
4492 buf = gst_buffer_new_and_alloc (obj_data_size);
4493 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4494 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4498 case ASF_OBJ_LANGUAGE_LIST:
4499 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4501 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4502 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4505 case ASF_OBJ_SIMPLE_INDEX:
4506 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4508 case ASF_OBJ_CONTENT_ENCRYPTION:
4509 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4510 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4511 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4512 goto error_encrypted;
4513 case ASF_OBJ_CONCEAL_NONE:
4515 case ASF_OBJ_UNDEFINED:
4516 case ASF_OBJ_CODEC_COMMENT:
4518 case ASF_OBJ_PADDING:
4519 case ASF_OBJ_BITRATE_MUTEX:
4520 case ASF_OBJ_COMPATIBILITY:
4521 case ASF_OBJ_INDEX_PLACEHOLDER:
4522 case ASF_OBJ_INDEX_PARAMETERS:
4523 case ASF_OBJ_STREAM_PRIORITIZATION:
4524 case ASF_OBJ_SCRIPT_COMMAND:
4525 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4527 /* Unknown/unhandled object, skip it and hope for the best */
4528 GST_INFO ("%s: skipping object", demux->objpath);
4533 /* this can't fail, we checked the number of bytes available before */
4534 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4536 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4538 gst_asf_demux_pop_obj (demux);
4545 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4546 return GST_FLOW_ERROR;
4551 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4552 GstBuffer ** p_buffer)
4554 GstBuffer *descrambled_buffer;
4555 GstBuffer *scrambled_buffer;
4556 GstBuffer *sub_buffer;
4563 /* descrambled_buffer is initialised in the first iteration */
4564 descrambled_buffer = NULL;
4565 scrambled_buffer = *p_buffer;
4567 if (gst_buffer_get_size (scrambled_buffer) <
4568 stream->ds_packet_size * stream->span)
4571 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4572 offset += stream->ds_chunk_size) {
4573 off = offset / stream->ds_chunk_size;
4574 row = off / stream->span;
4575 col = off % stream->span;
4576 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4577 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4578 col, off, stream->ds_chunk_size);
4579 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4580 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4581 stream->span, stream->ds_packet_size);
4582 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4583 gst_buffer_get_size (scrambled_buffer));
4585 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4586 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4588 descrambled_buffer = sub_buffer;
4590 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4594 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4595 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4596 GST_BUFFER_DURATION (descrambled_buffer) =
4597 GST_BUFFER_DURATION (scrambled_buffer);
4598 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4599 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4600 GST_BUFFER_OFFSET_END (scrambled_buffer);
4602 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4604 gst_buffer_unref (scrambled_buffer);
4605 *p_buffer = descrambled_buffer;
4609 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4611 GstASFDemux *demux = GST_ASF_DEMUX (element);
4614 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4616 for (i = 0; i < demux->num_streams; ++i) {
4617 gst_event_ref (event);
4618 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4619 GST_OBJECT_CAST (element), event)) {
4620 gst_event_unref (event);
4625 gst_event_unref (event);
4629 /* takes ownership of the passed event */
4631 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4633 gboolean ret = TRUE;
4636 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4637 GST_EVENT_TYPE_NAME (event));
4639 for (i = 0; i < demux->num_streams; ++i) {
4640 gst_event_ref (event);
4641 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4643 gst_event_unref (event);
4648 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4652 gboolean res = FALSE;
4654 demux = GST_ASF_DEMUX (parent);
4656 GST_DEBUG ("handling %s query",
4657 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4659 switch (GST_QUERY_TYPE (query)) {
4660 case GST_QUERY_DURATION:
4664 gst_query_parse_duration (query, &format, NULL);
4666 if (format != GST_FORMAT_TIME) {
4667 GST_LOG ("only support duration queries in TIME format");
4671 res = gst_pad_query_default (pad, parent, query);
4673 GST_OBJECT_LOCK (demux);
4675 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4676 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4677 GST_TIME_ARGS (demux->segment.duration));
4679 gst_query_set_duration (query, GST_FORMAT_TIME,
4680 demux->segment.duration);
4684 GST_LOG ("duration not known yet");
4687 GST_OBJECT_UNLOCK (demux);
4692 case GST_QUERY_POSITION:{
4695 gst_query_parse_position (query, &format, NULL);
4697 if (format != GST_FORMAT_TIME) {
4698 GST_LOG ("only support position queries in TIME format");
4702 GST_OBJECT_LOCK (demux);
4704 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4705 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4706 GST_TIME_ARGS (demux->segment.position));
4708 gst_query_set_position (query, GST_FORMAT_TIME,
4709 demux->segment.position);
4713 GST_LOG ("position not known yet");
4716 GST_OBJECT_UNLOCK (demux);
4720 case GST_QUERY_SEEKING:{
4723 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4724 if (format == GST_FORMAT_TIME) {
4727 GST_OBJECT_LOCK (demux);
4728 duration = demux->segment.duration;
4729 GST_OBJECT_UNLOCK (demux);
4731 if (!demux->streaming || !demux->seekable) {
4732 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4739 /* try upstream first in TIME */
4740 res = gst_pad_query_default (pad, parent, query);
4742 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4743 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4744 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4745 /* if no luck, maybe in BYTES */
4746 if (!seekable || fmt != GST_FORMAT_TIME) {
4749 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4750 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4751 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4752 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4753 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4754 if (fmt != GST_FORMAT_BYTES)
4757 gst_query_unref (q);
4758 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4764 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4768 case GST_QUERY_LATENCY:
4771 GstClockTime min, max;
4773 /* preroll delay does not matter in non-live pipeline,
4774 * but we might end up in a live (rtsp) one ... */
4777 res = gst_pad_query_default (pad, parent, query);
4781 gst_query_parse_latency (query, &live, &min, &max);
4783 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4784 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4785 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4787 GST_OBJECT_LOCK (demux);
4788 min += demux->latency;
4790 max += demux->latency;
4791 GST_OBJECT_UNLOCK (demux);
4793 gst_query_set_latency (query, live, min, max);
4796 case GST_QUERY_SEGMENT:
4801 format = demux->segment.format;
4804 gst_segment_to_stream_time (&demux->segment, format,
4805 demux->segment.start);
4806 if ((stop = demux->segment.stop) == -1)
4807 stop = demux->segment.duration;
4809 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4811 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4816 res = gst_pad_query_default (pad, parent, query);
4823 static GstStateChangeReturn
4824 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4826 GstASFDemux *demux = GST_ASF_DEMUX (element);
4827 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4829 switch (transition) {
4830 case GST_STATE_CHANGE_NULL_TO_READY:{
4831 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4832 demux->need_newsegment = TRUE;
4833 demux->segment_running = FALSE;
4834 demux->keyunit_sync = FALSE;
4835 demux->accurate = FALSE;
4836 demux->adapter = gst_adapter_new ();
4837 demux->metadata = gst_caps_new_empty ();
4838 demux->global_metadata = gst_structure_new_empty ("metadata");
4839 demux->data_size = 0;
4840 demux->data_offset = 0;
4841 demux->index_offset = 0;
4842 demux->base_offset = 0;
4843 demux->flowcombiner = gst_flow_combiner_new ();
4851 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4852 if (ret == GST_STATE_CHANGE_FAILURE)
4855 switch (transition) {
4856 case GST_STATE_CHANGE_PAUSED_TO_READY:
4857 gst_asf_demux_reset (demux, FALSE);
4860 case GST_STATE_CHANGE_READY_TO_NULL:
4861 gst_asf_demux_reset (demux, FALSE);
4862 gst_flow_combiner_free (demux->flowcombiner);
4863 demux->flowcombiner = NULL;