1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <gst/video/video.h>
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS ("video/x-ms-asf")
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE (16+8)
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA 99
76 #define gst_asf_get_flow_name(flow) \
77 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
78 "need-more-data" : gst_flow_get_name (flow)
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83 GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89 GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98 GstObject * parent, GstPadMode mode, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
103 GstFlowReturn * pflow);
104 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109 AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
123 GstElementClass *gstelement_class;
125 gstelement_class = (GstElementClass *) klass;
127 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
129 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 gst_element_class_add_static_pad_template (gstelement_class,
132 &audio_src_template);
133 gst_element_class_add_static_pad_template (gstelement_class,
134 &video_src_template);
135 gst_element_class_add_static_pad_template (gstelement_class,
136 &gst_asf_demux_sink_template);
138 gstelement_class->change_state =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140 gstelement_class->send_event =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 gst_caps_replace (&stream->caps, NULL);
148 if (stream->pending_tags) {
149 gst_tag_list_unref (stream->pending_tags);
150 stream->pending_tags = NULL;
152 if (stream->streamheader) {
153 gst_buffer_unref (stream->streamheader);
154 stream->streamheader = NULL;
157 if (stream->active) {
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
161 gst_object_unref (stream->pad);
165 if (stream->payloads) {
166 while (stream->payloads->len > 0) {
170 last = stream->payloads->len - 1;
171 payload = &g_array_index (stream->payloads, AsfPayload, last);
172 gst_buffer_replace (&payload->buf, NULL);
173 g_array_remove_index (stream->payloads, last);
175 g_array_free (stream->payloads, TRUE);
176 stream->payloads = NULL;
179 if (stream->payloads_rev) {
180 while (stream->payloads_rev->len > 0) {
184 last = stream->payloads_rev->len - 1;
185 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186 gst_buffer_replace (&payload->buf, NULL);
187 g_array_remove_index (stream->payloads_rev, last);
189 g_array_free (stream->payloads_rev, TRUE);
190 stream->payloads_rev = NULL;
193 if (stream->ext_props.valid) {
194 g_free (stream->ext_props.payload_extensions);
195 stream->ext_props.payload_extensions = NULL;
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
202 GST_LOG_OBJECT (demux, "resetting");
204 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205 demux->segment_running = FALSE;
206 if (demux->adapter && !chain_reset) {
207 gst_adapter_clear (demux->adapter);
208 g_object_unref (demux->adapter);
209 demux->adapter = NULL;
211 if (demux->taglist) {
212 gst_tag_list_unref (demux->taglist);
213 demux->taglist = NULL;
215 if (demux->metadata) {
216 gst_caps_unref (demux->metadata);
217 demux->metadata = NULL;
219 if (demux->global_metadata) {
220 gst_structure_free (demux->global_metadata);
221 demux->global_metadata = NULL;
223 if (demux->mut_ex_streams) {
224 g_slist_free (demux->mut_ex_streams);
225 demux->mut_ex_streams = NULL;
228 demux->state = GST_ASF_DEMUX_STATE_HEADER;
229 g_free (demux->objpath);
230 demux->objpath = NULL;
231 g_strfreev (demux->languages);
232 demux->languages = NULL;
233 demux->num_languages = 0;
234 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
236 g_slist_free (demux->ext_stream_props);
237 demux->ext_stream_props = NULL;
239 while (demux->old_num_streams > 0) {
240 gst_asf_demux_free_stream (demux,
241 &demux->old_stream[demux->old_num_streams - 1]);
242 --demux->old_num_streams;
244 memset (demux->old_stream, 0, sizeof (demux->old_stream));
245 demux->old_num_streams = 0;
247 /* when resetting for a new chained asf, we don't want to remove the pads
248 * before adding the new ones */
250 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251 demux->old_num_streams = demux->num_streams;
252 demux->num_streams = 0;
255 while (demux->num_streams > 0) {
256 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257 --demux->num_streams;
259 memset (demux->stream, 0, sizeof (demux->stream));
261 /* do not remove those for not adding pads with same name */
262 demux->num_audio_streams = 0;
263 demux->num_video_streams = 0;
264 demux->have_group_id = FALSE;
265 demux->group_id = G_MAXUINT;
267 demux->num_streams = 0;
268 demux->activated_streams = FALSE;
269 demux->first_ts = GST_CLOCK_TIME_NONE;
270 demux->segment_ts = GST_CLOCK_TIME_NONE;
273 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274 demux->state = GST_ASF_DEMUX_STATE_HEADER;
275 demux->seekable = FALSE;
276 demux->broadcast = FALSE;
277 demux->sidx_interval = 0;
278 demux->sidx_num_entries = 0;
279 g_free (demux->sidx_entries);
280 demux->sidx_entries = NULL;
282 demux->speed_packets = 1;
284 demux->asf_3D_mode = GST_ASF_3D_NONE;
287 GST_LOG_OBJECT (demux, "Restarting");
288 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289 demux->need_newsegment = TRUE;
290 demux->segment_seqnum = 0;
291 demux->segment_running = FALSE;
292 demux->keyunit_sync = FALSE;
293 demux->accurate = FALSE;
294 demux->metadata = gst_caps_new_empty ();
295 demux->global_metadata = gst_structure_new_empty ("metadata");
296 demux->data_size = 0;
297 demux->data_offset = 0;
298 demux->index_offset = 0;
300 demux->base_offset = 0;
303 g_slist_free (demux->other_streams);
304 demux->other_streams = NULL;
308 gst_asf_demux_init (GstASFDemux * demux)
311 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312 gst_pad_set_chain_function (demux->sinkpad,
313 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314 gst_pad_set_event_function (demux->sinkpad,
315 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316 gst_pad_set_activate_function (demux->sinkpad,
317 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318 gst_pad_set_activatemode_function (demux->sinkpad,
319 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
322 /* set initial state */
323 gst_asf_demux_reset (demux, FALSE);
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
332 query = gst_query_new_scheduling ();
334 if (!gst_pad_peer_query (sinkpad, query)) {
335 gst_query_unref (query);
339 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341 gst_query_unref (query);
346 GST_DEBUG_OBJECT (sinkpad, "activating pull");
347 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
351 GST_DEBUG_OBJECT (sinkpad, "activating push");
352 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358 GstPadMode mode, gboolean active)
363 demux = GST_ASF_DEMUX (parent);
366 case GST_PAD_MODE_PUSH:
367 demux->state = GST_ASF_DEMUX_STATE_HEADER;
368 demux->streaming = TRUE;
371 case GST_PAD_MODE_PULL:
373 demux->state = GST_ASF_DEMUX_STATE_HEADER;
374 demux->streaming = FALSE;
376 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
379 res = gst_pad_stop_task (sinkpad);
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
395 demux = GST_ASF_DEMUX (parent);
397 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398 switch (GST_EVENT_TYPE (event)) {
399 case GST_EVENT_SEGMENT:{
400 const GstSegment *segment;
402 gst_event_parse_segment (event, &segment);
404 if (segment->format == GST_FORMAT_BYTES) {
405 if (demux->packet_size && segment->start > demux->data_offset)
406 demux->packet = (segment->start - demux->data_offset) /
410 } else if (segment->format == GST_FORMAT_TIME) {
411 /* do not know packet position, not really a problem */
414 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415 gst_event_unref (event);
419 /* record upstream segment for interpolation */
420 if (segment->format != demux->in_segment.format)
421 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422 gst_segment_copy_into (segment, &demux->in_segment);
424 /* in either case, clear some state and generate newsegment later on */
425 GST_OBJECT_LOCK (demux);
426 demux->segment_ts = GST_CLOCK_TIME_NONE;
427 demux->in_gap = GST_CLOCK_TIME_NONE;
428 demux->need_newsegment = TRUE;
429 demux->segment_seqnum = gst_event_get_seqnum (event);
430 gst_asf_demux_reset_stream_state_after_discont (demux);
431 /* if we seek back after reaching EOS, go back to packet reading state */
432 if (demux->data_offset > 0 && segment->start >= demux->data_offset
433 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
434 demux->state = GST_ASF_DEMUX_STATE_DATA;
436 GST_OBJECT_UNLOCK (demux);
438 gst_event_unref (event);
444 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
446 (_("This stream contains no data.")),
447 ("got eos and didn't receive a complete header object"));
450 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
451 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
452 GST_ELEMENT_FLOW_ERROR (demux, flow);
456 GST_OBJECT_LOCK (demux);
457 gst_adapter_clear (demux->adapter);
458 GST_OBJECT_UNLOCK (demux);
459 gst_asf_demux_send_event_unlocked (demux, event);
463 case GST_EVENT_FLUSH_STOP:
464 GST_OBJECT_LOCK (demux);
465 gst_asf_demux_reset_stream_state_after_discont (demux);
466 GST_OBJECT_UNLOCK (demux);
467 gst_asf_demux_send_event_unlocked (demux, event);
468 /* upon activation, latency is no longer introduced, e.g. after seek */
469 if (demux->activated_streams)
474 ret = gst_pad_event_default (pad, parent, event);
482 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
483 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
484 gboolean next, gboolean * eos)
486 GstClockTime idx_time;
492 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
495 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
498 /* if we want the next keyframe, we have to go forward till we find
499 a different packet number */
501 if (idx >= demux->sidx_num_entries - 1) {
502 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
507 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
508 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
515 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
521 *packet = demux->sidx_entries[idx].packet;
523 *speed = demux->sidx_entries[idx].count;
525 /* so we get closer to the actual time of the packet ... actually, let's not
526 * do this, since we throw away superfluous payloads before the seek position
527 * anyway; this way, our key unit seek 'snap resolution' is a bit better
528 * (ie. same as index resolution) */
530 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
534 idx_time = demux->sidx_interval * idx;
535 if (G_LIKELY (idx_time >= demux->preroll))
536 idx_time -= demux->preroll;
538 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
539 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
540 GST_TIME_ARGS (idx_time));
542 if (G_LIKELY (p_idx_time))
543 *p_idx_time = idx_time;
549 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
553 gst_adapter_clear (demux->adapter);
555 GST_DEBUG_OBJECT (demux, "reset stream state");
557 gst_flow_combiner_reset (demux->flowcombiner);
558 for (n = 0; n < demux->num_streams; n++) {
559 demux->stream[n].discont = TRUE;
560 demux->stream[n].first_buffer = TRUE;
562 while (demux->stream[n].payloads->len > 0) {
566 last = demux->stream[n].payloads->len - 1;
567 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
568 gst_buffer_replace (&payload->buf, NULL);
569 g_array_remove_index (demux->stream[n].payloads, last);
575 gst_asf_demux_mark_discont (GstASFDemux * demux)
579 GST_DEBUG_OBJECT (demux, "Mark stream discont");
581 for (n = 0; n < demux->num_streams; n++)
582 demux->stream[n].discont = TRUE;
585 /* do a seek in push based mode */
587 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
592 GstSeekType cur_type, stop_type;
596 GstEvent *byte_event;
598 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
601 stop_type = GST_SEEK_TYPE_NONE;
604 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
606 /* determine packet, by index or by estimation */
607 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
610 (guint) gst_util_uint64_scale (demux->num_packets, cur,
614 if (packet > demux->num_packets) {
615 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
620 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
622 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
624 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
625 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
626 /* BYTE seek event */
627 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
628 cur, stop_type, stop);
629 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
630 res = gst_pad_push_event (demux->sinkpad, byte_event);
636 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
638 GstClockTime idx_time;
641 GstSeekType cur_type, stop_type;
643 gboolean only_need_update;
644 gboolean after, before, next;
649 guint packet, speed_count = 1;
655 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
658 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
659 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
663 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
664 * so first try to let it handle the seek event. */
665 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
668 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
669 demux->num_packets == 0 || demux->play_time == 0)) {
670 GST_LOG_OBJECT (demux, "stream is not seekable");
674 if (G_UNLIKELY (!demux->activated_streams)) {
675 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
679 if (G_UNLIKELY (rate <= 0.0)) {
680 GST_LOG_OBJECT (demux, "backward playback");
681 demux->seek_to_cur_pos = TRUE;
682 for (i = 0; i < demux->num_streams; i++) {
683 demux->stream[i].reverse_kf_ready = FALSE;
687 seqnum = gst_event_get_seqnum (event);
688 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
690 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
691 demux->keyunit_sync =
692 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
693 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
694 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
695 next = after && !before;
697 if (G_UNLIKELY (demux->streaming)) {
698 /* support it safely needs more segment handling, e.g. closing etc */
700 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
703 /* we can (re)construct the start later on, but not the end */
704 if (stop_type != GST_SEEK_TYPE_NONE &&
705 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
706 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
709 return gst_asf_demux_handle_seek_push (demux, event);
712 /* unlock the streaming thread */
713 if (G_LIKELY (flush)) {
714 fevent = gst_event_new_flush_start ();
716 gst_event_set_seqnum (fevent, seqnum);
717 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
718 gst_asf_demux_send_event_unlocked (demux, fevent);
720 gst_pad_pause_task (demux->sinkpad);
723 /* grab the stream lock so that streaming cannot continue, for
724 * non flushing seeks when the element is in PAUSED this could block
726 GST_PAD_STREAM_LOCK (demux->sinkpad);
728 /* we now can stop flushing, since we have the stream lock now */
729 fevent = gst_event_new_flush_stop (TRUE);
730 gst_event_set_seqnum (fevent, seqnum);
731 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
733 if (G_LIKELY (flush))
734 gst_asf_demux_send_event_unlocked (demux, fevent);
736 gst_event_unref (fevent);
738 /* operating on copy of segment until we know the seek worked */
739 segment = demux->segment;
741 if (G_UNLIKELY (demux->segment_running && !flush)) {
742 GstSegment newsegment;
745 /* create the segment event to close the current segment */
746 gst_segment_copy_into (&segment, &newsegment);
747 newseg = gst_event_new_segment (&newsegment);
748 gst_event_set_seqnum (newseg, seqnum);
750 gst_asf_demux_send_event_unlocked (demux, newseg);
753 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
754 cur, stop_type, stop, &only_need_update);
756 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
757 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
759 if (cur_type != GST_SEEK_TYPE_SET)
760 seek_time = segment.start;
764 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
765 * real start of data and segment_start to indexed time for key unit seek*/
766 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
767 &idx_time, &speed_count, next, &eos))) {
771 demux->packet = demux->num_packets;
775 /* First try to query our source to see if it can convert for us. This is
776 the case when our source is an mms stream, notice that in this case
777 gstmms will do a time based seek to get the byte offset, this is not a
778 problem as the seek to this offset needs to happen anway. */
779 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
780 GST_FORMAT_BYTES, &offset)) {
781 packet = (offset - demux->data_offset) / demux->packet_size;
782 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
783 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
784 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
785 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
786 demux->packet_size, packet);
788 /* FIXME: For streams containing video, seek to an earlier position in
789 * the hope of hitting a keyframe and let the sinks throw away the stuff
790 * before the segment start. For audio-only this is unnecessary as every
792 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
793 && demux->num_video_streams > 0) {
794 seek_time -= 5 * GST_SECOND;
799 packet = (guint) gst_util_uint64_scale (demux->num_packets,
800 seek_time, demux->play_time);
802 if (packet > demux->num_packets)
803 packet = demux->num_packets;
806 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
807 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
808 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
809 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
810 segment.start = idx_time;
811 segment.position = idx_time;
812 segment.time = idx_time;
816 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
818 GST_OBJECT_LOCK (demux);
819 demux->segment = segment;
820 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
821 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
822 stop, demux->play_time);
824 demux->packet = packet;
827 demux->need_newsegment = TRUE;
828 demux->segment_seqnum = seqnum;
829 demux->speed_packets =
830 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
831 gst_asf_demux_reset_stream_state_after_discont (demux);
832 GST_OBJECT_UNLOCK (demux);
835 /* restart our task since it might have been stopped when we did the flush */
836 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
839 /* streaming can continue now */
840 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
846 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
852 demux = GST_ASF_DEMUX (parent);
854 switch (GST_EVENT_TYPE (event)) {
856 GST_LOG_OBJECT (pad, "seek event");
857 ret = gst_asf_demux_handle_seek_event (demux, event);
858 gst_event_unref (event);
861 case GST_EVENT_NAVIGATION:
862 /* just drop these two silently */
863 gst_event_unref (event);
867 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
868 ret = gst_pad_event_default (pad, parent, event);
875 static inline guint32
876 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
880 ret = gst_asf_identify_guid (guids, guid);
882 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
883 gst_asf_get_guid_nick (guids, ret),
884 guid->v1, guid->v2, guid->v3, guid->v4);
896 /* expect is true when the user is expeting an object,
897 * when false, it will give no warnings if the object
901 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
902 guint data_len, AsfObject * object, gboolean expect)
906 if (data_len < ASF_OBJECT_HEADER_SIZE)
909 guid.v1 = GST_READ_UINT32_LE (data + 0);
910 guid.v2 = GST_READ_UINT32_LE (data + 4);
911 guid.v3 = GST_READ_UINT32_LE (data + 8);
912 guid.v4 = GST_READ_UINT32_LE (data + 12);
914 object->size = GST_READ_UINT64_LE (data + 16);
916 /* FIXME: make asf_demux_identify_object_guid() */
917 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
918 if (object->id == ASF_OBJ_UNDEFINED && expect) {
919 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
920 guid.v1, guid.v2, guid.v3, guid.v4);
927 gst_asf_demux_release_old_pads (GstASFDemux * demux)
929 GST_DEBUG_OBJECT (demux, "Releasing old pads");
931 while (demux->old_num_streams > 0) {
932 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
933 gst_event_new_eos ());
934 gst_asf_demux_free_stream (demux,
935 &demux->old_stream[demux->old_num_streams - 1]);
936 --demux->old_num_streams;
938 memset (demux->old_stream, 0, sizeof (demux->old_stream));
939 demux->old_num_streams = 0;
943 gst_asf_demux_chain_headers (GstASFDemux * demux)
947 guint8 *header_data, *data = NULL;
948 const guint8 *cdata = NULL;
951 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
955 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
956 if (obj.id != ASF_OBJ_HEADER)
959 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
961 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
962 if (gst_adapter_available (demux->adapter) < obj.size + 50)
965 data = gst_adapter_take (demux->adapter, obj.size + 50);
968 header_size = obj.size;
969 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
970 if (flow != GST_FLOW_OK)
973 /* calculate where the packet data starts */
974 demux->data_offset = obj.size + 50;
976 /* now parse the beginning of the ASF_OBJ_DATA object */
977 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
980 if (demux->num_streams == 0)
989 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
996 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
997 ("This doesn't seem to be an ASF file"));
999 return GST_FLOW_ERROR;
1004 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1005 ("header parsing failed, or no streams found, flow = %s",
1006 gst_flow_get_name (flow)));
1008 return GST_FLOW_ERROR;
1013 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1014 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1019 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1022 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1024 if (G_LIKELY (p_flow))
1027 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1028 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1029 "+%u", gst_flow_get_name (flow), offset, size);
1034 g_assert (*p_buf != NULL);
1036 buffer_size = gst_buffer_get_size (*p_buf);
1037 if (G_UNLIKELY (buffer_size < size)) {
1038 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1039 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1040 gst_buffer_unref (*p_buf);
1041 if (G_LIKELY (p_flow))
1042 *p_flow = GST_FLOW_EOS;
1051 gst_asf_demux_pull_indices (GstASFDemux * demux)
1053 GstBuffer *buf = NULL;
1057 offset = demux->index_offset;
1059 if (G_UNLIKELY (offset == 0)) {
1060 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1064 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1070 gst_buffer_map (buf, &map, GST_MAP_READ);
1071 g_assert (map.size >= 16 + 8);
1072 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1073 gst_buffer_unmap (buf, &map);
1074 gst_buffer_replace (&buf, NULL);
1076 /* check for sanity */
1077 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1078 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1082 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1086 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1087 ", size %u", offset, (guint) obj.size);
1089 offset += obj.size; /* increase before _process_object changes it */
1091 gst_buffer_map (buf, &map, GST_MAP_READ);
1092 g_assert (map.size >= obj.size);
1093 bufdata = (guint8 *) map.data;
1094 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1095 gst_buffer_unmap (buf, &map);
1096 gst_buffer_replace (&buf, NULL);
1098 if (G_UNLIKELY (flow != GST_FLOW_OK))
1103 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1111 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1112 if (obj.id != ASF_OBJ_DATA) {
1113 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1117 demux->state = GST_ASF_DEMUX_STATE_DATA;
1119 if (!demux->broadcast && obj.size > 50) {
1120 demux->data_size = obj.size - 50;
1121 /* CHECKME: for at least one file this is off by +158 bytes?! */
1122 demux->index_offset = demux->data_offset + demux->data_size;
1124 demux->data_size = 0;
1125 demux->index_offset = 0;
1130 if (!demux->broadcast) {
1131 /* skip object header (24 bytes) and file GUID (16 bytes) */
1132 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1134 demux->num_packets = 0;
1137 if (demux->num_packets == 0)
1138 demux->seekable = FALSE;
1140 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1141 if (demux->data_size == 0 && demux->num_packets > 0) {
1142 demux->data_size = demux->num_packets * demux->packet_size;
1143 demux->index_offset = demux->data_offset + demux->data_size;
1146 /* process pending stream objects and create pads for those */
1147 gst_asf_demux_process_queued_extended_stream_objects (demux);
1149 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1150 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1151 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1152 demux->data_offset, demux->data_size, demux->index_offset);
1158 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1160 GstFlowReturn flow = GST_FLOW_OK;
1162 GstBuffer *buf = NULL;
1167 GST_LOG_OBJECT (demux, "reading headers");
1169 /* pull HEADER object header, so we know its size */
1170 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1173 gst_buffer_map (buf, &map, GST_MAP_READ);
1174 g_assert (map.size >= 16 + 8);
1175 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1176 gst_buffer_unmap (buf, &map);
1177 gst_buffer_replace (&buf, NULL);
1179 if (obj.id != ASF_OBJ_HEADER)
1182 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1184 /* pull HEADER object */
1185 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1189 size = obj.size; /* don't want obj.size changed */
1190 gst_buffer_map (buf, &map, GST_MAP_READ);
1191 g_assert (map.size >= size);
1192 bufdata = (guint8 *) map.data;
1193 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1194 gst_buffer_unmap (buf, &map);
1195 gst_buffer_replace (&buf, NULL);
1197 if (flow != GST_FLOW_OK) {
1198 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1202 /* calculate where the packet data starts */
1203 demux->data_offset = demux->base_offset + obj.size + 50;
1205 /* now pull beginning of DATA object before packet data */
1206 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1210 gst_buffer_map (buf, &map, GST_MAP_READ);
1211 g_assert (map.size >= size);
1212 bufdata = (guint8 *) map.data;
1213 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1216 if (demux->num_streams == 0)
1219 gst_buffer_unmap (buf, &map);
1220 gst_buffer_replace (&buf, NULL);
1228 gst_buffer_unmap (buf, &map);
1229 gst_buffer_replace (&buf, NULL);
1231 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1232 ("This doesn't seem to be an ASF file"));
1233 *pflow = GST_FLOW_ERROR;
1238 flow = GST_FLOW_ERROR;
1239 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1240 ("header parsing failed, or no streams found, flow = %s",
1241 gst_flow_get_name (flow)));
1246 gst_buffer_unmap (buf, &map);
1247 gst_buffer_replace (&buf, NULL);
1254 all_streams_prerolled (GstASFDemux * demux)
1256 GstClockTime preroll_time;
1257 guint i, num_no_data = 0;
1259 /* Allow at least 500ms of preroll_time */
1260 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1262 /* returns TRUE as long as there isn't a stream which (a) has data queued
1263 * and (b) the timestamp of last piece of data queued is < demux->preroll
1264 * AND there is at least one other stream with data queued */
1265 for (i = 0; i < demux->num_streams; ++i) {
1266 AsfPayload *last_payload = NULL;
1270 stream = &demux->stream[i];
1271 if (G_UNLIKELY (stream->payloads->len == 0)) {
1273 GST_LOG_OBJECT (stream->pad, "no data queued");
1277 /* find last payload with timestamp */
1278 for (last_idx = stream->payloads->len - 1;
1279 last_idx >= 0 && (last_payload == NULL
1280 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1281 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1284 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1285 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1286 GST_TIME_ARGS (preroll_time));
1287 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1288 || last_payload->ts <= preroll_time)) {
1289 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1294 if (G_UNLIKELY (num_no_data > 0))
1302 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1307 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1310 /* check for each mutual exclusion group whether it affects this stream */
1311 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1312 if (*mes == stream->id) {
1313 /* we are in this group; let's check if we've already activated streams
1314 * that are in the same group (and hence mutually exclusive to this
1316 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1319 for (i = 0; i < demux->num_streams; ++i) {
1320 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1321 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1322 "to already active stream with ID %d", stream->id,
1323 demux->stream[i].id);
1328 /* we can only be in this group once, let's break out and move on to
1329 * the next mutual exclusion group */
1340 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1342 /* remember the first queued timestamp for the segment */
1343 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1344 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1345 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1346 GST_TIME_ARGS (demux->first_ts));
1347 demux->segment_ts = payload_ts;
1348 /* always note, but only determines segment when streaming */
1349 if (demux->streaming)
1350 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1351 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1352 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1357 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1359 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1360 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1363 /* go trhough each stream, find smallest timestamp */
1364 for (i = 0; i < demux->num_streams; ++i) {
1367 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1368 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1369 stream = &demux->stream[i];
1371 for (j = 0; j < stream->payloads->len; ++j) {
1372 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1373 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1374 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1375 || stream_min_ts > payload->ts)) {
1376 stream_min_ts = payload->ts;
1378 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1379 payload->ts > stream_min_ts &&
1380 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1381 || stream_min_ts2 > payload->ts)) {
1382 stream_min_ts2 = payload->ts;
1386 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1387 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1388 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1389 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1390 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1392 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1395 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1396 stream_min_ts = stream_min_ts2;
1398 /* if we don't have timestamp for this stream, wait for more data */
1399 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1402 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1403 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1404 first_ts = stream_min_ts;
1407 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1410 demux->first_ts = first_ts;
1412 /* update packets queued before we knew first timestamp */
1413 for (i = 0; i < demux->num_streams; ++i) {
1416 stream = &demux->stream[i];
1418 for (j = 0; j < stream->payloads->len; ++j) {
1419 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1420 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1421 if (payload->ts > first_ts)
1422 payload->ts -= first_ts;
1430 gst_asf_demux_check_segment_ts (demux, 0);
1436 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1438 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1439 and often set wrong, inspecting the data is the only way that seem to be working */
1440 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1441 GstCaps *caps = NULL;
1443 GstAdapter *adapter = gst_adapter_new ();
1445 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1447 AsfPayload *payload;
1450 payload = &g_array_index (stream->payloads, AsfPayload, i);
1451 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1452 len = gst_adapter_available (adapter);
1453 data = gst_adapter_map (adapter, len);
1457 #define MIN_LENGTH 128
1459 /* look for the sync points */
1461 if (len < MIN_LENGTH || /* give typefind something to work on */
1462 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1463 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1469 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1472 if (prob < GST_TYPE_FIND_LIKELY) {
1475 if (len > MIN_LENGTH)
1476 /* this wasn't it, look for another sync point */
1480 gst_adapter_unmap (adapter);
1483 gst_object_unref (adapter);
1486 gst_caps_take (&stream->caps, caps);
1494 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1496 guint i, actual_streams = 0;
1498 if (demux->activated_streams)
1501 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1504 if (!all_streams_prerolled (demux) && !force) {
1505 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1509 for (i = 0; i < demux->num_streams; ++i) {
1510 AsfStream *stream = &demux->stream[i];
1512 if (stream->payloads->len > 0) {
1514 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1515 !stream->active && /* do not inspect active streams (caps were already set) */
1516 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1517 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1518 /* try to gather some more data */
1521 /* we don't check mutual exclusion stuff here; either we have data for
1522 * a stream, then we active it, or we don't, then we'll ignore it */
1523 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1524 gst_asf_demux_activate_stream (demux, stream);
1525 actual_streams += 1;
1527 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1531 if (actual_streams == 0) {
1532 /* We don't have any streams activated ! */
1533 GST_ERROR_OBJECT (demux, "No streams activated!");
1537 gst_asf_demux_release_old_pads (demux);
1539 demux->activated_streams = TRUE;
1540 GST_LOG_OBJECT (demux, "signalling no more pads");
1541 gst_element_no_more_pads (GST_ELEMENT (demux));
1545 /* returns the stream that has a complete payload with the lowest timestamp
1546 * queued, or NULL (we push things by timestamp because during the internal
1547 * prerolling we might accumulate more data then the external queues can take,
1548 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1550 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1552 AsfPayload *best_payload = NULL;
1553 AsfStream *best_stream = NULL;
1556 for (i = 0; i < demux->num_streams; ++i) {
1560 stream = &demux->stream[i];
1562 /* Don't push any data until we have at least one payload that falls within
1563 * the current segment. This way we can remove out-of-segment payloads that
1564 * don't need to be decoded after a seek, sending only data from the
1565 * keyframe directly before our segment start */
1566 if (stream->payloads->len > 0) {
1567 AsfPayload *payload = NULL;
1570 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1571 /* Reverse playback */
1573 if (stream->is_video) {
1574 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1575 if (stream->reverse_kf_ready) {
1577 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1578 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1579 /* TODO : remove payload from the list? */
1586 /* find first complete payload with timestamp */
1587 for (j = stream->payloads->len - 1;
1588 j >= 0 && (payload == NULL
1589 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1590 payload = &g_array_index (stream->payloads, AsfPayload, j);
1593 /* If there's a complete payload queued for this stream */
1594 if (!gst_asf_payload_is_complete (payload))
1600 /* find last payload with timestamp */
1601 for (last_idx = stream->payloads->len - 1;
1602 last_idx >= 0 && (payload == NULL
1603 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1604 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1607 /* if this is first payload after seek we might need to update the segment */
1608 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1609 gst_asf_demux_check_segment_ts (demux, payload->ts);
1611 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1612 (payload->ts < demux->segment.start))) {
1613 if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1614 && payload->keyframe)) {
1615 GST_DEBUG_OBJECT (stream->pad,
1616 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1617 GST_TIME_ARGS (payload->ts));
1618 demux->segment.start = payload->ts;
1619 demux->segment.time = payload->ts;
1621 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1622 GST_TIME_FORMAT " which is before our segment start %"
1623 GST_TIME_FORMAT ", not pushing yet",
1624 GST_TIME_ARGS (payload->ts),
1625 GST_TIME_ARGS (demux->segment.start));
1630 /* find first complete payload with timestamp */
1632 j < stream->payloads->len && (payload == NULL
1633 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1634 payload = &g_array_index (stream->payloads, AsfPayload, j);
1637 /* Now see if there's a complete payload queued for this stream */
1638 if (!gst_asf_payload_is_complete (payload))
1642 /* ... and whether its timestamp is lower than the current best */
1643 if (best_stream == NULL || best_payload->ts > payload->ts) {
1644 best_stream = stream;
1645 best_payload = payload;
1653 static GstFlowReturn
1654 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1657 GstFlowReturn ret = GST_FLOW_OK;
1659 if (G_UNLIKELY (!demux->activated_streams)) {
1660 if (!gst_asf_demux_check_activate_streams (demux, force))
1662 /* streams are now activated */
1665 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1666 AsfPayload *payload;
1667 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1668 GstClockTime duration = GST_CLOCK_TIME_NONE;
1670 /* wait until we had a chance to "lock on" some payload's timestamp */
1671 if (G_UNLIKELY (demux->need_newsegment
1672 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1675 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1676 && stream->payloads->len) {
1677 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1679 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1682 /* do we need to send a newsegment event */
1683 if ((G_UNLIKELY (demux->need_newsegment))) {
1684 GstEvent *segment_event;
1686 /* safe default if insufficient upstream info */
1687 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1690 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1691 demux->segment.duration > 0) {
1692 /* slight HACK; prevent clipping of last bit */
1693 demux->segment.stop = demux->segment.duration + demux->in_gap;
1696 /* FIXME : only if ACCURATE ! */
1697 if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1698 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1699 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1700 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1701 GST_TIME_ARGS (payload->ts));
1702 demux->segment.start = payload->ts;
1703 demux->segment.time = payload->ts;
1706 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1709 /* note: we fix up all timestamps to start from 0, so this should be ok */
1710 segment_event = gst_event_new_segment (&demux->segment);
1711 if (demux->segment_seqnum)
1712 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1713 gst_asf_demux_send_event_unlocked (demux, segment_event);
1715 /* now post any global tags we may have found */
1716 if (demux->taglist == NULL) {
1717 demux->taglist = gst_tag_list_new_empty ();
1718 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1721 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1722 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1724 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1725 gst_asf_demux_send_event_unlocked (demux,
1726 gst_event_new_tag (demux->taglist));
1727 demux->taglist = NULL;
1729 demux->need_newsegment = FALSE;
1730 demux->segment_seqnum = 0;
1731 demux->segment_running = TRUE;
1734 /* Do we have tags pending for this stream? */
1735 if (G_UNLIKELY (stream->pending_tags)) {
1736 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1737 gst_pad_push_event (stream->pad,
1738 gst_event_new_tag (stream->pending_tags));
1739 stream->pending_tags = NULL;
1742 /* We have the whole packet now so we should push the packet to
1743 * the src pad now. First though we should check if we need to do
1745 if (G_UNLIKELY (stream->span > 1)) {
1746 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1749 payload->buf = gst_buffer_make_writable (payload->buf);
1751 if (G_LIKELY (!payload->keyframe)) {
1752 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1755 if (G_UNLIKELY (stream->discont)) {
1756 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1757 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1758 stream->discont = FALSE;
1761 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1762 (payload->par_x != stream->par_x) &&
1763 (payload->par_y != stream->par_y))) {
1764 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1765 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1766 stream->par_x = payload->par_x;
1767 stream->par_y = payload->par_y;
1768 stream->caps = gst_caps_make_writable (stream->caps);
1769 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1770 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1771 gst_pad_set_caps (stream->pad, stream->caps);
1774 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1775 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1776 payload->interlaced);
1777 stream->interlaced = payload->interlaced;
1778 stream->caps = gst_caps_make_writable (stream->caps);
1779 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1780 (stream->interlaced ? "mixed" : "progressive"), NULL);
1781 gst_pad_set_caps (stream->pad, stream->caps);
1784 /* (sort of) interpolate timestamps using upstream "frame of reference",
1785 * typically useful for live src, but might (unavoidably) mess with
1786 * position reporting if a live src is playing not so live content
1787 * (e.g. rtspsrc taking some time to fall back to tcp) */
1788 timestamp = payload->ts;
1789 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1790 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1791 timestamp += demux->in_gap;
1793 /* Check if we're after the segment already, if so no need to push
1795 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1796 GST_DEBUG_OBJECT (stream->pad,
1797 "Payload after segment stop %" GST_TIME_FORMAT,
1798 GST_TIME_ARGS (demux->segment.stop));
1800 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1802 gst_buffer_unref (payload->buf);
1803 payload->buf = NULL;
1804 g_array_remove_index (stream->payloads, 0);
1805 /* Break out as soon as we have an issue */
1806 if (G_UNLIKELY (ret != GST_FLOW_OK))
1813 GST_BUFFER_PTS (payload->buf) = timestamp;
1815 if (payload->duration == GST_CLOCK_TIME_NONE
1816 && stream->ext_props.avg_time_per_frame != 0) {
1817 duration = stream->ext_props.avg_time_per_frame * 100;
1819 duration = payload->duration;
1821 GST_BUFFER_DURATION (payload->buf) = duration;
1823 /* FIXME: we should really set durations on buffers if we can */
1825 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1828 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1829 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1830 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1832 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1833 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1837 if (stream->active) {
1838 if (G_UNLIKELY (stream->first_buffer)) {
1839 if (stream->streamheader != NULL) {
1840 GST_DEBUG_OBJECT (stream->pad,
1841 "Pushing streamheader before first buffer");
1842 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1844 stream->first_buffer = FALSE;
1847 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1848 && timestamp > demux->segment.position) {
1849 demux->segment.position = timestamp;
1850 if (GST_CLOCK_TIME_IS_VALID (duration))
1851 demux->segment.position += timestamp;
1854 ret = gst_pad_push (stream->pad, payload->buf);
1856 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1859 gst_buffer_unref (payload->buf);
1862 payload->buf = NULL;
1863 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1864 && stream->reverse_kf_ready) {
1865 g_array_remove_index (stream->payloads, stream->kf_pos);
1868 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1870 stream->reverse_kf_ready = FALSE;
1873 g_array_remove_index (stream->payloads, 0);
1876 /* Break out as soon as we have an issue */
1877 if (G_UNLIKELY (ret != GST_FLOW_OK))
1885 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1889 g_assert (buf != NULL);
1891 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1893 gst_buffer_map (buf, &map, GST_MAP_READ);
1895 /* we return false on buffer too small */
1896 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1897 gst_buffer_unmap (buf, &map);
1901 /* check if it is a header */
1902 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1903 gst_buffer_unmap (buf, &map);
1904 if (obj.id == ASF_OBJ_HEADER) {
1911 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1913 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1914 GstFlowReturn ret = GST_FLOW_OK;
1915 GstBuffer *buf = NULL;
1916 gboolean header = FALSE;
1918 /* TODO maybe we should skip index objects after the data and look
1919 * further for a new header */
1920 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1921 g_assert (buf != NULL);
1922 /* check if it is a header */
1923 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1924 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1925 demux->base_offset = off;
1929 gst_buffer_unref (buf);
1936 gst_asf_demux_loop (GstASFDemux * demux)
1938 GstFlowReturn flow = GST_FLOW_OK;
1939 GstBuffer *buf = NULL;
1942 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1943 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1947 gst_asf_demux_pull_indices (demux);
1950 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1952 if (G_UNLIKELY (demux->num_packets != 0
1953 && demux->packet >= demux->num_packets))
1956 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1957 (guint) demux->num_packets);
1959 off = demux->data_offset + (demux->packet * demux->packet_size);
1961 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1962 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1963 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1964 if (flow == GST_FLOW_EOS) {
1966 } else if (flow == GST_FLOW_FLUSHING) {
1967 GST_DEBUG_OBJECT (demux, "Not fatal");
1974 if (G_LIKELY (demux->speed_packets == 1)) {
1975 GstAsfDemuxParsePacketError err;
1976 err = gst_asf_demux_parse_packet (demux, buf);
1977 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1978 /* when we don't know when the data object ends, we should check
1979 * for a chained asf */
1980 if (demux->num_packets == 0) {
1981 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1982 GST_INFO_OBJECT (demux, "Chained asf found");
1983 demux->base_offset = off;
1984 gst_asf_demux_reset (demux, TRUE);
1985 gst_buffer_unref (buf);
1989 /* FIXME: We should tally up fatal errors and error out only
1990 * after a few broken packets in a row? */
1992 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1993 gst_buffer_unref (buf);
1995 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
1996 && !demux->seek_to_cur_pos) {
1998 if (demux->packet < 0) {
2008 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2010 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2011 && !demux->seek_to_cur_pos) {
2013 if (demux->packet < 0) {
2022 for (n = 0; n < demux->speed_packets; n++) {
2024 GstAsfDemuxParsePacketError err;
2027 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2028 n * demux->packet_size, demux->packet_size);
2029 err = gst_asf_demux_parse_packet (demux, sub);
2030 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2031 /* when we don't know when the data object ends, we should check
2032 * for a chained asf */
2033 if (demux->num_packets == 0) {
2034 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2035 GST_INFO_OBJECT (demux, "Chained asf found");
2036 demux->base_offset = off + n * demux->packet_size;
2037 gst_asf_demux_reset (demux, TRUE);
2038 gst_buffer_unref (sub);
2039 gst_buffer_unref (buf);
2043 /* FIXME: We should tally up fatal errors and error out only
2044 * after a few broken packets in a row? */
2046 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2050 gst_buffer_unref (sub);
2052 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2053 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2059 /* reset speed pull */
2060 demux->speed_packets = 1;
2063 gst_buffer_unref (buf);
2065 if (G_UNLIKELY ((demux->num_packets > 0
2066 && demux->packet >= demux->num_packets)
2067 || flow == GST_FLOW_EOS)) {
2068 GST_LOG_OBJECT (demux, "reached EOS");
2072 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2073 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2077 /* check if we're at the end of the configured segment */
2078 /* FIXME: check if segment end reached etc. */
2084 /* if we haven't activated our streams yet, this might be because we have
2085 * less data queued than required for preroll; force stream activation and
2086 * send any pending payloads before sending EOS */
2087 if (!demux->activated_streams)
2088 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2090 /* we want to push an eos or post a segment-done in any case */
2091 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2094 /* for segment playback we need to post when (in stream time)
2095 * we stopped, this is either stop (when set) or the duration. */
2096 if ((stop = demux->segment.stop) == -1)
2097 stop = demux->segment.duration;
2099 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2100 gst_element_post_message (GST_ELEMENT_CAST (demux),
2101 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2103 gst_asf_demux_send_event_unlocked (demux,
2104 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2105 } else if (flow != GST_FLOW_EOS) {
2106 /* check if we have a chained asf, in case, we don't eos yet */
2107 if (gst_asf_demux_check_chained_asf (demux)) {
2108 GST_INFO_OBJECT (demux, "Chained ASF starting");
2109 gst_asf_demux_reset (demux, TRUE);
2114 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2115 if (demux->activated_streams) {
2116 /* normal playback, send EOS to all linked pads */
2117 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2118 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2120 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2121 flow = GST_FLOW_EOS;
2124 /* ... and fall through to pause */
2128 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2129 gst_flow_get_name (flow));
2130 demux->segment_running = FALSE;
2131 gst_pad_pause_task (demux->sinkpad);
2133 /* For the error cases */
2134 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2135 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2136 ("This doesn't seem to be an ASF file"));
2137 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2138 /* Post an error. Hopefully something else already has, but if not... */
2139 GST_ELEMENT_FLOW_ERROR (demux, flow);
2140 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2149 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2150 flow = GST_FLOW_EOS;
2154 /* See FIXMEs above */
2157 gst_buffer_unref (buf);
2158 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2159 ("Error parsing ASF packet %u", (guint) demux->packet));
2160 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2161 flow = GST_FLOW_ERROR;
2167 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2168 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2169 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2172 gst_asf_demux_check_header (GstASFDemux * demux)
2175 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2176 ASF_OBJECT_HEADER_SIZE);
2177 if (cdata == NULL) /* need more data */
2178 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2180 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2181 if (obj.id != ASF_OBJ_HEADER) {
2182 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2184 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2188 static GstFlowReturn
2189 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2191 GstFlowReturn ret = GST_FLOW_OK;
2194 demux = GST_ASF_DEMUX (parent);
2196 GST_LOG_OBJECT (demux,
2197 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2198 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2199 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2201 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2202 GST_DEBUG_OBJECT (demux, "received DISCONT");
2203 gst_asf_demux_mark_discont (demux);
2206 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2207 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2208 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2209 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2210 ", interpolation gap: %" GST_TIME_FORMAT,
2211 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2214 gst_adapter_push (demux->adapter, buf);
2216 switch (demux->state) {
2217 case GST_ASF_DEMUX_STATE_INDEX:{
2218 gint result = gst_asf_demux_check_header (demux);
2219 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2222 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2223 /* we don't care about this, probably an index */
2224 /* TODO maybe would be smarter to skip all the indices
2225 * until we got a new header or EOS to decide */
2226 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2229 GST_INFO_OBJECT (demux, "Chained asf starting");
2230 /* cleanup and get ready for a chained asf */
2231 gst_asf_demux_reset (demux, TRUE);
2235 case GST_ASF_DEMUX_STATE_HEADER:{
2236 ret = gst_asf_demux_chain_headers (demux);
2237 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2239 /* otherwise fall through */
2241 case GST_ASF_DEMUX_STATE_DATA:
2245 data_size = demux->packet_size;
2247 while (gst_adapter_available (demux->adapter) >= data_size) {
2249 GstAsfDemuxParsePacketError err;
2251 /* we don't know the length of the stream
2252 * check for a chained asf everytime */
2253 if (demux->num_packets == 0) {
2254 gint result = gst_asf_demux_check_header (demux);
2256 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2257 GST_INFO_OBJECT (demux, "Chained asf starting");
2258 /* cleanup and get ready for a chained asf */
2259 gst_asf_demux_reset (demux, TRUE);
2262 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2263 && demux->packet >= demux->num_packets)) {
2264 /* do not overshoot data section when streaming */
2268 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2270 /* FIXME: We should tally up fatal errors and error out only
2271 * after a few broken packets in a row? */
2272 err = gst_asf_demux_parse_packet (demux, buf);
2274 gst_buffer_unref (buf);
2276 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2277 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2279 GST_WARNING_OBJECT (demux, "Parse error");
2281 if (demux->packet >= 0)
2284 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2285 && demux->packet >= demux->num_packets)) {
2286 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2291 g_assert_not_reached ();
2295 if (ret != GST_FLOW_OK)
2296 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2302 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2308 static inline gboolean
2309 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2311 if (*p_size < num_bytes)
2314 *p_data += num_bytes;
2315 *p_size -= num_bytes;
2319 static inline guint8
2320 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2324 g_assert (*p_size >= 1);
2325 ret = GST_READ_UINT8 (*p_data);
2326 *p_data += sizeof (guint8);
2327 *p_size -= sizeof (guint8);
2331 static inline guint16
2332 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2336 g_assert (*p_size >= 2);
2337 ret = GST_READ_UINT16_LE (*p_data);
2338 *p_data += sizeof (guint16);
2339 *p_size -= sizeof (guint16);
2343 static inline guint32
2344 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2348 g_assert (*p_size >= 4);
2349 ret = GST_READ_UINT32_LE (*p_data);
2350 *p_data += sizeof (guint32);
2351 *p_size -= sizeof (guint32);
2355 static inline guint64
2356 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2360 g_assert (*p_size >= 8);
2361 ret = GST_READ_UINT64_LE (*p_data);
2362 *p_data += sizeof (guint64);
2363 *p_size -= sizeof (guint64);
2368 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2369 guint8 ** p_data, guint64 * p_size)
2373 if (*p_size < num_bytes_to_read)
2376 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2377 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2379 *p_data += num_bytes_to_read;
2380 *p_size -= num_bytes_to_read;
2386 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2387 guint8 ** p_data, guint64 * p_size)
2391 if (*p_size < num_bytes_to_read)
2394 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2395 *p_data += num_bytes_to_read;
2396 *p_size -= num_bytes_to_read;
2401 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2402 guint8 ** p_data, guint64 * p_size)
2412 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2415 *p_strlen = s_length;
2417 if (s_length == 0) {
2418 GST_WARNING ("zero-length string");
2419 *p_str = g_strdup ("");
2423 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2426 g_assert (s != NULL);
2428 /* just because They don't exist doesn't
2429 * mean They are not out to get you ... */
2430 if (s[s_length - 1] != '\0') {
2431 s = g_realloc (s, s_length + 1);
2435 *p_str = (gchar *) s;
2441 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2443 g_assert (*p_size >= 4 * sizeof (guint32));
2445 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2446 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2447 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2448 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2452 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2455 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2458 /* WAVEFORMATEX Structure */
2459 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2460 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2461 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2462 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2463 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2464 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2465 /* Codec specific data size */
2466 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2471 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2474 if (*p_size < (4 + 4 + 1 + 2))
2477 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2478 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2479 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2480 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2485 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2486 guint8 ** p_data, guint64 * p_size)
2488 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2491 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2492 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2493 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2494 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2495 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2496 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2497 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2498 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2499 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2500 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2501 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2506 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2510 for (i = 0; i < demux->num_streams; i++) {
2511 if (demux->stream[i].id == id)
2512 return &demux->stream[i];
2515 if (gst_asf_demux_is_unknown_stream (demux, id))
2516 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2521 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2522 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2527 gst_pad_use_fixed_caps (src_pad);
2528 gst_pad_set_caps (src_pad, caps);
2530 gst_pad_set_event_function (src_pad,
2531 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2532 gst_pad_set_query_function (src_pad,
2533 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2535 stream = &demux->stream[demux->num_streams];
2536 stream->caps = caps;
2537 stream->pad = src_pad;
2539 stream->fps_known = !is_video; /* bit hacky for audio */
2540 stream->is_video = is_video;
2541 stream->pending_tags = tags;
2542 stream->discont = TRUE;
2543 stream->first_buffer = TRUE;
2544 stream->streamheader = streamheader;
2545 if (stream->streamheader) {
2546 stream->streamheader = gst_buffer_make_writable (streamheader);
2547 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2552 st = gst_caps_get_structure (caps, 0);
2553 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2554 par_x > 0 && par_y > 0) {
2555 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2556 stream->par_x = par_x;
2557 stream->par_y = par_y;
2561 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2563 /* TODO: create this array during reverse play? */
2564 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2566 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2567 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2569 ++demux->num_streams;
2571 stream->active = FALSE;
2577 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2578 GstBuffer * buffer, GstStructure * structure)
2580 GValue arr_val = G_VALUE_INIT;
2581 GValue buf_val = G_VALUE_INIT;
2583 g_value_init (&arr_val, GST_TYPE_ARRAY);
2584 g_value_init (&buf_val, GST_TYPE_BUFFER);
2586 gst_value_set_buffer (&buf_val, buffer);
2587 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2589 gst_structure_take_value (structure, "streamheader", &arr_val);
2593 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2594 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2596 GstTagList *tags = NULL;
2597 GstBuffer *extradata = NULL;
2600 guint16 size_left = 0;
2601 gchar *codec_name = NULL;
2604 size_left = audio->size;
2606 /* Create the audio pad */
2607 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2609 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2612 /* Swallow up any left over data and set up the
2613 * standard properties from the header info */
2615 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2616 "codec specific data", size_left);
2618 g_assert (size_left <= *p_size);
2619 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2622 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2623 * additional two bytes indicating extradata. */
2624 /* FIXME: Handle the channel reorder map here */
2625 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2626 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2629 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2630 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2633 /* Informing about that audio format we just added */
2635 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2636 g_free (codec_name);
2639 if (audio->byte_rate > 0) {
2640 /* Some ASF files have no bitrate props object (often seen with
2641 * ASF files that contain raw audio data). Example files can
2642 * be generated with FFmpeg (tested with v2.8.6), like this:
2644 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2646 * In this case, if audio->byte_rate is nonzero, use that as
2649 guint bitrate = audio->byte_rate * 8;
2652 tags = gst_tag_list_new_empty ();
2654 /* Add bitrate, but only if there is none set already, since
2655 * this is just a fallback in case there is no bitrate tag
2656 * already present */
2657 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2661 gst_buffer_unref (extradata);
2663 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2664 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2665 audio->codec_tag, tags);
2667 ++demux->num_audio_streams;
2669 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2673 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2674 asf_stream_video_format * video, guint16 id,
2675 guint8 ** p_data, guint64 * p_size)
2677 GstTagList *tags = NULL;
2678 GstStructure *caps_s;
2679 GstBuffer *extradata = NULL;
2684 gchar *codec_name = NULL;
2685 gint size_left = video->size - 40;
2686 GstBuffer *streamheader = NULL;
2687 guint par_w = 1, par_h = 1;
2689 /* Create the video pad */
2690 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2691 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2694 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2696 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2697 g_assert (size_left <= *p_size);
2698 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2701 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2703 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2704 caps = gst_riff_create_video_caps (video->tag, NULL,
2705 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2708 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2709 G_TYPE_UINT, video->tag, NULL);
2714 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2715 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2716 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2719 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2723 /* retry with the global metadata */
2724 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2725 demux->global_metadata);
2726 s = demux->global_metadata;
2727 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2728 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2729 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2730 if (ax > 0 && ay > 0) {
2733 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2738 s = gst_caps_get_structure (caps, 0);
2739 gst_structure_remove_field (s, "framerate");
2742 caps_s = gst_caps_get_structure (caps, 0);
2744 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2745 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2746 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2747 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2750 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2751 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2752 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2754 GstBuffer *buf = gst_value_get_buffer (value);
2757 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2758 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2759 /* this looks like a bytestream start */
2760 streamheader = gst_buffer_ref (buf);
2761 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2762 gst_structure_remove_field (caps_s, "codec_data");
2765 gst_buffer_unmap (buf, &mapinfo);
2770 /* For a 3D video, set multiview information into the caps based on
2771 * what was detected during object parsing */
2772 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2773 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2774 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2775 const gchar *mview_mode_str;
2777 switch (demux->asf_3D_mode) {
2778 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2779 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2781 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2782 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2783 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2785 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2786 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2788 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2789 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2790 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2792 case GST_ASF_3D_DUAL_STREAM:{
2793 gboolean is_right_view = FALSE;
2794 /* if Advanced_Mutual_Exclusion object exists, use it
2795 * to figure out which is the left view (lower ID) */
2796 if (demux->mut_ex_streams != NULL) {
2800 length = g_slist_length (demux->mut_ex_streams);
2802 for (i = 0; i < length; i++) {
2805 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2807 GST_DEBUG_OBJECT (demux,
2808 "has Mutual_Exclusion object. stream id in object is %d",
2809 GPOINTER_TO_INT (v_s_id));
2811 if (id > GPOINTER_TO_INT (v_s_id))
2812 is_right_view = TRUE;
2815 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2816 * first video stream encountered has the lower ID */
2817 if (demux->num_video_streams > 0) {
2818 /* This is not the first video stream, assuming right eye view */
2819 is_right_view = TRUE;
2823 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2825 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2832 GST_INFO_OBJECT (demux,
2833 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2836 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2837 if (mview_mode_str != NULL) {
2838 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2839 video->height, par_w, par_h))
2840 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2842 gst_caps_set_simple (caps,
2843 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2844 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2845 GST_FLAG_SET_MASK_EXACT, NULL);
2850 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2851 g_free (codec_name);
2855 gst_buffer_unref (extradata);
2857 GST_INFO ("Adding video stream #%u, id %u, codec %"
2858 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2859 GST_FOURCC_ARGS (video->tag), video->tag);
2861 ++demux->num_video_streams;
2863 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2864 streamheader, tags);
2868 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2870 if (!stream->active) {
2874 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2875 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2876 gst_pad_set_active (stream->pad, TRUE);
2879 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2880 "%03u", stream->id);
2883 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2885 if (gst_event_parse_group_id (event, &demux->group_id))
2886 demux->have_group_id = TRUE;
2888 demux->have_group_id = FALSE;
2889 gst_event_unref (event);
2890 } else if (!demux->have_group_id) {
2891 demux->have_group_id = TRUE;
2892 demux->group_id = gst_util_group_id_next ();
2895 event = gst_event_new_stream_start (stream_id);
2896 if (demux->have_group_id)
2897 gst_event_set_group_id (event, demux->group_id);
2899 gst_pad_push_event (stream->pad, event);
2901 gst_pad_set_caps (stream->pad, stream->caps);
2903 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2904 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2905 stream->active = TRUE;
2910 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2913 AsfCorrectionType correction_type;
2914 AsfStreamType stream_type;
2915 GstClockTime time_offset;
2916 gboolean is_encrypted G_GNUC_UNUSED;
2920 guint stream_specific_size;
2921 guint type_specific_size G_GNUC_UNUSED;
2922 guint unknown G_GNUC_UNUSED;
2923 gboolean inspect_payload = FALSE;
2924 AsfStream *stream = NULL;
2926 /* Get the rest of the header's header */
2927 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2928 goto not_enough_data;
2930 gst_asf_demux_get_guid (&guid, &data, &size);
2931 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2933 gst_asf_demux_get_guid (&guid, &data, &size);
2934 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2936 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2938 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2939 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2941 flags = gst_asf_demux_get_uint16 (&data, &size);
2942 stream_id = flags & 0x7f;
2943 is_encrypted = ! !((flags & 0x8000) << 15);
2944 unknown = gst_asf_demux_get_uint32 (&data, &size);
2946 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2947 stream_id, GST_TIME_ARGS (time_offset));
2949 /* dvr-ms has audio stream declared in stream specific data */
2950 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2951 AsfExtStreamType ext_stream_type;
2952 gst_asf_demux_get_guid (&guid, &data, &size);
2953 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2955 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2956 inspect_payload = TRUE;
2958 gst_asf_demux_get_guid (&guid, &data, &size);
2959 gst_asf_demux_get_uint32 (&data, &size);
2960 gst_asf_demux_get_uint32 (&data, &size);
2961 gst_asf_demux_get_uint32 (&data, &size);
2962 gst_asf_demux_get_guid (&guid, &data, &size);
2963 gst_asf_demux_get_uint32 (&data, &size);
2964 stream_type = ASF_STREAM_AUDIO;
2968 switch (stream_type) {
2969 case ASF_STREAM_AUDIO:{
2970 asf_stream_audio audio_object;
2972 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2973 goto not_enough_data;
2975 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2978 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2981 switch (correction_type) {
2982 case ASF_CORRECTION_ON:{
2983 guint span, packet_size, chunk_size, data_size, silence_data;
2985 GST_INFO ("Using error correction");
2987 if (size < (1 + 2 + 2 + 2 + 1))
2988 goto not_enough_data;
2990 span = gst_asf_demux_get_uint8 (&data, &size);
2991 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2992 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2993 data_size = gst_asf_demux_get_uint16 (&data, &size);
2994 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2996 stream->span = span;
2998 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2999 packet_size, chunk_size, data_size, span, silence_data);
3001 if (stream->span > 1) {
3002 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3003 /* Disable descrambling */
3006 /* FIXME: this else branch was added for
3007 * weird_al_yankovic - the saga begins.asf */
3008 stream->ds_packet_size = packet_size;
3009 stream->ds_chunk_size = chunk_size;
3012 /* Descambling is enabled */
3013 stream->ds_packet_size = packet_size;
3014 stream->ds_chunk_size = chunk_size;
3017 /* Now skip the rest of the silence data */
3019 gst_bytestream_flush (demux->bs, data_size - 1);
3021 /* FIXME: CHECKME. And why -1? */
3022 if (data_size > 1) {
3023 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3024 goto not_enough_data;
3030 case ASF_CORRECTION_OFF:{
3031 GST_INFO ("Error correction off");
3032 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3033 goto not_enough_data;
3037 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3038 ("Audio stream using unknown error correction"));
3045 case ASF_STREAM_VIDEO:{
3046 asf_stream_video_format video_format_object;
3047 asf_stream_video video_object;
3050 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3051 goto not_enough_data;
3053 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3055 GST_INFO ("object is a video stream with %u bytes of "
3056 "additional data", vsize);
3058 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3060 goto not_enough_data;
3063 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3064 stream_id, &data, &size);
3070 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3072 demux->other_streams =
3073 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3078 stream->inspect_payload = inspect_payload;
3083 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3084 /* we'll error out later if we found no streams */
3089 static const gchar *
3090 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3094 const gchar *asf_name;
3095 const gchar *gst_name;
3098 "WM/Genre", GST_TAG_GENRE}, {
3099 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3100 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3101 "WM/Picture", GST_TAG_IMAGE}, {
3102 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3103 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3104 "WM/Year", GST_TAG_DATE_TIME}
3105 /* { "WM/Composer", GST_TAG_COMPOSER } */
3110 if (name_utf8 == NULL) {
3111 GST_WARNING ("Failed to convert name to UTF8, skipping");
3115 out = strlen (name_utf8);
3117 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3118 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3119 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3120 return tags[i].gst_name;
3127 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3129 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3133 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3135 if (taglist == NULL)
3138 if (gst_tag_list_is_empty (taglist)) {
3139 gst_tag_list_unref (taglist);
3143 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3144 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3146 gst_tag_list_unref (demux->taglist);
3147 gst_tag_list_unref (taglist);
3149 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3152 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3153 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3154 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3155 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3158 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3162 const guint8 *img_data = NULL;
3163 guint32 img_data_len = 0;
3164 guint8 pic_type = 0;
3166 gst_byte_reader_init (&r, tag_data, tag_data_len);
3168 /* skip mime type string (we don't trust it and do our own typefinding),
3169 * and also skip the description string, since we don't use it */
3170 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3171 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3172 !gst_byte_reader_skip_string_utf16 (&r) ||
3173 !gst_byte_reader_skip_string_utf16 (&r) ||
3174 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3175 goto not_enough_data;
3179 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3180 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3186 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3187 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3192 /* Extended Content Description Object */
3193 static GstFlowReturn
3194 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3197 /* Other known (and unused) 'text/unicode' metadata available :
3200 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3201 * WMFSDKVersion = 9.00.00.2980
3202 * WMFSDKNeeded = 0.0.0.0000
3203 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3204 * WM/Publisher = 4AD
3206 * WM/ProviderRating = 8
3207 * WM/ProviderStyle = Rock (similar to WM/Genre)
3208 * WM/GenreID (similar to WM/Genre)
3209 * WM/TrackNumber (same as WM/Track but as a string)
3211 * Other known (and unused) 'non-text' metadata available :
3217 * We might want to read WM/TrackNumber and use atoi() if we don't have
3221 GstTagList *taglist;
3222 guint16 blockcount, i;
3223 gboolean content3D = FALSE;
3227 const gchar *interleave_name;
3228 GstASF3DMode interleaving_type;
3229 } stereoscopic_layout_map[] = {
3231 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3232 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3233 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3234 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3235 "DualStream", GST_ASF_3D_DUAL_STREAM}
3237 GST_INFO_OBJECT (demux, "object is an extended content description");
3239 taglist = gst_tag_list_new_empty ();
3241 /* Content Descriptor Count */
3243 goto not_enough_data;
3245 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3247 for (i = 1; i <= blockcount; ++i) {
3248 const gchar *gst_tag_name;
3252 GValue tag_value = { 0, };
3255 gchar *name_utf8 = NULL;
3259 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3260 goto not_enough_data;
3264 goto not_enough_data;
3266 /* Descriptor Value Data Type */
3267 datatype = gst_asf_demux_get_uint16 (&data, &size);
3269 /* Descriptor Value (not really a string, but same thing reading-wise) */
3270 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3272 goto not_enough_data;
3276 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3278 if (name_utf8 != NULL) {
3279 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3281 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3282 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3285 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3288 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3291 /* get rid of tags with empty value */
3292 if (value_utf8 != NULL && *value_utf8 != '\0') {
3293 GST_DEBUG ("string value %s", value_utf8);
3295 value_utf8[out] = '\0';
3297 if (gst_tag_name != NULL) {
3298 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3299 guint year = atoi (value_utf8);
3302 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3303 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3305 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3306 guint id3v1_genre_id;
3307 const gchar *genre_str;
3309 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3310 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3311 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3312 g_free (value_utf8);
3313 value_utf8 = g_strdup (genre_str);
3318 /* convert tag from string to other type if required */
3319 tag_type = gst_tag_get_type (gst_tag_name);
3320 g_value_init (&tag_value, tag_type);
3321 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3322 GValue from_val = { 0, };
3324 g_value_init (&from_val, G_TYPE_STRING);
3325 g_value_set_string (&from_val, value_utf8);
3326 if (!g_value_transform (&from_val, &tag_value)) {
3327 GST_WARNING_OBJECT (demux,
3328 "Could not transform string tag to " "%s tag type %s",
3329 gst_tag_name, g_type_name (tag_type));
3330 g_value_unset (&tag_value);
3332 g_value_unset (&from_val);
3337 GST_DEBUG ("Setting metadata");
3338 g_value_init (&tag_value, G_TYPE_STRING);
3339 g_value_set_string (&tag_value, value_utf8);
3340 /* If we found a stereoscopic marker, look for StereoscopicLayout
3344 if (strncmp ("StereoscopicLayout", name_utf8,
3345 strlen (name_utf8)) == 0) {
3346 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3347 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3349 demux->asf_3D_mode =
3350 stereoscopic_layout_map[i].interleaving_type;
3351 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3355 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3357 demux->asf_3D_mode = GST_ASF_3D_NONE;
3358 GST_INFO_OBJECT (demux, "None 3d type");
3361 } else if (value_utf8 == NULL) {
3362 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3364 GST_DEBUG ("Skipping empty string value for %s",
3365 GST_STR_NULL (gst_tag_name));
3367 g_free (value_utf8);
3370 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3372 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3373 GST_FIXME ("Unhandled byte array tag %s",
3374 GST_STR_NULL (gst_tag_name));
3377 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3383 case ASF_DEMUX_DATA_TYPE_DWORD:{
3384 guint uint_val = GST_READ_UINT32_LE (value);
3386 /* this is the track number */
3387 g_value_init (&tag_value, G_TYPE_UINT);
3389 /* WM/Track counts from 0 */
3390 if (!strcmp (name_utf8, "WM/Track"))
3393 g_value_set_uint (&tag_value, uint_val);
3397 case ASF_DEMUX_DATA_TYPE_BOOL:{
3398 gboolean bool_val = GST_READ_UINT32_LE (value);
3400 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3402 GST_INFO_OBJECT (demux, "This is 3D contents");
3405 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3413 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3418 if (G_IS_VALUE (&tag_value)) {
3420 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3422 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3423 * is supposed to have a 0 base but is often wrongly written to start
3424 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3425 * replace the value added earlier from WM/Track or put it first in
3426 * the list, so that it will get picked up by _get_uint() */
3427 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3428 merge_mode = GST_TAG_MERGE_REPLACE;
3430 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3433 GST_DEBUG ("Setting global metadata %s", name_utf8);
3434 gst_structure_set_value (demux->global_metadata, name_utf8,
3438 g_value_unset (&tag_value);
3447 gst_asf_demux_add_global_tags (demux, taglist);
3454 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3455 gst_tag_list_unref (taglist);
3456 return GST_FLOW_OK; /* not really fatal */
3460 static GstStructure *
3461 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3466 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3468 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3471 s = gst_caps_get_structure (demux->metadata, i);
3472 if (gst_structure_has_name (s, sname))
3476 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3478 /* try lookup again; demux->metadata took ownership of the structure, so we
3479 * can't really make any assumptions about what happened to it, so we can't
3480 * just return it directly after appending it */
3481 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3484 static GstFlowReturn
3485 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3488 guint16 blockcount, i;
3490 GST_INFO_OBJECT (demux, "object is a metadata object");
3492 /* Content Descriptor Count */
3494 goto not_enough_data;
3496 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3498 for (i = 0; i < blockcount; ++i) {
3500 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3501 guint32 data_len, ival;
3504 if (size < (2 + 2 + 2 + 2 + 4))
3505 goto not_enough_data;
3507 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3508 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3509 name_len = gst_asf_demux_get_uint16 (&data, &size);
3510 data_type = gst_asf_demux_get_uint16 (&data, &size);
3511 data_len = gst_asf_demux_get_uint32 (&data, &size);
3513 if (size < name_len + data_len)
3514 goto not_enough_data;
3516 /* convert name to UTF-8 */
3517 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3519 gst_asf_demux_skip_bytes (name_len, &data, &size);
3521 if (name_utf8 == NULL) {
3522 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3523 gst_asf_demux_skip_bytes (data_len, &data, &size);
3527 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3528 gst_asf_demux_skip_bytes (data_len, &data, &size);
3536 goto not_enough_data;
3539 ival = gst_asf_demux_get_uint32 (&data, &size);
3541 /* skip anything else there may be, just in case */
3542 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3544 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3545 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3549 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3555 GST_WARNING ("Unexpected end of data parsing metadata object");
3556 return GST_FLOW_OK; /* not really fatal */
3560 static GstFlowReturn
3561 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3563 GstFlowReturn ret = GST_FLOW_OK;
3564 guint32 i, num_objects;
3565 guint8 unknown G_GNUC_UNUSED;
3567 /* Get the rest of the header's header */
3568 if (size < (4 + 1 + 1))
3569 goto not_enough_data;
3571 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3572 unknown = gst_asf_demux_get_uint8 (&data, &size);
3573 unknown = gst_asf_demux_get_uint8 (&data, &size);
3575 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3577 /* Loop through the header's objects, processing those */
3578 for (i = 0; i < num_objects; ++i) {
3579 GST_INFO_OBJECT (demux, "reading header part %u", i);
3580 ret = gst_asf_demux_process_object (demux, &data, &size);
3581 if (ret != GST_FLOW_OK) {
3582 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3591 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3592 ("short read parsing HEADER object"));
3593 return GST_FLOW_ERROR;
3597 static GstFlowReturn
3598 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3600 guint64 creation_time G_GNUC_UNUSED;
3601 guint64 file_size G_GNUC_UNUSED;
3602 guint64 send_time G_GNUC_UNUSED;
3603 guint64 packets_count, play_time, preroll;
3604 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3606 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3607 goto not_enough_data;
3609 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3610 file_size = gst_asf_demux_get_uint64 (&data, &size);
3611 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3612 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3613 play_time = gst_asf_demux_get_uint64 (&data, &size);
3614 send_time = gst_asf_demux_get_uint64 (&data, &size);
3615 preroll = gst_asf_demux_get_uint64 (&data, &size);
3616 flags = gst_asf_demux_get_uint32 (&data, &size);
3617 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3618 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3619 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3621 demux->broadcast = ! !(flags & 0x01);
3622 demux->seekable = ! !(flags & 0x02);
3624 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3625 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3626 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3628 if (demux->broadcast) {
3629 /* these fields are invalid if the broadcast flag is set */
3634 if (min_pktsize != max_pktsize)
3635 goto non_fixed_packet_size;
3637 demux->packet_size = max_pktsize;
3639 /* FIXME: do we need send_time as well? what is it? */
3640 if ((play_time * 100) >= (preroll * GST_MSECOND))
3641 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3643 demux->play_time = 0;
3645 demux->preroll = preroll * GST_MSECOND;
3647 /* initial latency */
3648 demux->latency = demux->preroll;
3650 if (demux->play_time == 0)
3651 demux->seekable = FALSE;
3653 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3654 GST_TIME_ARGS (demux->play_time));
3655 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3656 GST_TIME_ARGS (demux->preroll));
3658 if (demux->play_time > 0) {
3659 demux->segment.duration = demux->play_time;
3662 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3664 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3669 non_fixed_packet_size:
3671 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3672 ("packet size must be fixed"));
3673 return GST_FLOW_ERROR;
3677 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3678 ("short read parsing FILE object"));
3679 return GST_FLOW_ERROR;
3683 /* Content Description Object */
3684 static GstFlowReturn
3685 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3689 const gchar *gst_tag;
3694 GST_TAG_TITLE, 0, NULL}, {
3695 GST_TAG_ARTIST, 0, NULL}, {
3696 GST_TAG_COPYRIGHT, 0, NULL}, {
3697 GST_TAG_DESCRIPTION, 0, NULL}, {
3698 GST_TAG_COMMENT, 0, NULL}
3700 GstTagList *taglist;
3701 GValue value = { 0 };
3705 GST_INFO_OBJECT (demux, "object is a comment");
3707 if (size < (2 + 2 + 2 + 2 + 2))
3708 goto not_enough_data;
3710 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3711 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3712 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3713 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3714 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3716 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3717 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3718 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3720 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3721 if (size < tags[i].val_length)
3722 goto not_enough_data;
3724 /* might be just '/0', '/0'... */
3725 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3726 /* convert to UTF-8 */
3727 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3728 "UTF-8", "UTF-16LE", &in, &out, NULL);
3730 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3733 /* parse metadata into taglist */
3734 taglist = gst_tag_list_new_empty ();
3735 g_value_init (&value, G_TYPE_STRING);
3736 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3737 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3738 g_value_set_string (&value, tags[i].val_utf8);
3739 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3740 tags[i].gst_tag, &value, NULL);
3743 g_value_unset (&value);
3745 gst_asf_demux_add_global_tags (demux, taglist);
3747 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3748 g_free (tags[i].val_utf8);
3754 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3755 "comment tag section %d, skipping comment object", i);
3756 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3757 g_free (tags[i].val_utf8);
3758 return GST_FLOW_OK; /* not really fatal */
3762 static GstFlowReturn
3763 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3766 guint16 num_streams, i;
3770 goto not_enough_data;
3772 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3774 GST_INFO ("object is a bitrate properties object with %u streams",
3777 if (size < (num_streams * (2 + 4)))
3778 goto not_enough_data;
3780 for (i = 0; i < num_streams; ++i) {
3784 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3785 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3787 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3788 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3789 stream = gst_asf_demux_get_stream (demux, stream_id);
3791 if (stream->pending_tags == NULL)
3792 stream->pending_tags = gst_tag_list_new_empty ();
3793 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3794 GST_TAG_BITRATE, bitrate, NULL);
3796 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3799 GST_WARNING ("stream id %u is too large", stream_id);
3807 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3808 return GST_FLOW_OK; /* not really fatal */
3812 static GstFlowReturn
3813 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3816 GstFlowReturn ret = GST_FLOW_OK;
3819 /* Get the rest of the header's header */
3820 if (size < (16 + 2 + 4))
3821 goto not_enough_data;
3823 /* skip GUID and two other bytes */
3824 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3825 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3827 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3829 /* FIXME: does data_size include the rest of the header that we have read? */
3830 if (hdr_size > size)
3831 goto not_enough_data;
3833 while (hdr_size > 0) {
3834 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3835 if (ret != GST_FLOW_OK)
3843 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3844 ("short read parsing extended header object"));
3845 return GST_FLOW_ERROR;
3849 static GstFlowReturn
3850 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3856 goto not_enough_data;
3858 if (demux->languages) {
3859 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3860 g_strfreev (demux->languages);
3861 demux->languages = NULL;
3862 demux->num_languages = 0;
3865 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3866 GST_LOG ("%u languages:", demux->num_languages);
3868 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3869 for (i = 0; i < demux->num_languages; ++i) {
3870 guint8 len, *lang_data = NULL;
3873 goto not_enough_data;
3874 len = gst_asf_demux_get_uint8 (&data, &size);
3875 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3878 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3881 /* truncate "en-us" etc. to just "en" */
3882 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3885 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3886 demux->languages[i] = utf8;
3889 goto not_enough_data;
3897 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3898 g_free (demux->languages);
3899 demux->languages = NULL;
3900 return GST_FLOW_OK; /* not fatal */
3904 static GstFlowReturn
3905 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3908 GstClockTime interval;
3911 if (size < (16 + 8 + 4 + 4))
3912 goto not_enough_data;
3915 gst_asf_demux_skip_bytes (16, &data, &size);
3916 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3917 gst_asf_demux_skip_bytes (4, &data, &size);
3918 count = gst_asf_demux_get_uint32 (&data, &size);
3920 demux->sidx_interval = interval;
3921 demux->sidx_num_entries = count;
3922 g_free (demux->sidx_entries);
3923 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3925 for (i = 0; i < count; ++i) {
3926 if (G_UNLIKELY (size < 6)) {
3927 /* adjust for broken files, to avoid having entries at the end
3928 * of the parsed index that point to time=0. Resulting in seeking to
3929 * the end of the file leading back to the beginning */
3930 demux->sidx_num_entries -= (count - i);
3933 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3934 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3935 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3936 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3937 demux->sidx_entries[i].count);
3940 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3947 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3948 return GST_FLOW_OK; /* not fatal */
3952 static GstFlowReturn
3953 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3954 guint8 * data, guint64 size)
3959 if (size < 16 + 2 + (2 * 2))
3960 goto not_enough_data;
3962 gst_asf_demux_get_guid (&guid, &data, &size);
3963 num = gst_asf_demux_get_uint16 (&data, &size);
3966 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3970 if (size < (num * sizeof (guint16)))
3971 goto not_enough_data;
3973 /* read mutually exclusive stream numbers */
3974 for (i = 0; i < num; ++i) {
3976 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3977 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3979 demux->mut_ex_streams =
3980 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
3989 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3990 return GST_FLOW_OK; /* not absolutely fatal */
3995 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3997 return g_slist_find (demux->other_streams,
3998 GINT_TO_POINTER (stream_num)) == NULL;
4001 static GstFlowReturn
4002 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4005 AsfStreamExtProps esp;
4006 AsfStream *stream = NULL;
4007 AsfObject stream_obj;
4008 guint16 stream_name_count;
4009 guint16 num_payload_ext;
4011 guint8 *stream_obj_data = NULL;
4014 guint i, stream_num;
4017 obj_size = (guint) size;
4020 goto not_enough_data;
4023 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4024 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4025 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4026 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4027 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4028 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4029 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4030 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4031 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4032 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4033 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4034 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4035 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4036 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4037 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4039 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4040 GST_TIME_ARGS (esp.start_time));
4041 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4042 GST_TIME_ARGS (esp.end_time));
4043 GST_INFO ("flags = %08x", esp.flags);
4044 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4045 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4046 GST_INFO ("stream number = %u", stream_num);
4047 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4048 (esp.lang_idx < demux->num_languages) ?
4049 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4050 GST_INFO ("stream name count = %u", stream_name_count);
4052 /* read stream names */
4053 for (i = 0; i < stream_name_count; ++i) {
4054 guint16 stream_lang_idx G_GNUC_UNUSED;
4055 gchar *stream_name = NULL;
4058 goto not_enough_data;
4059 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4060 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4061 goto not_enough_data;
4062 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4063 g_free (stream_name); /* TODO: store names in struct */
4066 /* read payload extension systems stuff */
4067 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4069 if (num_payload_ext > 0)
4070 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4072 esp.payload_extensions = NULL;
4074 for (i = 0; i < num_payload_ext; ++i) {
4075 AsfPayloadExtension ext;
4077 guint32 sys_info_len;
4079 if (size < 16 + 2 + 4)
4080 goto not_enough_data;
4082 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4083 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4084 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4086 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4087 GST_LOG ("payload systems info len = %u", sys_info_len);
4088 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4089 goto not_enough_data;
4091 esp.payload_extensions[i] = ext;
4094 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4096 /* there might be an optional STREAM_INFO object here now; if not, we
4097 * should have parsed the corresponding stream info object already (since
4098 * we are parsing the extended stream properties objects delayed) */
4100 stream = gst_asf_demux_get_stream (demux, stream_num);
4104 /* get size of the stream object */
4105 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4106 goto not_enough_data;
4108 if (stream_obj.id != ASF_OBJ_STREAM)
4109 goto expected_stream_object;
4111 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4112 stream_obj.size > (10 * 1024 * 1024))
4113 goto not_enough_data;
4115 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4117 /* process this stream object later after all the other 'normal' ones
4118 * have been processed (since the others are more important/non-hidden) */
4119 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4120 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4121 goto not_enough_data;
4123 /* parse stream object */
4124 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4125 g_free (stream_obj_data);
4130 stream->ext_props = esp;
4132 /* try to set the framerate */
4133 if (stream->is_video && stream->caps) {
4134 GValue framerate = { 0 };
4138 g_value_init (&framerate, GST_TYPE_FRACTION);
4140 num = GST_SECOND / 100;
4141 denom = esp.avg_time_per_frame;
4143 /* avoid division by 0, assume 25/1 framerate */
4144 denom = GST_SECOND / 2500;
4147 gst_value_set_fraction (&framerate, num, denom);
4149 stream->caps = gst_caps_make_writable (stream->caps);
4150 s = gst_caps_get_structure (stream->caps, 0);
4151 gst_structure_set_value (s, "framerate", &framerate);
4152 g_value_unset (&framerate);
4153 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4154 num, denom, ((gdouble) num) / denom);
4157 /* add language info now if we have it */
4158 if (stream->ext_props.lang_idx < demux->num_languages) {
4159 if (stream->pending_tags == NULL)
4160 stream->pending_tags = gst_tag_list_new_empty ();
4161 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4162 demux->languages[stream->ext_props.lang_idx]);
4163 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4164 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4167 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4168 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4176 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4177 return GST_FLOW_OK; /* not absolutely fatal */
4179 expected_stream_object:
4181 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4182 "object: expected embedded stream object, but got %s object instead!",
4183 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4184 return GST_FLOW_OK; /* not absolutely fatal */
4188 static const gchar *
4189 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4193 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4194 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4195 nick += strlen ("ASF_OBJ_");
4197 if (demux->objpath == NULL) {
4198 demux->objpath = g_strdup (nick);
4202 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4203 g_free (demux->objpath);
4204 demux->objpath = newpath;
4207 return (const gchar *) demux->objpath;
4211 gst_asf_demux_pop_obj (GstASFDemux * demux)
4215 if ((s = g_strrstr (demux->objpath, "/"))) {
4218 g_free (demux->objpath);
4219 demux->objpath = NULL;
4224 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4229 /* Parse the queued extended stream property objects and add the info
4230 * to the existing streams or add the new embedded streams, but without
4231 * activating them yet */
4232 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4233 g_slist_length (demux->ext_stream_props));
4235 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4236 GstBuffer *buf = GST_BUFFER (l->data);
4239 gst_buffer_map (buf, &map, GST_MAP_READ);
4241 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4242 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4243 gst_buffer_unmap (buf, &map);
4244 gst_buffer_unref (buf);
4246 g_slist_free (demux->ext_stream_props);
4247 demux->ext_stream_props = NULL;
4252 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4256 for (i = 0; i < demux->num_streams; ++i) {
4261 stream = &demux->stream[i];
4263 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4265 if (stream->active) {
4266 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4271 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4274 /* check for each mutual exclusion whether it affects this stream */
4275 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4276 if (*mes == stream->id) {
4277 /* if yes, check if we've already added streams that are mutually
4278 * exclusive with the stream we're about to add */
4279 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4280 for (j = 0; j < demux->num_streams; ++j) {
4281 /* if the broadcast flag is set, assume the hidden streams aren't
4282 * actually streamed and hide them (or playbin won't work right),
4283 * otherwise assume their data is available */
4284 if (demux->stream[j].id == *mes && demux->broadcast) {
4286 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4287 "mutually exclusive with already existing stream ID %d, "
4288 "hiding stream", stream->id, demux->stream[j].id);
4300 /* FIXME: we should do stream activation based on preroll data in
4301 * streaming mode too */
4302 if (demux->streaming && !is_hidden)
4303 gst_asf_demux_activate_stream (demux, stream);
4308 static GstFlowReturn
4309 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4312 GstFlowReturn ret = GST_FLOW_OK;
4314 guint64 obj_data_size;
4316 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4317 return ASF_FLOW_NEED_MORE_DATA;
4319 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4320 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4322 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4324 if (*p_size < obj_data_size)
4325 return ASF_FLOW_NEED_MORE_DATA;
4327 gst_asf_demux_push_obj (demux, obj.id);
4329 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4332 case ASF_OBJ_STREAM:
4333 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4337 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4339 case ASF_OBJ_HEADER:
4340 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4342 case ASF_OBJ_COMMENT:
4343 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4346 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4348 case ASF_OBJ_BITRATE_PROPS:
4350 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4353 case ASF_OBJ_EXT_CONTENT_DESC:
4355 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4358 case ASF_OBJ_METADATA_OBJECT:
4359 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4361 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4364 /* process these later, we might not have parsed the corresponding
4365 * stream object yet */
4366 GST_LOG ("%s: queued for later parsing", demux->objpath);
4367 buf = gst_buffer_new_and_alloc (obj_data_size);
4368 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4369 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4373 case ASF_OBJ_LANGUAGE_LIST:
4374 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4376 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4377 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4380 case ASF_OBJ_SIMPLE_INDEX:
4381 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4383 case ASF_OBJ_CONTENT_ENCRYPTION:
4384 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4385 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4386 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4387 goto error_encrypted;
4388 case ASF_OBJ_CONCEAL_NONE:
4390 case ASF_OBJ_UNDEFINED:
4391 case ASF_OBJ_CODEC_COMMENT:
4393 case ASF_OBJ_PADDING:
4394 case ASF_OBJ_BITRATE_MUTEX:
4395 case ASF_OBJ_COMPATIBILITY:
4396 case ASF_OBJ_INDEX_PLACEHOLDER:
4397 case ASF_OBJ_INDEX_PARAMETERS:
4398 case ASF_OBJ_STREAM_PRIORITIZATION:
4399 case ASF_OBJ_SCRIPT_COMMAND:
4400 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4402 /* Unknown/unhandled object, skip it and hope for the best */
4403 GST_INFO ("%s: skipping object", demux->objpath);
4408 /* this can't fail, we checked the number of bytes available before */
4409 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4411 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4413 gst_asf_demux_pop_obj (demux);
4420 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4421 return GST_FLOW_ERROR;
4426 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4427 GstBuffer ** p_buffer)
4429 GstBuffer *descrambled_buffer;
4430 GstBuffer *scrambled_buffer;
4431 GstBuffer *sub_buffer;
4438 /* descrambled_buffer is initialised in the first iteration */
4439 descrambled_buffer = NULL;
4440 scrambled_buffer = *p_buffer;
4442 if (gst_buffer_get_size (scrambled_buffer) <
4443 stream->ds_packet_size * stream->span)
4446 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4447 offset += stream->ds_chunk_size) {
4448 off = offset / stream->ds_chunk_size;
4449 row = off / stream->span;
4450 col = off % stream->span;
4451 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4452 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4453 col, off, stream->ds_chunk_size);
4454 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4455 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4456 stream->span, stream->ds_packet_size);
4457 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4458 gst_buffer_get_size (scrambled_buffer));
4460 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4461 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4463 descrambled_buffer = sub_buffer;
4465 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4469 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4470 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4471 GST_BUFFER_DURATION (descrambled_buffer) =
4472 GST_BUFFER_DURATION (scrambled_buffer);
4473 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4474 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4475 GST_BUFFER_OFFSET_END (scrambled_buffer);
4477 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4479 gst_buffer_unref (scrambled_buffer);
4480 *p_buffer = descrambled_buffer;
4484 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4486 GstASFDemux *demux = GST_ASF_DEMUX (element);
4489 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4491 for (i = 0; i < demux->num_streams; ++i) {
4492 gst_event_ref (event);
4493 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4494 GST_OBJECT_CAST (element), event)) {
4495 gst_event_unref (event);
4500 gst_event_unref (event);
4504 /* takes ownership of the passed event */
4506 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4508 gboolean ret = TRUE;
4511 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4512 GST_EVENT_TYPE_NAME (event));
4514 for (i = 0; i < demux->num_streams; ++i) {
4515 gst_event_ref (event);
4516 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4518 gst_event_unref (event);
4523 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4527 gboolean res = FALSE;
4529 demux = GST_ASF_DEMUX (parent);
4531 GST_DEBUG ("handling %s query",
4532 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4534 switch (GST_QUERY_TYPE (query)) {
4535 case GST_QUERY_DURATION:
4539 gst_query_parse_duration (query, &format, NULL);
4541 if (format != GST_FORMAT_TIME) {
4542 GST_LOG ("only support duration queries in TIME format");
4546 res = gst_pad_query_default (pad, parent, query);
4548 GST_OBJECT_LOCK (demux);
4550 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4551 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4552 GST_TIME_ARGS (demux->segment.duration));
4554 gst_query_set_duration (query, GST_FORMAT_TIME,
4555 demux->segment.duration);
4559 GST_LOG ("duration not known yet");
4562 GST_OBJECT_UNLOCK (demux);
4567 case GST_QUERY_POSITION:{
4570 gst_query_parse_position (query, &format, NULL);
4572 if (format != GST_FORMAT_TIME) {
4573 GST_LOG ("only support position queries in TIME format");
4577 GST_OBJECT_LOCK (demux);
4579 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4580 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4581 GST_TIME_ARGS (demux->segment.position));
4583 gst_query_set_position (query, GST_FORMAT_TIME,
4584 demux->segment.position);
4588 GST_LOG ("position not known yet");
4591 GST_OBJECT_UNLOCK (demux);
4595 case GST_QUERY_SEEKING:{
4598 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4599 if (format == GST_FORMAT_TIME) {
4602 GST_OBJECT_LOCK (demux);
4603 duration = demux->segment.duration;
4604 GST_OBJECT_UNLOCK (demux);
4606 if (!demux->streaming || !demux->seekable) {
4607 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4614 /* try upstream first in TIME */
4615 res = gst_pad_query_default (pad, parent, query);
4617 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4618 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4619 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4620 /* if no luck, maybe in BYTES */
4621 if (!seekable || fmt != GST_FORMAT_TIME) {
4624 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4625 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4626 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4627 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4628 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4629 if (fmt != GST_FORMAT_BYTES)
4632 gst_query_unref (q);
4633 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4639 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4643 case GST_QUERY_LATENCY:
4646 GstClockTime min, max;
4648 /* preroll delay does not matter in non-live pipeline,
4649 * but we might end up in a live (rtsp) one ... */
4652 res = gst_pad_query_default (pad, parent, query);
4656 gst_query_parse_latency (query, &live, &min, &max);
4658 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4659 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4660 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4662 GST_OBJECT_LOCK (demux);
4663 min += demux->latency;
4665 max += demux->latency;
4666 GST_OBJECT_UNLOCK (demux);
4668 gst_query_set_latency (query, live, min, max);
4671 case GST_QUERY_SEGMENT:
4676 format = demux->segment.format;
4679 gst_segment_to_stream_time (&demux->segment, format,
4680 demux->segment.start);
4681 if ((stop = demux->segment.stop) == -1)
4682 stop = demux->segment.duration;
4684 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4686 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4691 res = gst_pad_query_default (pad, parent, query);
4698 static GstStateChangeReturn
4699 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4701 GstASFDemux *demux = GST_ASF_DEMUX (element);
4702 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4704 switch (transition) {
4705 case GST_STATE_CHANGE_NULL_TO_READY:{
4706 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4707 demux->need_newsegment = TRUE;
4708 demux->segment_running = FALSE;
4709 demux->keyunit_sync = FALSE;
4710 demux->accurate = FALSE;
4711 demux->adapter = gst_adapter_new ();
4712 demux->metadata = gst_caps_new_empty ();
4713 demux->global_metadata = gst_structure_new_empty ("metadata");
4714 demux->data_size = 0;
4715 demux->data_offset = 0;
4716 demux->index_offset = 0;
4717 demux->base_offset = 0;
4718 demux->flowcombiner = gst_flow_combiner_new ();
4726 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4727 if (ret == GST_STATE_CHANGE_FAILURE)
4730 switch (transition) {
4731 case GST_STATE_CHANGE_PAUSED_TO_READY:
4732 gst_asf_demux_reset (demux, FALSE);
4735 case GST_STATE_CHANGE_READY_TO_NULL:
4736 gst_asf_demux_reset (demux, FALSE);
4737 gst_flow_combiner_free (demux->flowcombiner);
4738 demux->flowcombiner = NULL;