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 "gstasfelements.h"
47 #include "gstasfdemux.h"
48 #include "asfheaders.h"
49 #include "asfpacket.h"
51 static GstStaticPadTemplate gst_asf_demux_sink_template =
52 GST_STATIC_PAD_TEMPLATE ("sink",
55 GST_STATIC_CAPS ("video/x-ms-asf")
58 static GstStaticPadTemplate audio_src_template =
59 GST_STATIC_PAD_TEMPLATE ("audio_%u",
64 static GstStaticPadTemplate video_src_template =
65 GST_STATIC_PAD_TEMPLATE ("video_%u",
70 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
71 #define ASF_OBJECT_HEADER_SIZE (16+8)
73 /* FIXME: get rid of this */
74 /* abuse this GstFlowReturn enum for internal usage */
75 #define ASF_FLOW_NEED_MORE_DATA 99
77 #define gst_asf_get_flow_name(flow) \
78 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
79 "need-more-data" : gst_flow_get_name (flow)
81 GST_DEBUG_CATEGORY (asfdemux_dbg);
83 static void gst_asf_demux_finalize (GObject * object);
84 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
85 GstStateChange transition);
86 static gboolean gst_asf_demux_element_send_event (GstElement * element,
88 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
90 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
91 GstObject * parent, GstQuery * query);
92 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
94 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
96 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
97 guint8 ** p_data, guint64 * p_size);
98 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
99 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
100 GstObject * parent, GstPadMode mode, gboolean active);
101 static void gst_asf_demux_loop (GstASFDemux * demux);
103 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
104 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
105 GstFlowReturn * pflow);
106 static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
107 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
109 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
110 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
111 AsfStream * stream, GstBuffer ** p_buffer);
112 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
114 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
116 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
119 #define gst_asf_demux_parent_class parent_class
120 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (asfdemux, "asfdemux", GST_RANK_SECONDARY,
122 GST_TYPE_ASF_DEMUX, asf_element_init (plugin));
125 gst_asf_demux_class_init (GstASFDemuxClass * klass)
127 GObjectClass *gobject_class;
128 GstElementClass *gstelement_class;
130 gobject_class = G_OBJECT_CLASS (klass);
131 gstelement_class = (GstElementClass *) klass;
133 gobject_class->finalize = gst_asf_demux_finalize;
135 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
137 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
139 gst_element_class_add_static_pad_template (gstelement_class,
140 &audio_src_template);
141 gst_element_class_add_static_pad_template (gstelement_class,
142 &video_src_template);
143 gst_element_class_add_static_pad_template (gstelement_class,
144 &gst_asf_demux_sink_template);
146 gstelement_class->change_state =
147 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
148 gstelement_class->send_event =
149 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
153 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
155 gst_caps_replace (&stream->caps, NULL);
156 if (stream->pending_tags) {
157 gst_tag_list_unref (stream->pending_tags);
158 stream->pending_tags = NULL;
160 if (stream->streamheader) {
161 gst_buffer_unref (stream->streamheader);
162 stream->streamheader = NULL;
165 if (stream->active) {
166 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
167 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
169 gst_object_unref (stream->pad);
173 if (stream->payloads) {
174 while (stream->payloads->len > 0) {
178 last = stream->payloads->len - 1;
179 payload = &g_array_index (stream->payloads, AsfPayload, last);
180 gst_buffer_replace (&payload->buf, NULL);
181 g_array_remove_index (stream->payloads, last);
183 g_array_free (stream->payloads, TRUE);
184 stream->payloads = NULL;
187 if (stream->payloads_rev) {
188 while (stream->payloads_rev->len > 0) {
192 last = stream->payloads_rev->len - 1;
193 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
194 gst_buffer_replace (&payload->buf, NULL);
195 g_array_remove_index (stream->payloads_rev, last);
197 g_array_free (stream->payloads_rev, TRUE);
198 stream->payloads_rev = NULL;
201 if (stream->ext_props.valid) {
202 g_free (stream->ext_props.payload_extensions);
203 stream->ext_props.payload_extensions = NULL;
208 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
210 GST_LOG_OBJECT (demux, "resetting");
212 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
213 demux->segment_running = FALSE;
214 if (demux->adapter && !chain_reset) {
215 gst_adapter_clear (demux->adapter);
216 g_object_unref (demux->adapter);
217 demux->adapter = NULL;
219 if (demux->taglist) {
220 gst_tag_list_unref (demux->taglist);
221 demux->taglist = NULL;
223 if (demux->metadata) {
224 gst_caps_unref (demux->metadata);
225 demux->metadata = NULL;
227 demux->metadata = gst_caps_new_empty ();
228 if (demux->global_metadata) {
229 gst_structure_free (demux->global_metadata);
230 demux->global_metadata = NULL;
232 demux->global_metadata = gst_structure_new_empty ("metadata");
233 if (demux->mut_ex_streams) {
234 g_slist_free (demux->mut_ex_streams);
235 demux->mut_ex_streams = NULL;
238 demux->state = GST_ASF_DEMUX_STATE_HEADER;
239 g_free (demux->objpath);
240 demux->objpath = NULL;
241 g_strfreev (demux->languages);
242 demux->languages = NULL;
243 demux->num_languages = 0;
244 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
246 g_slist_free (demux->ext_stream_props);
247 demux->ext_stream_props = NULL;
249 while (demux->old_num_streams > 0) {
250 gst_asf_demux_free_stream (demux,
251 &demux->old_stream[demux->old_num_streams - 1]);
252 --demux->old_num_streams;
254 memset (demux->old_stream, 0, sizeof (demux->old_stream));
255 demux->old_num_streams = 0;
257 /* when resetting for a new chained asf, we don't want to remove the pads
258 * before adding the new ones */
260 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
261 demux->old_num_streams = demux->num_streams;
262 demux->num_streams = 0;
265 while (demux->num_streams > 0) {
266 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
267 --demux->num_streams;
269 memset (demux->stream, 0, sizeof (demux->stream));
271 /* do not remove those for not adding pads with same name */
272 demux->num_audio_streams = 0;
273 demux->num_video_streams = 0;
274 demux->have_group_id = FALSE;
275 demux->group_id = G_MAXUINT;
277 demux->num_streams = 0;
278 demux->activated_streams = FALSE;
279 demux->first_ts = GST_CLOCK_TIME_NONE;
280 demux->segment_ts = GST_CLOCK_TIME_NONE;
283 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
284 demux->state = GST_ASF_DEMUX_STATE_HEADER;
285 demux->seekable = FALSE;
286 demux->broadcast = FALSE;
287 demux->sidx_interval = 0;
288 demux->sidx_num_entries = 0;
289 g_free (demux->sidx_entries);
290 demux->sidx_entries = NULL;
292 demux->speed_packets = 1;
294 demux->asf_3D_mode = GST_ASF_3D_NONE;
297 GST_LOG_OBJECT (demux, "Restarting");
298 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
299 demux->need_newsegment = TRUE;
300 demux->segment_seqnum = 0;
301 demux->segment_running = FALSE;
302 demux->keyunit_sync = FALSE;
303 demux->accurate = FALSE;
304 demux->data_size = 0;
305 demux->data_offset = 0;
306 demux->index_offset = 0;
308 demux->base_offset = 0;
311 g_slist_free (demux->other_streams);
312 demux->other_streams = NULL;
316 gst_asf_demux_init (GstASFDemux * demux)
319 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
320 gst_pad_set_chain_function (demux->sinkpad,
321 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
322 gst_pad_set_event_function (demux->sinkpad,
323 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
324 gst_pad_set_activate_function (demux->sinkpad,
325 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
326 gst_pad_set_activatemode_function (demux->sinkpad,
327 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
328 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
330 /* set initial state */
331 gst_asf_demux_reset (demux, FALSE);
335 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
340 query = gst_query_new_scheduling ();
342 if (!gst_pad_peer_query (sinkpad, query)) {
343 gst_query_unref (query);
347 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
348 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
349 gst_query_unref (query);
354 GST_DEBUG_OBJECT (sinkpad, "activating pull");
355 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
359 GST_DEBUG_OBJECT (sinkpad, "activating push");
360 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
365 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
366 GstPadMode mode, gboolean active)
371 demux = GST_ASF_DEMUX (parent);
374 case GST_PAD_MODE_PUSH:
375 demux->state = GST_ASF_DEMUX_STATE_HEADER;
376 demux->streaming = TRUE;
379 case GST_PAD_MODE_PULL:
381 demux->state = GST_ASF_DEMUX_STATE_HEADER;
382 demux->streaming = FALSE;
384 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
387 res = gst_pad_stop_task (sinkpad);
398 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
403 demux = GST_ASF_DEMUX (parent);
405 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
406 switch (GST_EVENT_TYPE (event)) {
407 case GST_EVENT_SEGMENT:{
408 const GstSegment *segment;
410 gst_event_parse_segment (event, &segment);
412 if (segment->format == GST_FORMAT_BYTES) {
413 if (demux->packet_size && segment->start > demux->data_offset)
414 demux->packet = (segment->start - demux->data_offset) /
418 } else if (segment->format == GST_FORMAT_TIME) {
419 /* do not know packet position, not really a problem */
422 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
423 gst_event_unref (event);
427 /* record upstream segment for interpolation */
428 if (segment->format != demux->in_segment.format)
429 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
430 gst_segment_copy_into (segment, &demux->in_segment);
432 /* in either case, clear some state and generate newsegment later on */
433 GST_OBJECT_LOCK (demux);
434 demux->segment_ts = GST_CLOCK_TIME_NONE;
435 demux->in_gap = GST_CLOCK_TIME_NONE;
436 demux->need_newsegment = TRUE;
437 demux->segment_seqnum = gst_event_get_seqnum (event);
438 gst_asf_demux_reset_stream_state_after_discont (demux);
439 /* if we seek back after reaching EOS, go back to packet reading state */
440 if (demux->data_offset > 0 && segment->start >= demux->data_offset
441 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
442 demux->state = GST_ASF_DEMUX_STATE_DATA;
444 GST_OBJECT_UNLOCK (demux);
446 gst_event_unref (event);
452 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
453 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
454 (_("This stream contains no data.")),
455 ("got eos and didn't receive a complete header object"));
458 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
459 if (!demux->activated_streams) {
460 /* If we still haven't got activated streams, the file is most likely corrupt */
461 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
462 (_("This stream contains no data.")),
463 ("got eos and didn't receive a complete header object"));
466 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
467 GST_ELEMENT_FLOW_ERROR (demux, flow);
471 GST_OBJECT_LOCK (demux);
472 gst_adapter_clear (demux->adapter);
473 GST_OBJECT_UNLOCK (demux);
474 gst_asf_demux_send_event_unlocked (demux, event);
478 case GST_EVENT_FLUSH_STOP:
479 GST_OBJECT_LOCK (demux);
480 gst_asf_demux_reset_stream_state_after_discont (demux);
481 GST_OBJECT_UNLOCK (demux);
482 gst_asf_demux_send_event_unlocked (demux, event);
483 /* upon activation, latency is no longer introduced, e.g. after seek */
484 if (demux->activated_streams)
489 ret = gst_pad_event_default (pad, parent, event);
497 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
498 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
499 gboolean next, gboolean * eos)
501 GstClockTime idx_time;
507 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
510 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
513 /* if we want the next keyframe, we have to go forward till we find
514 a different packet number */
516 if (idx >= demux->sidx_num_entries - 1) {
517 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
522 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
523 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
530 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
536 *packet = demux->sidx_entries[idx].packet;
538 *speed = demux->sidx_entries[idx].count;
540 /* so we get closer to the actual time of the packet ... actually, let's not
541 * do this, since we throw away superfluous payloads before the seek position
542 * anyway; this way, our key unit seek 'snap resolution' is a bit better
543 * (ie. same as index resolution) */
545 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
549 idx_time = demux->sidx_interval * idx;
550 if (G_LIKELY (idx_time >= demux->preroll))
551 idx_time -= demux->preroll;
553 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
554 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
555 GST_TIME_ARGS (idx_time));
557 if (G_LIKELY (p_idx_time))
558 *p_idx_time = idx_time;
564 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
568 gst_adapter_clear (demux->adapter);
570 GST_DEBUG_OBJECT (demux, "reset stream state");
572 gst_flow_combiner_reset (demux->flowcombiner);
573 for (n = 0; n < demux->num_streams; n++) {
574 demux->stream[n].discont = TRUE;
575 demux->stream[n].first_buffer = TRUE;
577 while (demux->stream[n].payloads->len > 0) {
581 last = demux->stream[n].payloads->len - 1;
582 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
583 gst_buffer_replace (&payload->buf, NULL);
584 g_array_remove_index (demux->stream[n].payloads, last);
590 gst_asf_demux_mark_discont (GstASFDemux * demux)
594 GST_DEBUG_OBJECT (demux, "Mark stream discont");
596 for (n = 0; n < demux->num_streams; n++)
597 demux->stream[n].discont = TRUE;
600 /* do a seek in push based mode */
602 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
607 GstSeekType cur_type, stop_type;
611 GstEvent *byte_event;
613 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
616 stop_type = GST_SEEK_TYPE_NONE;
619 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
621 /* determine packet, by index or by estimation */
622 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
625 (guint) gst_util_uint64_scale (demux->num_packets, cur,
629 if (packet > demux->num_packets) {
630 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
635 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
637 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
639 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
640 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
641 /* BYTE seek event */
642 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
643 cur, stop_type, stop);
644 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
645 res = gst_pad_push_event (demux->sinkpad, byte_event);
651 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
654 GstClockTime idx_time;
657 GstSeekType cur_type, stop_type;
659 gboolean only_need_update;
660 gboolean after, before, next;
665 guint packet, speed_count = 1;
671 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
674 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
675 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
679 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
680 demux->num_packets == 0 || demux->play_time == 0)) {
681 GST_LOG_OBJECT (demux, "stream is not seekable");
685 if (G_UNLIKELY (!demux->activated_streams)) {
686 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
690 if (G_UNLIKELY (rate <= 0.0)) {
691 GST_LOG_OBJECT (demux, "backward playback");
692 demux->seek_to_cur_pos = TRUE;
693 for (i = 0; i < demux->num_streams; i++) {
694 demux->stream[i].reverse_kf_ready = FALSE;
698 seqnum = gst_event_get_seqnum (event);
699 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
701 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
702 demux->keyunit_sync =
703 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
704 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
705 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
706 next = after && !before;
708 if (G_UNLIKELY (demux->streaming)) {
709 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
710 * so first try to let it handle the seek event. */
711 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
714 /* support it safely needs more segment handling, e.g. closing etc */
716 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
719 /* we can (re)construct the start later on, but not the end */
720 if (stop_type != GST_SEEK_TYPE_NONE &&
721 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
722 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
725 return gst_asf_demux_handle_seek_push (demux, event);
728 /* unlock the streaming thread */
729 if (G_LIKELY (flush)) {
730 fevent = gst_event_new_flush_start ();
732 gst_event_set_seqnum (fevent, seqnum);
733 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
734 gst_asf_demux_send_event_unlocked (demux, fevent);
736 gst_pad_pause_task (demux->sinkpad);
739 /* grab the stream lock so that streaming cannot continue, for
740 * non flushing seeks when the element is in PAUSED this could block
742 GST_PAD_STREAM_LOCK (demux->sinkpad);
744 if (G_LIKELY (flush)) {
745 /* we now can stop flushing, since we have the stream lock now */
746 fevent = gst_event_new_flush_stop (TRUE);
747 gst_event_set_seqnum (fevent, seqnum);
748 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
749 gst_asf_demux_send_event_unlocked (demux, fevent);
752 /* operating on copy of segment until we know the seek worked */
753 segment = demux->segment;
755 if (!gst_segment_do_seek (&segment, rate, format, flags, cur_type,
756 cur, stop_type, stop, &only_need_update)) {
761 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
762 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
764 if (cur_type != GST_SEEK_TYPE_SET)
765 seek_time = segment.start;
769 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
770 * real start of data and segment_start to indexed time for key unit seek*/
771 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
772 &idx_time, &speed_count, next, &eos))) {
776 demux->packet = demux->num_packets;
780 /* First try to query our source to see if it can convert for us. This is
781 the case when our source is an mms stream, notice that in this case
782 gstmms will do a time based seek to get the byte offset, this is not a
783 problem as the seek to this offset needs to happen anyway. */
784 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
785 GST_FORMAT_BYTES, &offset)) {
786 packet = (offset - demux->data_offset) / demux->packet_size;
787 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
788 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
789 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
790 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
791 demux->packet_size, packet);
793 /* FIXME: For streams containing video, seek to an earlier position in
794 * the hope of hitting a keyframe and let the sinks throw away the stuff
795 * before the segment start. For audio-only this is unnecessary as every
797 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
798 && demux->num_video_streams > 0) {
799 seek_time -= 5 * GST_SECOND;
804 packet = (guint) gst_util_uint64_scale (demux->num_packets,
805 seek_time, demux->play_time);
807 if (packet > demux->num_packets)
808 packet = demux->num_packets;
811 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
812 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
813 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
814 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
815 segment.start = idx_time;
816 segment.position = idx_time;
817 segment.time = idx_time;
821 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
823 GST_OBJECT_LOCK (demux);
824 demux->segment = segment;
825 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
826 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
827 stop, demux->play_time);
829 demux->packet = packet;
832 demux->need_newsegment = TRUE;
833 demux->segment_seqnum = seqnum;
834 demux->speed_packets =
835 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
836 gst_asf_demux_reset_stream_state_after_discont (demux);
837 GST_OBJECT_UNLOCK (demux);
840 /* restart our task since it might have been stopped when we did the flush */
841 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
844 /* streaming can continue now */
845 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
851 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
857 demux = GST_ASF_DEMUX (parent);
859 switch (GST_EVENT_TYPE (event)) {
861 GST_LOG_OBJECT (pad, "seek event");
862 ret = gst_asf_demux_handle_seek_event (demux, event);
863 gst_event_unref (event);
866 case GST_EVENT_NAVIGATION:
867 /* just drop these two silently */
868 gst_event_unref (event);
872 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
873 ret = gst_pad_event_default (pad, parent, event);
880 static inline guint32
881 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
885 ret = gst_asf_identify_guid (guids, guid);
887 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
888 gst_asf_get_guid_nick (guids, ret),
889 guid->v1, guid->v2, guid->v3, guid->v4);
901 /* Peek for an object.
903 * Returns FALSE is the object is corrupted (such as the reported
904 * object size being greater than 2**32bits.
907 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
908 guint data_len, AsfObject * object, gboolean expect)
912 /* Callers should have made sure that data_len is big enough */
913 g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
915 if (data_len < ASF_OBJECT_HEADER_SIZE)
918 guid.v1 = GST_READ_UINT32_LE (data + 0);
919 guid.v2 = GST_READ_UINT32_LE (data + 4);
920 guid.v3 = GST_READ_UINT32_LE (data + 8);
921 guid.v4 = GST_READ_UINT32_LE (data + 12);
923 /* FIXME: make asf_demux_identify_object_guid() */
924 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
925 if (object->id == ASF_OBJ_UNDEFINED && expect) {
926 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
927 guid.v1, guid.v2, guid.v3, guid.v4);
930 object->size = GST_READ_UINT64_LE (data + 16);
931 if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
932 GST_WARNING_OBJECT (demux,
933 "ASF Object size corrupted (greater than 32bit)");
942 gst_asf_demux_release_old_pads (GstASFDemux * demux)
944 GST_DEBUG_OBJECT (demux, "Releasing old pads");
946 while (demux->old_num_streams > 0) {
947 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
948 gst_event_new_eos ());
949 gst_asf_demux_free_stream (demux,
950 &demux->old_stream[demux->old_num_streams - 1]);
951 --demux->old_num_streams;
953 memset (demux->old_stream, 0, sizeof (demux->old_stream));
954 demux->old_num_streams = 0;
958 gst_asf_demux_chain_headers (GstASFDemux * demux)
961 guint8 *header_data, *data = NULL;
962 const guint8 *cdata = NULL;
964 GstFlowReturn flow = GST_FLOW_OK;
966 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
970 if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
972 if (obj.id != ASF_OBJ_HEADER)
975 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
977 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
978 if (gst_adapter_available (demux->adapter) < obj.size + 50)
981 data = gst_adapter_take (demux->adapter, obj.size + 50);
984 header_size = obj.size;
985 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
986 if (flow != GST_FLOW_OK)
989 /* calculate where the packet data starts */
990 demux->data_offset = obj.size + 50;
992 /* now parse the beginning of the ASF_OBJ_DATA object */
993 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
996 if (demux->num_streams == 0)
1005 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
1012 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1013 ("This doesn't seem to be an ASF file"));
1015 return GST_FLOW_ERROR;
1020 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1021 ("header parsing failed, or no streams found, flow = %s",
1022 gst_flow_get_name (flow)));
1024 return GST_FLOW_ERROR;
1029 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1030 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1035 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1038 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1040 if (G_LIKELY (p_flow))
1043 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1044 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1045 "+%u", gst_flow_get_name (flow), offset, size);
1050 g_assert (*p_buf != NULL);
1052 buffer_size = gst_buffer_get_size (*p_buf);
1053 if (G_UNLIKELY (buffer_size < size)) {
1054 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1055 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1056 gst_buffer_unref (*p_buf);
1057 if (G_LIKELY (p_flow))
1058 *p_flow = GST_FLOW_EOS;
1066 static GstFlowReturn
1067 gst_asf_demux_pull_indices (GstASFDemux * demux)
1069 GstBuffer *buf = NULL;
1072 GstFlowReturn ret = GST_FLOW_OK;
1074 offset = demux->index_offset;
1076 if (G_UNLIKELY (offset == 0)) {
1077 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1082 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1088 gst_buffer_map (buf, &map, GST_MAP_READ);
1089 g_assert (map.size >= 16 + 8);
1090 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1091 GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
1092 GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
1094 gst_buffer_unmap (buf, &map);
1095 gst_buffer_replace (&buf, NULL);
1096 /* Non-fatal, return */
1099 gst_buffer_unmap (buf, &map);
1100 gst_buffer_replace (&buf, NULL);
1102 /* check for sanity */
1103 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1104 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1108 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1112 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1113 ", size %u", offset, (guint) obj.size);
1115 offset += obj.size; /* increase before _process_object changes it */
1117 gst_buffer_map (buf, &map, GST_MAP_READ);
1118 g_assert (map.size >= obj.size);
1119 bufdata = (guint8 *) map.data;
1120 obj_size = obj.size;
1121 ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
1122 gst_buffer_unmap (buf, &map);
1123 gst_buffer_replace (&buf, NULL);
1125 if (ret == ASF_FLOW_NEED_MORE_DATA) {
1126 /* Since indices are at the end of the file, if we need more data,
1127 * we consider it as a non-fatal corrupted index */
1132 if (G_UNLIKELY (ret != GST_FLOW_OK))
1138 GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
1139 gst_flow_get_name (ret));
1144 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1148 if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
1149 GST_WARNING_OBJECT (demux, "Corrupted data");
1152 if (obj.id != ASF_OBJ_DATA) {
1153 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1157 demux->state = GST_ASF_DEMUX_STATE_DATA;
1159 if (!demux->broadcast && obj.size > 50) {
1160 demux->data_size = obj.size - 50;
1161 /* CHECKME: for at least one file this is off by +158 bytes?! */
1162 demux->index_offset = demux->data_offset + demux->data_size;
1164 demux->data_size = 0;
1165 demux->index_offset = 0;
1170 if (!demux->broadcast) {
1171 /* skip object header (24 bytes) and file GUID (16 bytes) */
1172 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1174 demux->num_packets = 0;
1177 if (demux->num_packets == 0)
1178 demux->seekable = FALSE;
1180 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1181 if (demux->data_size == 0 && demux->num_packets > 0) {
1182 demux->data_size = demux->num_packets * demux->packet_size;
1183 demux->index_offset = demux->data_offset + demux->data_size;
1186 /* process pending stream objects and create pads for those */
1187 gst_asf_demux_process_queued_extended_stream_objects (demux);
1189 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1190 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1191 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1192 demux->data_offset, demux->data_size, demux->index_offset);
1198 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1200 GstFlowReturn flow = GST_FLOW_OK;
1202 GstBuffer *buf = NULL;
1207 GST_LOG_OBJECT (demux, "reading headers");
1209 /* pull HEADER object header, so we know its size */
1210 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1213 gst_buffer_map (buf, &map, GST_MAP_READ);
1214 g_assert (map.size >= 16 + 8);
1215 if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
1216 gst_buffer_unmap (buf, &map);
1217 gst_buffer_replace (&buf, NULL);
1218 flow = GST_FLOW_ERROR;
1221 gst_buffer_unmap (buf, &map);
1222 gst_buffer_replace (&buf, NULL);
1224 if (obj.id != ASF_OBJ_HEADER)
1227 GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
1229 /* pull HEADER object */
1230 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1234 size = obj.size; /* don't want obj.size changed */
1235 gst_buffer_map (buf, &map, GST_MAP_READ);
1236 g_assert (map.size >= size);
1237 bufdata = (guint8 *) map.data;
1238 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1239 gst_buffer_unmap (buf, &map);
1240 gst_buffer_replace (&buf, NULL);
1242 if (flow != GST_FLOW_OK) {
1243 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1247 /* calculate where the packet data starts */
1248 demux->data_offset = demux->base_offset + obj.size + 50;
1250 /* now pull beginning of DATA object before packet data */
1251 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1255 gst_buffer_map (buf, &map, GST_MAP_READ);
1256 g_assert (map.size >= size);
1257 bufdata = (guint8 *) map.data;
1258 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1261 if (demux->num_streams == 0)
1264 gst_buffer_unmap (buf, &map);
1265 gst_buffer_replace (&buf, NULL);
1273 gst_buffer_unmap (buf, &map);
1274 gst_buffer_replace (&buf, NULL);
1276 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1277 ("This doesn't seem to be an ASF file"));
1278 *pflow = GST_FLOW_ERROR;
1283 flow = GST_FLOW_ERROR;
1284 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1285 ("header parsing failed, or no streams found, flow = %s",
1286 gst_flow_get_name (flow)));
1291 gst_buffer_unmap (buf, &map);
1292 gst_buffer_replace (&buf, NULL);
1293 if (flow == ASF_FLOW_NEED_MORE_DATA)
1294 flow = GST_FLOW_ERROR;
1301 all_streams_prerolled (GstASFDemux * demux)
1303 GstClockTime preroll_time;
1304 guint i, num_no_data = 0;
1305 AsfStreamType prerolled_types = 0, all_types = 0;
1307 /* Allow at least 500ms of preroll_time */
1308 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1310 /* returns TRUE as long as there isn't a stream which (a) has data queued
1311 * and (b) the timestamp of last piece of data queued is < demux->preroll
1312 * AND there is at least one other stream with data queued */
1313 for (i = 0; i < demux->num_streams; ++i) {
1314 AsfPayload *last_payload = NULL;
1318 stream = &demux->stream[i];
1320 all_types |= stream->type;
1322 if (G_UNLIKELY (stream->payloads->len == 0)) {
1324 GST_LOG_OBJECT (stream->pad, "no data queued");
1328 prerolled_types |= stream->type;
1330 /* find last payload with timestamp */
1331 for (last_idx = stream->payloads->len - 1;
1332 last_idx >= 0 && (last_payload == NULL
1333 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1334 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1337 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1338 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1339 GST_TIME_ARGS (preroll_time));
1340 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1341 || last_payload->ts <= preroll_time)) {
1342 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1347 GST_LOG_OBJECT (demux, "all_types:%d prerolled_types:%d",
1348 all_types, prerolled_types);
1350 /* If streams of each present type have prerolled, we are good to go */
1351 if (all_types != 0 && prerolled_types == all_types)
1354 if (G_UNLIKELY (num_no_data > 0))
1362 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1367 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1370 /* check for each mutual exclusion group whether it affects this stream */
1371 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1372 if (*mes == stream->id) {
1373 /* we are in this group; let's check if we've already activated streams
1374 * that are in the same group (and hence mutually exclusive to this
1376 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1379 for (i = 0; i < demux->num_streams; ++i) {
1380 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1381 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1382 "to already active stream with ID %d", stream->id,
1383 demux->stream[i].id);
1388 /* we can only be in this group once, let's break out and move on to
1389 * the next mutual exclusion group */
1400 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1402 /* remember the first queued timestamp for the segment */
1403 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1404 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1405 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1406 GST_TIME_ARGS (demux->first_ts));
1407 demux->segment_ts = payload_ts;
1408 /* always note, but only determines segment when streaming */
1409 if (demux->streaming)
1410 if (!gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1411 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1412 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0,
1414 GST_WARNING_OBJECT (demux, "Initial segment seek failed");
1420 gst_asf_demux_get_first_ts (GstASFDemux * demux)
1422 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1423 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1426 /* go trhough each stream, find smallest timestamp */
1427 for (i = 0; i < demux->num_streams; ++i) {
1430 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1431 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1432 stream = &demux->stream[i];
1434 for (j = 0; j < stream->payloads->len; ++j) {
1435 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1436 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1437 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1438 || stream_min_ts > payload->ts)) {
1439 stream_min_ts = payload->ts;
1441 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1442 payload->ts > stream_min_ts &&
1443 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1444 || stream_min_ts2 > payload->ts)) {
1445 stream_min_ts2 = payload->ts;
1449 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1450 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1451 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1452 from it. I haven't found a better way to distinguish between these two, except to set an arbitrary boundary
1453 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1455 GST_DEBUG_OBJECT (demux,
1456 "stream #%u stream_min_ts %" GST_TIME_FORMAT " stream_min_ts2 %"
1457 GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (stream_min_ts),
1458 GST_TIME_ARGS (stream_min_ts2));
1460 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1461 stream_min_ts = stream_min_ts2;
1463 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1464 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1465 first_ts = stream_min_ts;
1468 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen */
1471 demux->first_ts = first_ts;
1473 /* update packets queued before we knew first timestamp */
1474 for (i = 0; i < demux->num_streams; ++i) {
1477 stream = &demux->stream[i];
1479 for (j = 0; j < stream->payloads->len; ++j) {
1480 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1481 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1482 if (payload->ts > first_ts)
1483 payload->ts -= first_ts;
1491 gst_asf_demux_check_segment_ts (demux, 0);
1497 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1499 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1500 and often set wrong, inspecting the data is the only way that seem to be working */
1501 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1502 GstCaps *caps = NULL;
1504 GstAdapter *adapter = gst_adapter_new ();
1506 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1508 AsfPayload *payload;
1511 payload = &g_array_index (stream->payloads, AsfPayload, i);
1512 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1513 len = gst_adapter_available (adapter);
1514 data = gst_adapter_map (adapter, len);
1518 #define MIN_LENGTH 128
1520 /* look for the sync points */
1522 if (len < MIN_LENGTH || /* give typefind something to work on */
1523 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1524 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1530 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1533 if (prob < GST_TYPE_FIND_LIKELY) {
1536 if (len > MIN_LENGTH)
1537 /* this wasn't it, look for another sync point */
1541 gst_adapter_unmap (adapter);
1544 gst_object_unref (adapter);
1547 gst_caps_take (&stream->caps, caps);
1555 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1557 guint i, actual_streams = 0;
1559 if (demux->activated_streams)
1562 if (!all_streams_prerolled (demux) && !force) {
1563 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1567 if (G_UNLIKELY (!gst_asf_demux_get_first_ts (demux)))
1570 for (i = 0; i < demux->num_streams; ++i) {
1571 AsfStream *stream = &demux->stream[i];
1573 if (stream->payloads->len > 0) {
1575 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1576 !stream->active && /* do not inspect active streams (caps were already set) */
1577 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1578 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1579 /* try to gather some more data */
1582 /* we don't check mutual exclusion stuff here; either we have data for
1583 * a stream, then we active it, or we don't, then we'll ignore it */
1584 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1585 gst_asf_demux_activate_stream (demux, stream);
1586 actual_streams += 1;
1588 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1592 if (actual_streams == 0) {
1593 /* We don't have any streams activated ! */
1594 GST_ERROR_OBJECT (demux, "No streams activated!");
1598 gst_asf_demux_release_old_pads (demux);
1600 demux->activated_streams = TRUE;
1601 GST_LOG_OBJECT (demux, "signalling no more pads");
1602 gst_element_no_more_pads (GST_ELEMENT (demux));
1606 /* returns the stream that has a complete payload with the lowest timestamp
1607 * queued, or NULL (we push things by timestamp because during the internal
1608 * prerolling we might accumulate more data then the external queues can take,
1609 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1611 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1613 AsfPayload *best_payload = NULL;
1614 AsfStream *best_stream = NULL;
1617 for (i = 0; i < demux->num_streams; ++i) {
1621 stream = &demux->stream[i];
1623 /* Don't push any data until we have at least one payload that falls within
1624 * the current segment. This way we can remove out-of-segment payloads that
1625 * don't need to be decoded after a seek, sending only data from the
1626 * keyframe directly before our segment start */
1627 if (stream->payloads->len > 0) {
1628 AsfPayload *payload = NULL;
1631 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1632 /* Reverse playback */
1634 if (stream->is_video) {
1635 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1636 if (stream->reverse_kf_ready) {
1638 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1639 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1640 /* TODO : remove payload from the list? */
1647 /* find first complete payload with timestamp */
1648 for (j = stream->payloads->len - 1;
1649 j >= 0 && (payload == NULL
1650 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1651 payload = &g_array_index (stream->payloads, AsfPayload, j);
1654 /* If there's a complete payload queued for this stream */
1655 if (!gst_asf_payload_is_complete (payload))
1661 /* find last payload with timestamp */
1662 for (last_idx = stream->payloads->len - 1;
1663 last_idx >= 0 && (payload == NULL
1664 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1665 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1668 /* if this is first payload after seek we might need to update the segment */
1669 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1670 gst_asf_demux_check_segment_ts (demux, payload->ts);
1672 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1673 (payload->ts < demux->segment.start))) {
1674 if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
1675 && payload->keyframe)) {
1676 GST_DEBUG_OBJECT (stream->pad,
1677 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1678 GST_TIME_ARGS (payload->ts));
1679 demux->segment.start = payload->ts;
1680 demux->segment.time = payload->ts;
1682 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1683 GST_TIME_FORMAT " which is before our segment start %"
1684 GST_TIME_FORMAT ", not pushing yet",
1685 GST_TIME_ARGS (payload->ts),
1686 GST_TIME_ARGS (demux->segment.start));
1691 /* find first complete payload with timestamp */
1693 j < stream->payloads->len && (payload == NULL
1694 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1695 payload = &g_array_index (stream->payloads, AsfPayload, j);
1698 /* Now see if there's a complete payload queued for this stream */
1699 if (!gst_asf_payload_is_complete (payload))
1703 /* ... and whether its timestamp is lower than the current best */
1704 if (best_stream == NULL || best_payload->ts > payload->ts) {
1705 best_stream = stream;
1706 best_payload = payload;
1714 static GstFlowReturn
1715 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1718 GstFlowReturn ret = GST_FLOW_OK;
1720 if (G_UNLIKELY (!demux->activated_streams)) {
1721 if (!gst_asf_demux_check_activate_streams (demux, force))
1723 /* streams are now activated */
1726 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1727 AsfPayload *payload;
1728 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1729 GstClockTime duration = GST_CLOCK_TIME_NONE;
1731 /* wait until we had a chance to "lock on" some payload's timestamp */
1732 if (G_UNLIKELY (demux->need_newsegment
1733 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1736 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1737 && stream->payloads->len) {
1738 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1740 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1743 /* do we need to send a newsegment event */
1744 if ((G_UNLIKELY (demux->need_newsegment))) {
1745 GstEvent *segment_event;
1747 /* safe default if insufficient upstream info */
1748 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1751 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1752 demux->segment.duration > 0) {
1753 /* slight HACK; prevent clipping of last bit */
1754 demux->segment.stop = demux->segment.duration + demux->in_gap;
1757 /* FIXME : only if ACCURATE ! */
1758 if (G_LIKELY (demux->keyunit_sync && !demux->accurate
1759 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1760 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1761 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1762 GST_TIME_ARGS (payload->ts));
1763 demux->segment.start = payload->ts;
1764 demux->segment.time = payload->ts;
1767 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1770 /* note: we fix up all timestamps to start from 0, so this should be ok */
1771 segment_event = gst_event_new_segment (&demux->segment);
1772 if (demux->segment_seqnum)
1773 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1774 gst_asf_demux_send_event_unlocked (demux, segment_event);
1776 /* now post any global tags we may have found */
1777 if (demux->taglist == NULL) {
1778 demux->taglist = gst_tag_list_new_empty ();
1779 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1782 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1783 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1785 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1786 gst_asf_demux_send_event_unlocked (demux,
1787 gst_event_new_tag (demux->taglist));
1788 demux->taglist = NULL;
1790 demux->need_newsegment = FALSE;
1791 demux->segment_seqnum = 0;
1792 demux->segment_running = TRUE;
1795 /* Do we have tags pending for this stream? */
1796 if (G_UNLIKELY (stream->pending_tags)) {
1797 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1798 gst_pad_push_event (stream->pad,
1799 gst_event_new_tag (stream->pending_tags));
1800 stream->pending_tags = NULL;
1803 /* We have the whole packet now so we should push the packet to
1804 * the src pad now. First though we should check if we need to do
1806 if (G_UNLIKELY (stream->span > 1)) {
1807 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1810 payload->buf = gst_buffer_make_writable (payload->buf);
1812 if (G_LIKELY (!payload->keyframe)) {
1813 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1816 if (G_UNLIKELY (stream->discont)) {
1817 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1818 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1819 stream->discont = FALSE;
1822 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1823 (payload->par_x != stream->par_x) &&
1824 (payload->par_y != stream->par_y))) {
1825 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1826 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1827 stream->par_x = payload->par_x;
1828 stream->par_y = payload->par_y;
1829 stream->caps = gst_caps_make_writable (stream->caps);
1830 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1831 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1832 gst_pad_set_caps (stream->pad, stream->caps);
1835 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1836 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1837 payload->interlaced);
1838 stream->interlaced = payload->interlaced;
1839 stream->caps = gst_caps_make_writable (stream->caps);
1840 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1841 (stream->interlaced ? "mixed" : "progressive"), NULL);
1842 gst_pad_set_caps (stream->pad, stream->caps);
1845 /* (sort of) interpolate timestamps using upstream "frame of reference",
1846 * typically useful for live src, but might (unavoidably) mess with
1847 * position reporting if a live src is playing not so live content
1848 * (e.g. rtspsrc taking some time to fall back to tcp) */
1849 timestamp = payload->ts;
1850 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1851 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1852 timestamp += demux->in_gap;
1854 /* Check if we're after the segment already, if so no need to push
1856 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1857 GST_DEBUG_OBJECT (stream->pad,
1858 "Payload after segment stop %" GST_TIME_FORMAT,
1859 GST_TIME_ARGS (demux->segment.stop));
1861 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1863 gst_buffer_unref (payload->buf);
1864 payload->buf = NULL;
1865 g_array_remove_index (stream->payloads, 0);
1866 /* Break out as soon as we have an issue */
1867 if (G_UNLIKELY (ret != GST_FLOW_OK))
1874 GST_BUFFER_PTS (payload->buf) = timestamp;
1876 if (payload->duration == GST_CLOCK_TIME_NONE
1877 && stream->ext_props.avg_time_per_frame != 0) {
1878 duration = stream->ext_props.avg_time_per_frame * 100;
1880 duration = payload->duration;
1882 GST_BUFFER_DURATION (payload->buf) = duration;
1884 /* FIXME: we should really set durations on buffers if we can */
1886 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1889 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1890 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1891 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1893 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1894 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1898 if (stream->active) {
1899 if (G_UNLIKELY (stream->first_buffer)) {
1900 if (stream->streamheader != NULL) {
1901 GST_DEBUG_OBJECT (stream->pad,
1902 "Pushing streamheader before first buffer");
1903 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1905 stream->first_buffer = FALSE;
1908 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1909 && timestamp > demux->segment.position) {
1910 demux->segment.position = timestamp;
1911 if (GST_CLOCK_TIME_IS_VALID (duration))
1912 demux->segment.position += timestamp;
1915 ret = gst_pad_push (stream->pad, payload->buf);
1917 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1920 gst_buffer_unref (payload->buf);
1923 payload->buf = NULL;
1924 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1925 && stream->reverse_kf_ready) {
1926 g_array_remove_index (stream->payloads, stream->kf_pos);
1929 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1931 stream->reverse_kf_ready = FALSE;
1934 g_array_remove_index (stream->payloads, 0);
1937 /* Break out as soon as we have an issue */
1938 if (G_UNLIKELY (ret != GST_FLOW_OK))
1946 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1951 g_assert (buf != NULL);
1953 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1955 gst_buffer_map (buf, &map, GST_MAP_READ);
1957 /* we return false on buffer too small */
1958 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1959 gst_buffer_unmap (buf, &map);
1963 /* check if it is a header */
1965 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
1967 gst_buffer_unmap (buf, &map);
1968 if (valid && obj.id == ASF_OBJ_HEADER) {
1975 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1977 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1978 GstFlowReturn ret = GST_FLOW_OK;
1979 GstBuffer *buf = NULL;
1980 gboolean header = FALSE;
1982 /* TODO maybe we should skip index objects after the data and look
1983 * further for a new header */
1984 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1985 g_assert (buf != NULL);
1986 /* check if it is a header */
1987 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1988 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1989 demux->base_offset = off;
1993 gst_buffer_unref (buf);
2000 gst_asf_demux_loop (GstASFDemux * demux)
2002 GstFlowReturn flow = GST_FLOW_OK;
2003 GstBuffer *buf = NULL;
2006 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
2007 if (!gst_asf_demux_pull_headers (demux, &flow)) {
2011 flow = gst_asf_demux_pull_indices (demux);
2012 if (flow != GST_FLOW_OK)
2016 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
2018 if (G_UNLIKELY (demux->num_packets != 0
2019 && demux->packet >= demux->num_packets))
2022 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
2023 (guint) demux->num_packets);
2025 off = demux->data_offset + (demux->packet * demux->packet_size);
2027 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
2028 demux->packet_size * demux->speed_packets, &buf, &flow))) {
2029 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
2030 if (flow == GST_FLOW_EOS) {
2032 } else if (flow == GST_FLOW_FLUSHING) {
2033 GST_DEBUG_OBJECT (demux, "Not fatal");
2040 if (G_LIKELY (demux->speed_packets == 1)) {
2041 GstAsfDemuxParsePacketError err;
2042 err = gst_asf_demux_parse_packet (demux, buf);
2043 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2044 /* when we don't know when the data object ends, we should check
2045 * for a chained asf */
2046 if (demux->num_packets == 0) {
2047 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
2048 GST_INFO_OBJECT (demux, "Chained asf found");
2049 demux->base_offset = off;
2050 gst_asf_demux_reset (demux, TRUE);
2051 gst_buffer_unref (buf);
2055 /* FIXME: We should tally up fatal errors and error out only
2056 * after a few broken packets in a row? */
2058 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2059 gst_buffer_unref (buf);
2061 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2062 && !demux->seek_to_cur_pos) {
2064 if (demux->packet < 0) {
2074 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2076 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2077 && !demux->seek_to_cur_pos) {
2079 if (demux->packet < 0) {
2088 for (n = 0; n < demux->speed_packets; n++) {
2090 GstAsfDemuxParsePacketError err;
2093 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2094 n * demux->packet_size, demux->packet_size);
2095 err = gst_asf_demux_parse_packet (demux, sub);
2096 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2097 /* when we don't know when the data object ends, we should check
2098 * for a chained asf */
2099 if (demux->num_packets == 0) {
2100 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2101 GST_INFO_OBJECT (demux, "Chained asf found");
2102 demux->base_offset = off + n * demux->packet_size;
2103 gst_asf_demux_reset (demux, TRUE);
2104 gst_buffer_unref (sub);
2105 gst_buffer_unref (buf);
2109 /* FIXME: We should tally up fatal errors and error out only
2110 * after a few broken packets in a row? */
2112 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2116 gst_buffer_unref (sub);
2118 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2119 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2125 /* reset speed pull */
2126 demux->speed_packets = 1;
2129 gst_buffer_unref (buf);
2131 if (G_UNLIKELY ((demux->num_packets > 0
2132 && demux->packet >= demux->num_packets)
2133 || flow == GST_FLOW_EOS)) {
2134 GST_LOG_OBJECT (demux, "reached EOS");
2138 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2139 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2143 /* check if we're at the end of the configured segment */
2144 /* FIXME: check if segment end reached etc. */
2150 /* if we haven't activated our streams yet, this might be because we have
2151 * less data queued than required for preroll; force stream activation and
2152 * send any pending payloads before sending EOS */
2153 if (!demux->activated_streams)
2154 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2156 /* we want to push an eos or post a segment-done in any case */
2157 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2160 /* for segment playback we need to post when (in stream time)
2161 * we stopped, this is either stop (when set) or the duration. */
2162 if ((stop = demux->segment.stop) == -1)
2163 stop = demux->segment.duration;
2165 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2166 gst_element_post_message (GST_ELEMENT_CAST (demux),
2167 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2169 gst_asf_demux_send_event_unlocked (demux,
2170 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2171 } else if (flow != GST_FLOW_EOS) {
2172 /* check if we have a chained asf, in case, we don't eos yet */
2173 if (gst_asf_demux_check_chained_asf (demux)) {
2174 GST_INFO_OBJECT (demux, "Chained ASF starting");
2175 gst_asf_demux_reset (demux, TRUE);
2180 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2181 if (demux->activated_streams) {
2182 /* normal playback, send EOS to all linked pads */
2183 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2184 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2186 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2187 flow = GST_FLOW_EOS;
2190 /* ... and fall through to pause */
2194 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2195 gst_flow_get_name (flow));
2196 demux->segment_running = FALSE;
2197 gst_pad_pause_task (demux->sinkpad);
2199 /* For the error cases */
2200 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2201 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2202 ("This doesn't seem to be an ASF file"));
2203 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2204 /* Post an error. Hopefully something else already has, but if not... */
2205 GST_ELEMENT_FLOW_ERROR (demux, flow);
2206 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2215 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2216 flow = GST_FLOW_EOS;
2220 /* See FIXMEs above */
2223 gst_buffer_unref (buf);
2224 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2225 ("Error parsing ASF packet %u", (guint) demux->packet));
2226 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2227 flow = GST_FLOW_ERROR;
2233 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2234 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2235 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2238 gst_asf_demux_check_header (GstASFDemux * demux)
2241 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2242 ASF_OBJECT_HEADER_SIZE);
2243 if (cdata == NULL) /* need more data */
2244 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2246 if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
2247 && obj.id == ASF_OBJ_HEADER) {
2248 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2251 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2254 static GstFlowReturn
2255 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2257 GstFlowReturn ret = GST_FLOW_OK;
2260 demux = GST_ASF_DEMUX (parent);
2262 GST_LOG_OBJECT (demux,
2263 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2264 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2265 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2267 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2268 GST_DEBUG_OBJECT (demux, "received DISCONT");
2269 gst_asf_demux_mark_discont (demux);
2272 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2273 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2274 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2275 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2276 ", interpolation gap: %" GST_TIME_FORMAT,
2277 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2280 gst_adapter_push (demux->adapter, buf);
2282 switch (demux->state) {
2283 case GST_ASF_DEMUX_STATE_INDEX:{
2284 gint result = gst_asf_demux_check_header (demux);
2285 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2288 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2289 /* we don't care about this, probably an index */
2290 /* TODO maybe would be smarter to skip all the indices
2291 * until we got a new header or EOS to decide */
2292 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2295 GST_INFO_OBJECT (demux, "Chained asf starting");
2296 /* cleanup and get ready for a chained asf */
2297 gst_asf_demux_reset (demux, TRUE);
2301 case GST_ASF_DEMUX_STATE_HEADER:{
2302 ret = gst_asf_demux_chain_headers (demux);
2303 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2305 /* otherwise fall through */
2307 case GST_ASF_DEMUX_STATE_DATA:
2311 data_size = demux->packet_size;
2313 while (gst_adapter_available (demux->adapter) >= data_size) {
2315 GstAsfDemuxParsePacketError err;
2317 /* we don't know the length of the stream
2318 * check for a chained asf every time */
2319 if (demux->num_packets == 0) {
2320 gint result = gst_asf_demux_check_header (demux);
2322 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2323 GST_INFO_OBJECT (demux, "Chained asf starting");
2324 /* cleanup and get ready for a chained asf */
2325 gst_asf_demux_reset (demux, TRUE);
2328 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2329 && demux->packet >= demux->num_packets)) {
2330 /* do not overshoot data section when streaming */
2334 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2336 /* FIXME: We should tally up fatal errors and error out only
2337 * after a few broken packets in a row? */
2338 err = gst_asf_demux_parse_packet (demux, buf);
2340 gst_buffer_unref (buf);
2342 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2343 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2345 GST_WARNING_OBJECT (demux, "Parse error");
2347 if (demux->packet >= 0)
2350 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2351 && demux->packet >= demux->num_packets)) {
2352 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2357 g_assert_not_reached ();
2361 if (ret != GST_FLOW_OK)
2362 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2368 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2374 static inline gboolean
2375 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2377 if (*p_size < num_bytes)
2380 *p_data += num_bytes;
2381 *p_size -= num_bytes;
2385 static inline guint8
2386 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2390 g_assert (*p_size >= 1);
2391 ret = GST_READ_UINT8 (*p_data);
2392 *p_data += sizeof (guint8);
2393 *p_size -= sizeof (guint8);
2397 static inline guint16
2398 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2402 g_assert (*p_size >= 2);
2403 ret = GST_READ_UINT16_LE (*p_data);
2404 *p_data += sizeof (guint16);
2405 *p_size -= sizeof (guint16);
2409 static inline guint32
2410 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2414 g_assert (*p_size >= 4);
2415 ret = GST_READ_UINT32_LE (*p_data);
2416 *p_data += sizeof (guint32);
2417 *p_size -= sizeof (guint32);
2421 static inline guint64
2422 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2426 g_assert (*p_size >= 8);
2427 ret = GST_READ_UINT64_LE (*p_data);
2428 *p_data += sizeof (guint64);
2429 *p_size -= sizeof (guint64);
2434 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2435 guint8 ** p_data, guint64 * p_size)
2439 if (*p_size < num_bytes_to_read)
2442 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2443 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2445 *p_data += num_bytes_to_read;
2446 *p_size -= num_bytes_to_read;
2452 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2453 guint8 ** p_data, guint64 * p_size)
2457 if (*p_size < num_bytes_to_read)
2460 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2461 *p_data += num_bytes_to_read;
2462 *p_size -= num_bytes_to_read;
2467 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2468 guint8 ** p_data, guint64 * p_size)
2478 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2481 *p_strlen = s_length;
2483 if (s_length == 0) {
2484 GST_WARNING ("zero-length string");
2485 *p_str = g_strdup ("");
2489 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2492 g_assert (s != NULL);
2494 /* just because They don't exist doesn't
2495 * mean They are not out to get you ... */
2496 if (s[s_length - 1] != '\0') {
2497 s = g_realloc (s, s_length + 1);
2501 *p_str = (gchar *) s;
2507 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2509 g_assert (*p_size >= 4 * sizeof (guint32));
2511 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2512 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2513 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2514 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2518 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2521 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2524 /* WAVEFORMATEX Structure */
2525 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2526 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2527 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2528 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2529 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2530 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2531 /* Codec specific data size */
2532 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2533 if (audio->size > *p_size) {
2534 GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
2535 G_GUINT64_FORMAT " long)", audio->size, *p_size);
2542 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2545 if (*p_size < (4 + 4 + 1 + 2))
2548 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2549 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2550 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2551 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2556 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2557 guint8 ** p_data, guint64 * p_size)
2559 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2562 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2564 if (fmt->size < 40) {
2565 GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
2568 if ((guint64) fmt->size - 4 > *p_size) {
2569 GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
2572 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2573 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2574 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2575 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2576 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2577 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2578 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2579 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2580 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2581 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2586 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2590 for (i = 0; i < demux->num_streams; i++) {
2591 if (demux->stream[i].id == id)
2592 return &demux->stream[i];
2595 if (gst_asf_demux_is_unknown_stream (demux, id))
2596 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2601 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2602 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2607 gst_pad_use_fixed_caps (src_pad);
2608 gst_pad_set_caps (src_pad, caps);
2610 gst_pad_set_event_function (src_pad,
2611 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2612 gst_pad_set_query_function (src_pad,
2613 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2615 stream = &demux->stream[demux->num_streams];
2616 stream->caps = caps;
2617 stream->pad = src_pad;
2619 stream->fps_known = !is_video; /* bit hacky for audio */
2620 stream->is_video = is_video;
2621 stream->pending_tags = tags;
2622 stream->discont = TRUE;
2623 stream->first_buffer = TRUE;
2624 stream->streamheader = streamheader;
2625 if (stream->streamheader) {
2626 stream->streamheader = gst_buffer_make_writable (streamheader);
2627 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2632 st = gst_caps_get_structure (caps, 0);
2633 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2634 par_x > 0 && par_y > 0) {
2635 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2636 stream->par_x = par_x;
2637 stream->par_y = par_y;
2641 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2643 /* TODO: create this array during reverse play? */
2644 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2646 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2647 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2649 ++demux->num_streams;
2651 stream->active = FALSE;
2657 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2658 GstBuffer * buffer, GstStructure * structure)
2660 GValue arr_val = G_VALUE_INIT;
2661 GValue buf_val = G_VALUE_INIT;
2663 g_value_init (&arr_val, GST_TYPE_ARRAY);
2664 g_value_init (&buf_val, GST_TYPE_BUFFER);
2666 gst_value_set_buffer (&buf_val, buffer);
2667 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2669 gst_structure_take_value (structure, "streamheader", &arr_val);
2673 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2674 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2676 GstTagList *tags = NULL;
2677 GstBuffer *extradata = NULL;
2680 guint16 size_left = 0;
2681 gchar *codec_name = NULL;
2684 size_left = audio->size;
2686 /* Create the audio pad */
2687 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2689 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2692 /* Swallow up any left over data and set up the
2693 * standard properties from the header info */
2695 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2696 "codec specific data", size_left);
2698 g_assert (size_left <= *p_size);
2699 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2702 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2703 * additional two bytes indicating extradata. */
2704 /* FIXME: Handle the channel reorder map here */
2705 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2706 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2709 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2710 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2713 /* Informing about that audio format we just added */
2715 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2716 g_free (codec_name);
2719 if (audio->byte_rate > 0) {
2720 /* Some ASF files have no bitrate props object (often seen with
2721 * ASF files that contain raw audio data). Example files can
2722 * be generated with FFmpeg (tested with v2.8.6), like this:
2724 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2726 * In this case, if audio->byte_rate is nonzero, use that as
2729 guint bitrate = audio->byte_rate * 8;
2732 tags = gst_tag_list_new_empty ();
2734 /* Add bitrate, but only if there is none set already, since
2735 * this is just a fallback in case there is no bitrate tag
2736 * already present */
2737 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2741 gst_buffer_unref (extradata);
2743 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2744 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2745 audio->codec_tag, tags);
2747 ++demux->num_audio_streams;
2749 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2753 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2754 asf_stream_video_format * video, guint16 id,
2755 guint8 ** p_data, guint64 * p_size)
2757 GstTagList *tags = NULL;
2758 GstStructure *caps_s;
2759 GstBuffer *extradata = NULL;
2764 gchar *codec_name = NULL;
2765 guint64 size_left = video->size - 40;
2766 GstBuffer *streamheader = NULL;
2767 guint par_w = 1, par_h = 1;
2769 /* Create the video pad */
2770 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2771 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2774 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2776 GST_LOG ("Video header has %" G_GUINT64_FORMAT
2777 " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
2779 g_assert (size_left <= *p_size);
2780 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2783 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2785 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2786 caps = gst_riff_create_video_caps (video->tag, NULL,
2787 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2790 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2791 G_TYPE_UINT, video->tag, NULL);
2796 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2797 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2798 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2801 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2805 /* retry with the global metadata */
2806 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2807 demux->global_metadata);
2808 s = demux->global_metadata;
2809 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2810 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2811 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2812 if (ax > 0 && ay > 0) {
2815 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2820 s = gst_caps_get_structure (caps, 0);
2821 gst_structure_remove_field (s, "framerate");
2824 caps_s = gst_caps_get_structure (caps, 0);
2826 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2827 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2828 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2829 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2832 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2833 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2834 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2836 GstBuffer *buf = gst_value_get_buffer (value);
2839 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2840 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2841 /* this looks like a bytestream start */
2842 streamheader = gst_buffer_ref (buf);
2843 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2844 gst_structure_remove_field (caps_s, "codec_data");
2845 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING,
2846 "byte-stream", NULL);
2848 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "avc",
2852 gst_buffer_unmap (buf, &mapinfo);
2855 gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "byte-stream",
2860 /* For a 3D video, set multiview information into the caps based on
2861 * what was detected during object parsing */
2862 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2863 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2864 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2865 const gchar *mview_mode_str;
2867 switch (demux->asf_3D_mode) {
2868 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2869 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2871 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2872 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2873 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2875 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2876 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2878 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2879 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2880 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2882 case GST_ASF_3D_DUAL_STREAM:{
2883 gboolean is_right_view = FALSE;
2884 /* if Advanced_Mutual_Exclusion object exists, use it
2885 * to figure out which is the left view (lower ID) */
2886 if (demux->mut_ex_streams != NULL) {
2890 length = g_slist_length (demux->mut_ex_streams);
2892 for (i = 0; i < length; i++) {
2895 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2897 GST_DEBUG_OBJECT (demux,
2898 "has Mutual_Exclusion object. stream id in object is %d",
2899 GPOINTER_TO_INT (v_s_id));
2901 if (id > GPOINTER_TO_INT (v_s_id))
2902 is_right_view = TRUE;
2905 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2906 * first video stream encountered has the lower ID */
2907 if (demux->num_video_streams > 0) {
2908 /* This is not the first video stream, assuming right eye view */
2909 is_right_view = TRUE;
2913 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2915 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2922 GST_INFO_OBJECT (demux,
2923 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2926 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2927 if (mview_mode_str != NULL) {
2928 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2929 video->height, par_w, par_h))
2930 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2932 gst_caps_set_simple (caps,
2933 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2934 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2935 GST_FLAG_SET_MASK_EXACT, NULL);
2940 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2941 g_free (codec_name);
2945 gst_buffer_unref (extradata);
2947 GST_INFO ("Adding video stream #%u, id %u, codec %"
2948 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2949 GST_FOURCC_ARGS (video->tag), video->tag);
2951 ++demux->num_video_streams;
2953 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2954 streamheader, tags);
2958 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2960 if (!stream->active) {
2964 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2965 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2966 gst_pad_set_active (stream->pad, TRUE);
2969 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2970 "%03u", stream->id);
2973 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2975 if (gst_event_parse_group_id (event, &demux->group_id))
2976 demux->have_group_id = TRUE;
2978 demux->have_group_id = FALSE;
2979 gst_event_unref (event);
2980 } else if (!demux->have_group_id) {
2981 demux->have_group_id = TRUE;
2982 demux->group_id = gst_util_group_id_next ();
2985 event = gst_event_new_stream_start (stream_id);
2986 if (demux->have_group_id)
2987 gst_event_set_group_id (event, demux->group_id);
2989 gst_pad_push_event (stream->pad, event);
2991 gst_pad_set_caps (stream->pad, stream->caps);
2993 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2994 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2995 stream->active = TRUE;
3000 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
3003 AsfCorrectionType correction_type;
3004 AsfStreamType stream_type;
3005 GstClockTime time_offset;
3006 gboolean is_encrypted G_GNUC_UNUSED;
3010 guint stream_specific_size;
3011 guint type_specific_size G_GNUC_UNUSED;
3012 guint unknown G_GNUC_UNUSED;
3013 gboolean inspect_payload = FALSE;
3014 AsfStream *stream = NULL;
3016 /* Get the rest of the header's header */
3017 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
3018 goto not_enough_data;
3020 gst_asf_demux_get_guid (&guid, &data, &size);
3021 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
3023 gst_asf_demux_get_guid (&guid, &data, &size);
3024 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
3026 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
3028 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3029 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
3031 flags = gst_asf_demux_get_uint16 (&data, &size);
3032 stream_id = flags & 0x7f;
3033 is_encrypted = ! !(flags & 0x8000);
3034 unknown = gst_asf_demux_get_uint32 (&data, &size);
3036 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
3037 stream_id, GST_TIME_ARGS (time_offset));
3039 /* dvr-ms has audio stream declared in stream specific data */
3040 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
3041 AsfExtStreamType ext_stream_type;
3042 gst_asf_demux_get_guid (&guid, &data, &size);
3043 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
3045 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
3046 inspect_payload = TRUE;
3048 gst_asf_demux_get_guid (&guid, &data, &size);
3049 gst_asf_demux_get_uint32 (&data, &size);
3050 gst_asf_demux_get_uint32 (&data, &size);
3051 gst_asf_demux_get_uint32 (&data, &size);
3052 gst_asf_demux_get_guid (&guid, &data, &size);
3053 gst_asf_demux_get_uint32 (&data, &size);
3054 stream_type = ASF_STREAM_AUDIO;
3058 switch (stream_type) {
3059 case ASF_STREAM_AUDIO:{
3060 asf_stream_audio audio_object;
3062 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
3063 goto not_enough_data;
3065 GST_INFO ("Object is an audio stream with %u bytes of additional data",
3068 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
3071 switch (correction_type) {
3072 case ASF_CORRECTION_ON:{
3073 guint span, packet_size, chunk_size, data_size, silence_data;
3075 GST_INFO ("Using error correction");
3077 if (size < (1 + 2 + 2 + 2 + 1))
3078 goto not_enough_data;
3080 span = gst_asf_demux_get_uint8 (&data, &size);
3081 packet_size = gst_asf_demux_get_uint16 (&data, &size);
3082 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
3083 data_size = gst_asf_demux_get_uint16 (&data, &size);
3084 silence_data = gst_asf_demux_get_uint8 (&data, &size);
3086 stream->span = span;
3088 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3089 packet_size, chunk_size, data_size, span, silence_data);
3091 if (stream->span > 1) {
3092 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3093 /* Disable descrambling */
3096 /* FIXME: this else branch was added for
3097 * weird_al_yankovic - the saga begins.asf */
3098 stream->ds_packet_size = packet_size;
3099 stream->ds_chunk_size = chunk_size;
3102 /* Descambling is enabled */
3103 stream->ds_packet_size = packet_size;
3104 stream->ds_chunk_size = chunk_size;
3107 /* Now skip the rest of the silence data */
3109 gst_bytestream_flush (demux->bs, data_size - 1);
3111 /* FIXME: CHECKME. And why -1? */
3112 if (data_size > 1) {
3113 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3114 goto not_enough_data;
3120 case ASF_CORRECTION_OFF:{
3121 GST_INFO ("Error correction off");
3122 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3123 goto not_enough_data;
3127 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3128 ("Audio stream using unknown error correction"));
3135 case ASF_STREAM_VIDEO:{
3136 asf_stream_video_format video_format_object;
3137 asf_stream_video video_object;
3140 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3141 goto not_enough_data;
3143 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3145 GST_INFO ("object is a video stream with %u bytes of "
3146 "additional data", vsize);
3148 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3150 goto not_enough_data;
3153 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3154 stream_id, &data, &size);
3160 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3162 demux->other_streams =
3163 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3168 stream->inspect_payload = inspect_payload;
3169 stream->type = stream_type;
3175 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3176 /* we'll error out later if we found no streams */
3181 static const gchar *
3182 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3187 const gchar *asf_name;
3188 const gchar *gst_name;
3191 "WM/Genre", GST_TAG_GENRE}, {
3192 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3193 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3194 "WM/PartOfSet", GST_TAG_ALBUM_VOLUME_COUNT}, {
3195 "WM/Picture", GST_TAG_IMAGE}, {
3196 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3197 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3198 "WM/Year", GST_TAG_DATE_TIME}
3199 /* { "WM/Composer", GST_TAG_COMPOSER } */
3205 if (name_utf8 == NULL) {
3206 GST_WARNING ("Failed to convert name to UTF8, skipping");
3210 out = strlen (name_utf8);
3212 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3213 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3214 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3215 return tags[i].gst_name;
3222 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3224 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3228 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3230 if (taglist == NULL)
3233 if (gst_tag_list_is_empty (taglist)) {
3234 gst_tag_list_unref (taglist);
3238 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3239 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3241 gst_tag_list_unref (demux->taglist);
3242 gst_tag_list_unref (taglist);
3244 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3247 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3248 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3249 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3250 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3253 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3257 const guint8 *img_data = NULL;
3258 guint32 img_data_len = 0;
3259 guint8 pic_type = 0;
3261 gst_byte_reader_init (&r, tag_data, tag_data_len);
3263 /* skip mime type string (we don't trust it and do our own typefinding),
3264 * and also skip the description string, since we don't use it */
3265 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3266 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3267 !gst_byte_reader_skip_string_utf16 (&r) ||
3268 !gst_byte_reader_skip_string_utf16 (&r) ||
3269 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3270 goto not_enough_data;
3274 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3275 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3281 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3282 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3287 /* Extended Content Description Object */
3288 static GstFlowReturn
3289 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3292 /* Other known (and unused) 'text/unicode' metadata available :
3295 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3296 * WMFSDKVersion = 9.00.00.2980
3297 * WMFSDKNeeded = 0.0.0.0000
3298 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3299 * WM/Publisher = 4AD
3301 * WM/ProviderRating = 8
3302 * WM/ProviderStyle = Rock (similar to WM/Genre)
3303 * WM/GenreID (similar to WM/Genre)
3304 * WM/TrackNumber (same as WM/Track but as a string)
3306 * Other known (and unused) 'non-text' metadata available :
3312 * We might want to read WM/TrackNumber and use atoi() if we don't have
3316 GstTagList *taglist;
3317 guint16 blockcount, i;
3318 gboolean content3D = FALSE;
3323 const gchar *interleave_name;
3324 GstASF3DMode interleaving_type;
3325 } stereoscopic_layout_map[] = {
3327 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3328 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3329 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3330 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3331 "DualStream", GST_ASF_3D_DUAL_STREAM}
3335 GST_INFO_OBJECT (demux, "object is an extended content description");
3337 taglist = gst_tag_list_new_empty ();
3339 /* Content Descriptor Count */
3341 goto not_enough_data;
3343 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3345 for (i = 1; i <= blockcount; ++i) {
3346 const gchar *gst_tag_name;
3350 GValue tag_value = { 0, };
3353 gchar *name_utf8 = NULL;
3357 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3358 goto not_enough_data;
3362 goto not_enough_data;
3364 /* Descriptor Value Data Type */
3365 datatype = gst_asf_demux_get_uint16 (&data, &size);
3367 /* Descriptor Value (not really a string, but same thing reading-wise) */
3368 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3370 goto not_enough_data;
3374 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3376 if (name_utf8 != NULL) {
3377 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3379 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3380 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3383 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3386 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3389 /* get rid of tags with empty value */
3390 if (value_utf8 != NULL && *value_utf8 != '\0') {
3391 GST_DEBUG ("string value %s", value_utf8);
3393 value_utf8[out] = '\0';
3395 if (gst_tag_name != NULL) {
3396 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3397 guint year = atoi (value_utf8);
3400 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3401 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3403 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3404 guint id3v1_genre_id;
3405 const gchar *genre_str;
3407 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3408 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3409 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3410 g_free (value_utf8);
3411 value_utf8 = g_strdup (genre_str);
3413 } else if (!strcmp (gst_tag_name, GST_TAG_ALBUM_VOLUME_COUNT)) {
3414 guint num = 0, count = 0;
3416 if (sscanf (value_utf8, "%u/%u", &num, &count) == 2
3417 && num > 0 && num <= 99999 && count > 0 && count <= 99999) {
3418 GST_DEBUG ("Disc %u of %u (%s)", num, count, value_utf8);
3419 g_value_init (&tag_value, G_TYPE_UINT);
3421 g_value_set_uint (&tag_value, num);
3422 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3423 GST_TAG_ALBUM_VOLUME_NUMBER, &tag_value, NULL);
3424 /* disc count (will be added to the taglist below) */
3425 g_value_set_uint (&tag_value, count);
3427 GST_DEBUG ("Couldn't parse PartOfSet value %s", value_utf8);
3432 /* convert tag from string to other type if required */
3433 tag_type = gst_tag_get_type (gst_tag_name);
3434 g_value_init (&tag_value, tag_type);
3435 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3436 GValue from_val = { 0, };
3438 g_value_init (&from_val, G_TYPE_STRING);
3439 g_value_set_string (&from_val, value_utf8);
3440 if (!g_value_transform (&from_val, &tag_value)) {
3441 GST_WARNING_OBJECT (demux,
3442 "Could not transform string tag to " "%s tag type %s",
3443 gst_tag_name, g_type_name (tag_type));
3444 g_value_unset (&tag_value);
3446 g_value_unset (&from_val);
3451 GST_DEBUG ("Setting metadata");
3452 g_value_init (&tag_value, G_TYPE_STRING);
3453 g_value_set_string (&tag_value, value_utf8);
3454 /* If we found a stereoscopic marker, look for StereoscopicLayout
3458 if (strncmp ("StereoscopicLayout", name_utf8,
3459 strlen (name_utf8)) == 0) {
3460 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3461 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3463 demux->asf_3D_mode =
3464 stereoscopic_layout_map[i].interleaving_type;
3465 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3469 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3471 demux->asf_3D_mode = GST_ASF_3D_NONE;
3472 GST_INFO_OBJECT (demux, "None 3d type");
3475 } else if (value_utf8 == NULL) {
3476 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3478 GST_DEBUG ("Skipping empty string value for %s",
3479 GST_STR_NULL (gst_tag_name));
3481 g_free (value_utf8);
3484 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3486 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3487 GST_FIXME ("Unhandled byte array tag %s",
3488 GST_STR_NULL (gst_tag_name));
3491 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3497 case ASF_DEMUX_DATA_TYPE_DWORD:{
3503 uint_val = GST_READ_UINT32_LE (value);
3505 /* this is the track number */
3506 g_value_init (&tag_value, G_TYPE_UINT);
3508 /* WM/Track counts from 0 */
3509 if (!strcmp (name_utf8, "WM/Track"))
3512 g_value_set_uint (&tag_value, uint_val);
3516 case ASF_DEMUX_DATA_TYPE_BOOL:{
3522 bool_val = GST_READ_UINT32_LE (value);
3524 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3526 GST_INFO_OBJECT (demux, "This is 3D contents");
3529 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3537 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3542 if (G_IS_VALUE (&tag_value)) {
3544 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3546 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3547 * is supposed to have a 0 base but is often wrongly written to start
3548 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3549 * replace the value added earlier from WM/Track or put it first in
3550 * the list, so that it will get picked up by _get_uint() */
3551 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3552 merge_mode = GST_TAG_MERGE_REPLACE;
3554 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3557 GST_DEBUG ("Setting global metadata %s", name_utf8);
3558 gst_structure_set_value (demux->global_metadata, name_utf8,
3562 g_value_unset (&tag_value);
3571 gst_asf_demux_add_global_tags (demux, taglist);
3578 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3579 gst_tag_list_unref (taglist);
3580 return GST_FLOW_OK; /* not really fatal */
3584 static GstStructure *
3585 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3590 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3592 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3595 s = gst_caps_get_structure (demux->metadata, i);
3596 if (gst_structure_has_name (s, sname))
3600 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3602 /* try lookup again; demux->metadata took ownership of the structure, so we
3603 * can't really make any assumptions about what happened to it, so we can't
3604 * just return it directly after appending it */
3605 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3608 static GstFlowReturn
3609 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3612 guint16 blockcount, i;
3614 GST_INFO_OBJECT (demux, "object is a metadata object");
3616 /* Content Descriptor Count */
3618 goto not_enough_data;
3620 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3622 for (i = 0; i < blockcount; ++i) {
3624 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3625 guint32 data_len, ival;
3628 if (size < (2 + 2 + 2 + 2 + 4))
3629 goto not_enough_data;
3631 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3632 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3633 name_len = gst_asf_demux_get_uint16 (&data, &size);
3634 data_type = gst_asf_demux_get_uint16 (&data, &size);
3635 data_len = gst_asf_demux_get_uint32 (&data, &size);
3637 if (size < name_len + data_len)
3638 goto not_enough_data;
3640 /* convert name to UTF-8 */
3641 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3643 gst_asf_demux_skip_bytes (name_len, &data, &size);
3645 if (name_utf8 == NULL) {
3646 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3647 gst_asf_demux_skip_bytes (data_len, &data, &size);
3651 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3652 gst_asf_demux_skip_bytes (data_len, &data, &size);
3660 goto not_enough_data;
3663 ival = gst_asf_demux_get_uint32 (&data, &size);
3665 /* skip anything else there may be, just in case */
3666 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3668 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3669 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3673 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3679 GST_WARNING ("Unexpected end of data parsing metadata object");
3680 return GST_FLOW_OK; /* not really fatal */
3684 static GstFlowReturn
3685 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3687 GstFlowReturn ret = GST_FLOW_OK;
3688 guint32 i, num_objects;
3689 guint8 unknown G_GNUC_UNUSED;
3691 /* Get the rest of the header's header */
3692 if (size < (4 + 1 + 1))
3693 goto not_enough_data;
3695 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3696 unknown = gst_asf_demux_get_uint8 (&data, &size);
3697 unknown = gst_asf_demux_get_uint8 (&data, &size);
3699 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3700 demux->saw_file_header = FALSE;
3701 /* Loop through the header's objects, processing those */
3702 for (i = 0; i < num_objects; ++i) {
3703 GST_INFO_OBJECT (demux, "reading header part %u", i);
3704 ret = gst_asf_demux_process_object (demux, &data, &size);
3705 if (ret != GST_FLOW_OK) {
3706 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3710 if (!demux->saw_file_header) {
3711 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3712 ("Header does not have mandatory FILE section"));
3713 return GST_FLOW_ERROR;
3720 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3721 ("short read parsing HEADER object"));
3722 return GST_FLOW_ERROR;
3726 static GstFlowReturn
3727 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3729 guint64 creation_time G_GNUC_UNUSED;
3730 guint64 file_size G_GNUC_UNUSED;
3731 guint64 send_time G_GNUC_UNUSED;
3732 guint64 packets_count, play_time, preroll;
3733 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3735 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3736 goto not_enough_data;
3738 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3739 file_size = gst_asf_demux_get_uint64 (&data, &size);
3740 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3741 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3742 play_time = gst_asf_demux_get_uint64 (&data, &size);
3743 send_time = gst_asf_demux_get_uint64 (&data, &size);
3744 preroll = gst_asf_demux_get_uint64 (&data, &size);
3745 flags = gst_asf_demux_get_uint32 (&data, &size);
3746 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3747 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3748 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3750 demux->broadcast = ! !(flags & 0x01);
3751 demux->seekable = ! !(flags & 0x02);
3753 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3754 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3755 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3757 if (demux->broadcast) {
3758 /* these fields are invalid if the broadcast flag is set */
3763 if (min_pktsize != max_pktsize)
3764 goto non_fixed_packet_size;
3766 demux->packet_size = max_pktsize;
3768 /* FIXME: do we need send_time as well? what is it? */
3769 if ((play_time * 100) >= (preroll * GST_MSECOND))
3770 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3772 demux->play_time = 0;
3774 demux->preroll = preroll * GST_MSECOND;
3776 /* initial latency */
3777 demux->latency = demux->preroll;
3779 if (demux->play_time == 0)
3780 demux->seekable = FALSE;
3782 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3783 GST_TIME_ARGS (demux->play_time));
3784 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3785 GST_TIME_ARGS (demux->preroll));
3787 if (demux->play_time > 0) {
3788 demux->segment.duration = demux->play_time;
3791 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3793 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3795 demux->saw_file_header = TRUE;
3800 non_fixed_packet_size:
3802 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3803 ("packet size must be fixed"));
3804 return GST_FLOW_ERROR;
3808 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3809 ("short read parsing FILE object"));
3810 return GST_FLOW_ERROR;
3814 /* Content Description Object */
3815 static GstFlowReturn
3816 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3821 const gchar *gst_tag;
3826 GST_TAG_TITLE, 0, NULL}, {
3827 GST_TAG_ARTIST, 0, NULL}, {
3828 GST_TAG_COPYRIGHT, 0, NULL}, {
3829 GST_TAG_DESCRIPTION, 0, NULL}, {
3830 GST_TAG_COMMENT, 0, NULL}
3833 GstTagList *taglist;
3834 GValue value = { 0 };
3838 GST_INFO_OBJECT (demux, "object is a comment");
3840 if (size < (2 + 2 + 2 + 2 + 2))
3841 goto not_enough_data;
3843 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3844 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3845 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3846 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3847 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3849 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3850 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3851 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3853 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3854 if (size < tags[i].val_length)
3855 goto not_enough_data;
3857 /* might be just '/0', '/0'... */
3858 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3859 /* convert to UTF-8 */
3860 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3861 "UTF-8", "UTF-16LE", &in, &out, NULL);
3863 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3866 /* parse metadata into taglist */
3867 taglist = gst_tag_list_new_empty ();
3868 g_value_init (&value, G_TYPE_STRING);
3869 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3870 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3871 g_value_set_string (&value, tags[i].val_utf8);
3872 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3873 tags[i].gst_tag, &value, NULL);
3876 g_value_unset (&value);
3878 gst_asf_demux_add_global_tags (demux, taglist);
3880 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3881 g_free (tags[i].val_utf8);
3887 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3888 "comment tag section %d, skipping comment object", i);
3889 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3890 g_free (tags[i].val_utf8);
3891 return GST_FLOW_OK; /* not really fatal */
3895 static GstFlowReturn
3896 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3899 guint16 num_streams, i;
3903 goto not_enough_data;
3905 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3907 GST_INFO ("object is a bitrate properties object with %u streams",
3910 if (size < (num_streams * (2 + 4)))
3911 goto not_enough_data;
3913 for (i = 0; i < num_streams; ++i) {
3917 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3918 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3920 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3921 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3922 stream = gst_asf_demux_get_stream (demux, stream_id);
3924 if (stream->pending_tags == NULL)
3925 stream->pending_tags = gst_tag_list_new_empty ();
3926 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3927 GST_TAG_BITRATE, bitrate, NULL);
3929 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3932 GST_WARNING ("stream id %u is too large", stream_id);
3940 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3941 return GST_FLOW_OK; /* not really fatal */
3945 static GstFlowReturn
3946 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3949 GstFlowReturn ret = GST_FLOW_OK;
3952 /* Get the rest of the header's header */
3953 if (size < (16 + 2 + 4))
3954 goto not_enough_data;
3956 /* skip GUID and two other bytes */
3957 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3958 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3960 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3962 /* FIXME: does data_size include the rest of the header that we have read? */
3963 if (hdr_size > size)
3964 goto not_enough_data;
3966 while (hdr_size > 0) {
3967 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3968 if (ret != GST_FLOW_OK)
3976 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3977 ("short read parsing extended header object"));
3978 return GST_FLOW_ERROR;
3982 static GstFlowReturn
3983 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3989 goto not_enough_data;
3991 if (demux->languages) {
3992 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3993 g_strfreev (demux->languages);
3994 demux->languages = NULL;
3995 demux->num_languages = 0;
3998 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3999 GST_LOG ("%u languages:", demux->num_languages);
4001 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
4002 for (i = 0; i < demux->num_languages; ++i) {
4003 guint8 len, *lang_data = NULL;
4006 goto not_enough_data;
4007 len = gst_asf_demux_get_uint8 (&data, &size);
4008 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
4011 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
4014 /* truncate "en-us" etc. to just "en" */
4015 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
4018 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
4019 demux->languages[i] = utf8;
4022 goto not_enough_data;
4030 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
4031 g_free (demux->languages);
4032 demux->languages = NULL;
4033 demux->num_languages = 0;
4034 return GST_FLOW_OK; /* not fatal */
4038 static GstFlowReturn
4039 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
4042 GstClockTime interval;
4045 if (size < (16 + 8 + 4 + 4))
4046 goto not_enough_data;
4049 gst_asf_demux_skip_bytes (16, &data, &size);
4050 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
4051 gst_asf_demux_skip_bytes (4, &data, &size);
4052 count = gst_asf_demux_get_uint32 (&data, &size);
4054 demux->sidx_interval = interval;
4055 demux->sidx_num_entries = count;
4056 g_free (demux->sidx_entries);
4057 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
4059 for (i = 0; i < count; ++i) {
4060 if (G_UNLIKELY (size < 6)) {
4061 /* adjust for broken files, to avoid having entries at the end
4062 * of the parsed index that point to time=0. Resulting in seeking to
4063 * the end of the file leading back to the beginning */
4064 demux->sidx_num_entries -= (count - i);
4067 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
4068 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
4069 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
4070 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
4071 demux->sidx_entries[i].count);
4074 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
4081 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
4082 return GST_FLOW_OK; /* not fatal */
4086 static GstFlowReturn
4087 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
4088 guint8 * data, guint64 size)
4093 if (size < 16 + 2 + (2 * 2))
4094 goto not_enough_data;
4096 gst_asf_demux_get_guid (&guid, &data, &size);
4097 num = gst_asf_demux_get_uint16 (&data, &size);
4100 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
4104 if (size < (num * sizeof (guint16)))
4105 goto not_enough_data;
4107 /* read mutually exclusive stream numbers */
4108 for (i = 0; i < num; ++i) {
4110 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
4111 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
4113 demux->mut_ex_streams =
4114 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
4123 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
4124 return GST_FLOW_OK; /* not absolutely fatal */
4129 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4131 return g_slist_find (demux->other_streams,
4132 GINT_TO_POINTER (stream_num)) == NULL;
4135 static GstFlowReturn
4136 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4139 AsfStreamExtProps esp;
4140 AsfStream *stream = NULL;
4141 AsfObject stream_obj;
4142 guint16 stream_name_count;
4143 guint16 num_payload_ext;
4145 guint8 *stream_obj_data = NULL;
4148 guint i, stream_num;
4151 obj_size = (guint) size;
4153 esp.payload_extensions = NULL;
4156 goto not_enough_data;
4159 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4160 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4161 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4162 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4163 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4164 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4165 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4166 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4167 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4168 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4169 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4170 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4171 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4172 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4173 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4175 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4176 GST_TIME_ARGS (esp.start_time));
4177 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4178 GST_TIME_ARGS (esp.end_time));
4179 GST_INFO ("flags = %08x", esp.flags);
4180 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4181 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4182 GST_INFO ("stream number = %u", stream_num);
4183 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4184 (esp.lang_idx < demux->num_languages) ?
4185 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4186 GST_INFO ("stream name count = %u", stream_name_count);
4188 /* read stream names */
4189 for (i = 0; i < stream_name_count; ++i) {
4190 guint16 stream_lang_idx G_GNUC_UNUSED;
4191 gchar *stream_name = NULL;
4194 goto not_enough_data;
4195 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4196 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4197 goto not_enough_data;
4198 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4199 g_free (stream_name); /* TODO: store names in struct */
4202 /* read payload extension systems stuff */
4203 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4205 if (num_payload_ext > 0)
4206 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4208 for (i = 0; i < num_payload_ext; ++i) {
4209 AsfPayloadExtension ext;
4211 guint32 sys_info_len;
4213 if (size < 16 + 2 + 4)
4214 goto not_enough_data;
4216 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4217 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4218 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4220 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4221 GST_LOG ("payload systems info len = %u", sys_info_len);
4222 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4223 goto not_enough_data;
4225 esp.payload_extensions[i] = ext;
4228 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4230 /* there might be an optional STREAM_INFO object here now; if not, we
4231 * should have parsed the corresponding stream info object already (since
4232 * we are parsing the extended stream properties objects delayed) */
4234 stream = gst_asf_demux_get_stream (demux, stream_num);
4238 if (size < ASF_OBJECT_HEADER_SIZE)
4239 goto not_enough_data;
4241 /* get size of the stream object */
4242 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4243 goto corrupted_stream;
4245 if (stream_obj.id != ASF_OBJ_STREAM)
4246 goto expected_stream_object;
4248 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4249 stream_obj.size > (10 * 1024 * 1024))
4250 goto not_enough_data;
4252 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4254 /* process this stream object later after all the other 'normal' ones
4255 * have been processed (since the others are more important/non-hidden) */
4256 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4257 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4258 goto not_enough_data;
4260 /* parse stream object */
4261 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4262 g_free (stream_obj_data);
4267 stream->ext_props = esp;
4269 /* try to set the framerate */
4270 if (stream->is_video && stream->caps) {
4271 GValue framerate = { 0 };
4275 g_value_init (&framerate, GST_TYPE_FRACTION);
4277 num = GST_SECOND / 100;
4278 denom = esp.avg_time_per_frame;
4280 /* avoid division by 0, assume 25/1 framerate */
4281 denom = GST_SECOND / 2500;
4284 gst_value_set_fraction (&framerate, num, denom);
4286 stream->caps = gst_caps_make_writable (stream->caps);
4287 s = gst_caps_get_structure (stream->caps, 0);
4288 gst_structure_set_value (s, "framerate", &framerate);
4289 g_value_unset (&framerate);
4290 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4291 num, denom, ((gdouble) num) / denom);
4294 /* add language info now if we have it */
4295 if (stream->ext_props.lang_idx < demux->num_languages) {
4296 if (stream->pending_tags == NULL)
4297 stream->pending_tags = gst_tag_list_new_empty ();
4298 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4299 demux->languages[stream->ext_props.lang_idx]);
4300 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4301 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4304 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4305 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4309 g_free (esp.payload_extensions);
4316 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4317 g_free (esp.payload_extensions);
4318 return GST_FLOW_OK; /* not absolutely fatal */
4320 expected_stream_object:
4322 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4323 "object: expected embedded stream object, but got %s object instead!",
4324 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4325 g_free (esp.payload_extensions);
4326 return GST_FLOW_OK; /* not absolutely fatal */
4330 GST_WARNING_OBJECT (demux, "Corrupted stream");
4331 g_free (esp.payload_extensions);
4332 return GST_FLOW_ERROR;
4336 static const gchar *
4337 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4341 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4342 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4343 nick += strlen ("ASF_OBJ_");
4345 if (demux->objpath == NULL) {
4346 demux->objpath = g_strdup (nick);
4350 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4351 g_free (demux->objpath);
4352 demux->objpath = newpath;
4355 return (const gchar *) demux->objpath;
4359 gst_asf_demux_pop_obj (GstASFDemux * demux)
4363 if ((s = g_strrstr (demux->objpath, "/"))) {
4366 g_free (demux->objpath);
4367 demux->objpath = NULL;
4372 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4377 /* Parse the queued extended stream property objects and add the info
4378 * to the existing streams or add the new embedded streams, but without
4379 * activating them yet */
4380 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4381 g_slist_length (demux->ext_stream_props));
4383 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4384 GstBuffer *buf = GST_BUFFER (l->data);
4387 gst_buffer_map (buf, &map, GST_MAP_READ);
4389 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4390 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4391 gst_buffer_unmap (buf, &map);
4392 gst_buffer_unref (buf);
4394 g_slist_free (demux->ext_stream_props);
4395 demux->ext_stream_props = NULL;
4400 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4404 for (i = 0; i < demux->num_streams; ++i) {
4409 stream = &demux->stream[i];
4411 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4413 if (stream->active) {
4414 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4419 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4422 /* check for each mutual exclusion whether it affects this stream */
4423 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4424 if (*mes == stream->id) {
4425 /* if yes, check if we've already added streams that are mutually
4426 * exclusive with the stream we're about to add */
4427 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4428 for (j = 0; j < demux->num_streams; ++j) {
4429 /* if the broadcast flag is set, assume the hidden streams aren't
4430 * actually streamed and hide them (or playbin won't work right),
4431 * otherwise assume their data is available */
4432 if (demux->stream[j].id == *mes && demux->broadcast) {
4434 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4435 "mutually exclusive with already existing stream ID %d, "
4436 "hiding stream", stream->id, demux->stream[j].id);
4448 /* FIXME: we should do stream activation based on preroll data in
4449 * streaming mode too */
4450 if (demux->streaming && !is_hidden)
4451 gst_asf_demux_activate_stream (demux, stream);
4456 static GstFlowReturn
4457 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4460 GstFlowReturn ret = GST_FLOW_OK;
4462 guint64 obj_data_size;
4464 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4465 return ASF_FLOW_NEED_MORE_DATA;
4467 if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
4469 return GST_FLOW_ERROR;
4470 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4472 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4474 if (*p_size < obj_data_size)
4475 return ASF_FLOW_NEED_MORE_DATA;
4477 gst_asf_demux_push_obj (demux, obj.id);
4479 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4482 case ASF_OBJ_STREAM:
4483 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4487 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4489 case ASF_OBJ_HEADER:
4490 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4492 case ASF_OBJ_COMMENT:
4493 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4496 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4498 case ASF_OBJ_BITRATE_PROPS:
4500 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4503 case ASF_OBJ_EXT_CONTENT_DESC:
4505 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4508 case ASF_OBJ_METADATA_OBJECT:
4509 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4511 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4514 /* process these later, we might not have parsed the corresponding
4515 * stream object yet */
4516 GST_LOG ("%s: queued for later parsing", demux->objpath);
4517 buf = gst_buffer_new_and_alloc (obj_data_size);
4518 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4519 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4523 case ASF_OBJ_LANGUAGE_LIST:
4524 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4526 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4527 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4530 case ASF_OBJ_SIMPLE_INDEX:
4531 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4533 case ASF_OBJ_CONTENT_ENCRYPTION:
4534 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4535 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4536 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4537 goto error_encrypted;
4538 case ASF_OBJ_CONCEAL_NONE:
4540 case ASF_OBJ_UNDEFINED:
4541 case ASF_OBJ_CODEC_COMMENT:
4543 case ASF_OBJ_PADDING:
4544 case ASF_OBJ_BITRATE_MUTEX:
4545 case ASF_OBJ_COMPATIBILITY:
4546 case ASF_OBJ_INDEX_PLACEHOLDER:
4547 case ASF_OBJ_INDEX_PARAMETERS:
4548 case ASF_OBJ_STREAM_PRIORITIZATION:
4549 case ASF_OBJ_SCRIPT_COMMAND:
4550 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4552 /* Unknown/unhandled object, skip it and hope for the best */
4553 GST_INFO ("%s: skipping object", demux->objpath);
4558 /* this can't fail, we checked the number of bytes available before */
4559 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4561 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4563 gst_asf_demux_pop_obj (demux);
4570 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4571 return GST_FLOW_ERROR;
4576 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4577 GstBuffer ** p_buffer)
4579 GstBuffer *descrambled_buffer;
4580 GstBuffer *scrambled_buffer;
4581 GstBuffer *sub_buffer;
4588 /* descrambled_buffer is initialised in the first iteration */
4589 descrambled_buffer = NULL;
4590 scrambled_buffer = *p_buffer;
4592 if (gst_buffer_get_size (scrambled_buffer) <
4593 stream->ds_packet_size * stream->span)
4596 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4597 offset += stream->ds_chunk_size) {
4598 off = offset / stream->ds_chunk_size;
4599 row = off / stream->span;
4600 col = off % stream->span;
4601 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4602 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4603 col, off, stream->ds_chunk_size);
4604 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4605 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4606 stream->span, stream->ds_packet_size);
4607 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4608 gst_buffer_get_size (scrambled_buffer));
4610 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4611 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4613 descrambled_buffer = sub_buffer;
4615 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4619 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4620 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4621 GST_BUFFER_DURATION (descrambled_buffer) =
4622 GST_BUFFER_DURATION (scrambled_buffer);
4623 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4624 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4625 GST_BUFFER_OFFSET_END (scrambled_buffer);
4627 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4629 gst_buffer_unref (scrambled_buffer);
4630 *p_buffer = descrambled_buffer;
4634 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4636 GstASFDemux *demux = GST_ASF_DEMUX (element);
4639 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4641 for (i = 0; i < demux->num_streams; ++i) {
4642 gst_event_ref (event);
4643 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4644 GST_OBJECT_CAST (element), event)) {
4645 gst_event_unref (event);
4650 gst_event_unref (event);
4654 /* takes ownership of the passed event */
4656 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4658 gboolean ret = TRUE;
4661 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4662 GST_EVENT_TYPE_NAME (event));
4664 for (i = 0; i < demux->num_streams; ++i) {
4665 gst_event_ref (event);
4666 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4668 gst_event_unref (event);
4673 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4677 gboolean res = FALSE;
4679 demux = GST_ASF_DEMUX (parent);
4681 GST_DEBUG ("handling %s query",
4682 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4684 switch (GST_QUERY_TYPE (query)) {
4685 case GST_QUERY_DURATION:
4689 gst_query_parse_duration (query, &format, NULL);
4691 if (format != GST_FORMAT_TIME) {
4692 GST_LOG ("only support duration queries in TIME format");
4696 res = gst_pad_query_default (pad, parent, query);
4698 GST_OBJECT_LOCK (demux);
4700 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4701 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4702 GST_TIME_ARGS (demux->segment.duration));
4704 gst_query_set_duration (query, GST_FORMAT_TIME,
4705 demux->segment.duration);
4709 GST_LOG ("duration not known yet");
4712 GST_OBJECT_UNLOCK (demux);
4717 case GST_QUERY_POSITION:{
4720 gst_query_parse_position (query, &format, NULL);
4722 if (format != GST_FORMAT_TIME) {
4723 GST_LOG ("only support position queries in TIME format");
4727 GST_OBJECT_LOCK (demux);
4729 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4730 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4731 GST_TIME_ARGS (demux->segment.position));
4733 gst_query_set_position (query, GST_FORMAT_TIME,
4734 demux->segment.position);
4738 GST_LOG ("position not known yet");
4741 GST_OBJECT_UNLOCK (demux);
4745 case GST_QUERY_SEEKING:{
4748 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4749 if (format == GST_FORMAT_TIME) {
4752 GST_OBJECT_LOCK (demux);
4753 duration = demux->segment.duration;
4754 GST_OBJECT_UNLOCK (demux);
4756 if (!demux->streaming || !demux->seekable) {
4757 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4764 /* try upstream first in TIME */
4765 res = gst_pad_query_default (pad, parent, query);
4767 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4768 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4769 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4770 /* if no luck, maybe in BYTES */
4771 if (!seekable || fmt != GST_FORMAT_TIME) {
4774 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4775 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4776 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4777 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4778 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4779 if (fmt != GST_FORMAT_BYTES)
4782 gst_query_unref (q);
4783 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4789 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4793 case GST_QUERY_LATENCY:
4796 GstClockTime min, max;
4798 /* preroll delay does not matter in non-live pipeline,
4799 * but we might end up in a live (rtsp) one ... */
4802 res = gst_pad_query_default (pad, parent, query);
4806 gst_query_parse_latency (query, &live, &min, &max);
4808 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4809 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4810 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4812 GST_OBJECT_LOCK (demux);
4813 min += demux->latency;
4815 max += demux->latency;
4816 GST_OBJECT_UNLOCK (demux);
4818 gst_query_set_latency (query, live, min, max);
4821 case GST_QUERY_SEGMENT:
4826 format = demux->segment.format;
4829 gst_segment_to_stream_time (&demux->segment, format,
4830 demux->segment.start);
4831 if ((stop = demux->segment.stop) == -1)
4832 stop = demux->segment.duration;
4834 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4836 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4841 res = gst_pad_query_default (pad, parent, query);
4849 gst_asf_demux_finalize (GObject * object)
4851 GstASFDemux *demux = GST_ASF_DEMUX (object);
4853 if (demux->metadata)
4854 gst_caps_unref (demux->metadata);
4855 demux->metadata = NULL;
4857 if (demux->global_metadata)
4858 gst_structure_free (demux->global_metadata);
4859 demux->global_metadata = NULL;
4861 G_OBJECT_CLASS (parent_class)->finalize (object);
4864 static GstStateChangeReturn
4865 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4867 GstASFDemux *demux = GST_ASF_DEMUX (element);
4868 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4870 switch (transition) {
4871 case GST_STATE_CHANGE_NULL_TO_READY:{
4872 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4873 demux->need_newsegment = TRUE;
4874 demux->segment_running = FALSE;
4875 demux->keyunit_sync = FALSE;
4876 demux->accurate = FALSE;
4877 demux->adapter = gst_adapter_new ();
4878 demux->data_size = 0;
4879 demux->data_offset = 0;
4880 demux->index_offset = 0;
4881 demux->base_offset = 0;
4882 demux->flowcombiner = gst_flow_combiner_new ();
4890 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4891 if (ret == GST_STATE_CHANGE_FAILURE)
4894 switch (transition) {
4895 case GST_STATE_CHANGE_PAUSED_TO_READY:
4896 gst_asf_demux_reset (demux, FALSE);
4899 case GST_STATE_CHANGE_READY_TO_NULL:
4900 gst_asf_demux_reset (demux, FALSE);
4901 gst_flow_combiner_free (demux->flowcombiner);
4902 demux->flowcombiner = NULL;