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);
1248 if (flow == ASF_FLOW_NEED_MORE_DATA)
1249 flow = GST_FLOW_ERROR;
1256 all_streams_prerolled (GstASFDemux * demux)
1258 GstClockTime preroll_time;
1259 guint i, num_no_data = 0;
1261 /* Allow at least 500ms of preroll_time */
1262 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1264 /* returns TRUE as long as there isn't a stream which (a) has data queued
1265 * and (b) the timestamp of last piece of data queued is < demux->preroll
1266 * AND there is at least one other stream with data queued */
1267 for (i = 0; i < demux->num_streams; ++i) {
1268 AsfPayload *last_payload = NULL;
1272 stream = &demux->stream[i];
1273 if (G_UNLIKELY (stream->payloads->len == 0)) {
1275 GST_LOG_OBJECT (stream->pad, "no data queued");
1279 /* find last payload with timestamp */
1280 for (last_idx = stream->payloads->len - 1;
1281 last_idx >= 0 && (last_payload == NULL
1282 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1283 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1286 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1287 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1288 GST_TIME_ARGS (preroll_time));
1289 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1290 || last_payload->ts <= preroll_time)) {
1291 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1296 if (G_UNLIKELY (num_no_data > 0))
1304 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1309 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1312 /* check for each mutual exclusion group whether it affects this stream */
1313 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1314 if (*mes == stream->id) {
1315 /* we are in this group; let's check if we've already activated streams
1316 * that are in the same group (and hence mutually exclusive to this
1318 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1321 for (i = 0; i < demux->num_streams; ++i) {
1322 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1323 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1324 "to already active stream with ID %d", stream->id,
1325 demux->stream[i].id);
1330 /* we can only be in this group once, let's break out and move on to
1331 * the next mutual exclusion group */
1342 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1344 /* remember the first queued timestamp for the segment */
1345 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1346 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1347 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1348 GST_TIME_ARGS (demux->first_ts));
1349 demux->segment_ts = payload_ts;
1350 /* always note, but only determines segment when streaming */
1351 if (demux->streaming)
1352 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1353 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1354 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1359 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1361 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1362 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1365 /* go trhough each stream, find smallest timestamp */
1366 for (i = 0; i < demux->num_streams; ++i) {
1369 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1370 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1371 stream = &demux->stream[i];
1373 for (j = 0; j < stream->payloads->len; ++j) {
1374 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1375 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1376 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1377 || stream_min_ts > payload->ts)) {
1378 stream_min_ts = payload->ts;
1380 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1381 payload->ts > stream_min_ts &&
1382 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1383 || stream_min_ts2 > payload->ts)) {
1384 stream_min_ts2 = payload->ts;
1388 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1389 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1390 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1391 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1392 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1394 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1397 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1398 stream_min_ts = stream_min_ts2;
1400 /* if we don't have timestamp for this stream, wait for more data */
1401 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1404 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1405 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1406 first_ts = stream_min_ts;
1409 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1412 demux->first_ts = first_ts;
1414 /* update packets queued before we knew first timestamp */
1415 for (i = 0; i < demux->num_streams; ++i) {
1418 stream = &demux->stream[i];
1420 for (j = 0; j < stream->payloads->len; ++j) {
1421 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1422 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1423 if (payload->ts > first_ts)
1424 payload->ts -= first_ts;
1432 gst_asf_demux_check_segment_ts (demux, 0);
1438 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1440 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1441 and often set wrong, inspecting the data is the only way that seem to be working */
1442 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1443 GstCaps *caps = NULL;
1445 GstAdapter *adapter = gst_adapter_new ();
1447 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1449 AsfPayload *payload;
1452 payload = &g_array_index (stream->payloads, AsfPayload, i);
1453 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1454 len = gst_adapter_available (adapter);
1455 data = gst_adapter_map (adapter, len);
1459 #define MIN_LENGTH 128
1461 /* look for the sync points */
1463 if (len < MIN_LENGTH || /* give typefind something to work on */
1464 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1465 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1471 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1474 if (prob < GST_TYPE_FIND_LIKELY) {
1477 if (len > MIN_LENGTH)
1478 /* this wasn't it, look for another sync point */
1482 gst_adapter_unmap (adapter);
1485 gst_object_unref (adapter);
1488 gst_caps_take (&stream->caps, caps);
1496 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1498 guint i, actual_streams = 0;
1500 if (demux->activated_streams)
1503 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1506 if (!all_streams_prerolled (demux) && !force) {
1507 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1511 for (i = 0; i < demux->num_streams; ++i) {
1512 AsfStream *stream = &demux->stream[i];
1514 if (stream->payloads->len > 0) {
1516 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1517 !stream->active && /* do not inspect active streams (caps were already set) */
1518 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1519 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1520 /* try to gather some more data */
1523 /* we don't check mutual exclusion stuff here; either we have data for
1524 * a stream, then we active it, or we don't, then we'll ignore it */
1525 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1526 gst_asf_demux_activate_stream (demux, stream);
1527 actual_streams += 1;
1529 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1533 if (actual_streams == 0) {
1534 /* We don't have any streams activated ! */
1535 GST_ERROR_OBJECT (demux, "No streams activated!");
1539 gst_asf_demux_release_old_pads (demux);
1541 demux->activated_streams = TRUE;
1542 GST_LOG_OBJECT (demux, "signalling no more pads");
1543 gst_element_no_more_pads (GST_ELEMENT (demux));
1547 /* returns the stream that has a complete payload with the lowest timestamp
1548 * queued, or NULL (we push things by timestamp because during the internal
1549 * prerolling we might accumulate more data then the external queues can take,
1550 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1552 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1554 AsfPayload *best_payload = NULL;
1555 AsfStream *best_stream = NULL;
1558 for (i = 0; i < demux->num_streams; ++i) {
1562 stream = &demux->stream[i];
1564 /* Don't push any data until we have at least one payload that falls within
1565 * the current segment. This way we can remove out-of-segment payloads that
1566 * don't need to be decoded after a seek, sending only data from the
1567 * keyframe directly before our segment start */
1568 if (stream->payloads->len > 0) {
1569 AsfPayload *payload = NULL;
1572 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1573 /* Reverse playback */
1575 if (stream->is_video) {
1576 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1577 if (stream->reverse_kf_ready) {
1579 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1580 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1581 /* TODO : remove payload from the list? */
1588 /* find first complete payload with timestamp */
1589 for (j = stream->payloads->len - 1;
1590 j >= 0 && (payload == NULL
1591 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1592 payload = &g_array_index (stream->payloads, AsfPayload, j);
1595 /* If there's a complete payload queued for this stream */
1596 if (!gst_asf_payload_is_complete (payload))
1602 /* find last payload with timestamp */
1603 for (last_idx = stream->payloads->len - 1;
1604 last_idx >= 0 && (payload == NULL
1605 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1606 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1609 /* if this is first payload after seek we might need to update the segment */
1610 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1611 gst_asf_demux_check_segment_ts (demux, payload->ts);
1613 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1614 (payload->ts < demux->segment.start))) {
1615 if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1616 && payload->keyframe)) {
1617 GST_DEBUG_OBJECT (stream->pad,
1618 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1619 GST_TIME_ARGS (payload->ts));
1620 demux->segment.start = payload->ts;
1621 demux->segment.time = payload->ts;
1623 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1624 GST_TIME_FORMAT " which is before our segment start %"
1625 GST_TIME_FORMAT ", not pushing yet",
1626 GST_TIME_ARGS (payload->ts),
1627 GST_TIME_ARGS (demux->segment.start));
1632 /* find first complete payload with timestamp */
1634 j < stream->payloads->len && (payload == NULL
1635 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1636 payload = &g_array_index (stream->payloads, AsfPayload, j);
1639 /* Now see if there's a complete payload queued for this stream */
1640 if (!gst_asf_payload_is_complete (payload))
1644 /* ... and whether its timestamp is lower than the current best */
1645 if (best_stream == NULL || best_payload->ts > payload->ts) {
1646 best_stream = stream;
1647 best_payload = payload;
1655 static GstFlowReturn
1656 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1659 GstFlowReturn ret = GST_FLOW_OK;
1661 if (G_UNLIKELY (!demux->activated_streams)) {
1662 if (!gst_asf_demux_check_activate_streams (demux, force))
1664 /* streams are now activated */
1667 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1668 AsfPayload *payload;
1669 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1670 GstClockTime duration = GST_CLOCK_TIME_NONE;
1672 /* wait until we had a chance to "lock on" some payload's timestamp */
1673 if (G_UNLIKELY (demux->need_newsegment
1674 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1677 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1678 && stream->payloads->len) {
1679 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1681 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1684 /* do we need to send a newsegment event */
1685 if ((G_UNLIKELY (demux->need_newsegment))) {
1686 GstEvent *segment_event;
1688 /* safe default if insufficient upstream info */
1689 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1692 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1693 demux->segment.duration > 0) {
1694 /* slight HACK; prevent clipping of last bit */
1695 demux->segment.stop = demux->segment.duration + demux->in_gap;
1698 /* FIXME : only if ACCURATE ! */
1699 if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1700 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1701 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1702 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1703 GST_TIME_ARGS (payload->ts));
1704 demux->segment.start = payload->ts;
1705 demux->segment.time = payload->ts;
1708 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1711 /* note: we fix up all timestamps to start from 0, so this should be ok */
1712 segment_event = gst_event_new_segment (&demux->segment);
1713 if (demux->segment_seqnum)
1714 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1715 gst_asf_demux_send_event_unlocked (demux, segment_event);
1717 /* now post any global tags we may have found */
1718 if (demux->taglist == NULL) {
1719 demux->taglist = gst_tag_list_new_empty ();
1720 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1723 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1724 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1726 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1727 gst_asf_demux_send_event_unlocked (demux,
1728 gst_event_new_tag (demux->taglist));
1729 demux->taglist = NULL;
1731 demux->need_newsegment = FALSE;
1732 demux->segment_seqnum = 0;
1733 demux->segment_running = TRUE;
1736 /* Do we have tags pending for this stream? */
1737 if (G_UNLIKELY (stream->pending_tags)) {
1738 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1739 gst_pad_push_event (stream->pad,
1740 gst_event_new_tag (stream->pending_tags));
1741 stream->pending_tags = NULL;
1744 /* We have the whole packet now so we should push the packet to
1745 * the src pad now. First though we should check if we need to do
1747 if (G_UNLIKELY (stream->span > 1)) {
1748 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1751 payload->buf = gst_buffer_make_writable (payload->buf);
1753 if (G_LIKELY (!payload->keyframe)) {
1754 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1757 if (G_UNLIKELY (stream->discont)) {
1758 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1759 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1760 stream->discont = FALSE;
1763 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1764 (payload->par_x != stream->par_x) &&
1765 (payload->par_y != stream->par_y))) {
1766 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1767 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1768 stream->par_x = payload->par_x;
1769 stream->par_y = payload->par_y;
1770 stream->caps = gst_caps_make_writable (stream->caps);
1771 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1772 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1773 gst_pad_set_caps (stream->pad, stream->caps);
1776 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1777 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1778 payload->interlaced);
1779 stream->interlaced = payload->interlaced;
1780 stream->caps = gst_caps_make_writable (stream->caps);
1781 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1782 (stream->interlaced ? "mixed" : "progressive"), NULL);
1783 gst_pad_set_caps (stream->pad, stream->caps);
1786 /* (sort of) interpolate timestamps using upstream "frame of reference",
1787 * typically useful for live src, but might (unavoidably) mess with
1788 * position reporting if a live src is playing not so live content
1789 * (e.g. rtspsrc taking some time to fall back to tcp) */
1790 timestamp = payload->ts;
1791 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1792 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1793 timestamp += demux->in_gap;
1795 /* Check if we're after the segment already, if so no need to push
1797 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1798 GST_DEBUG_OBJECT (stream->pad,
1799 "Payload after segment stop %" GST_TIME_FORMAT,
1800 GST_TIME_ARGS (demux->segment.stop));
1802 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1804 gst_buffer_unref (payload->buf);
1805 payload->buf = NULL;
1806 g_array_remove_index (stream->payloads, 0);
1807 /* Break out as soon as we have an issue */
1808 if (G_UNLIKELY (ret != GST_FLOW_OK))
1815 GST_BUFFER_PTS (payload->buf) = timestamp;
1817 if (payload->duration == GST_CLOCK_TIME_NONE
1818 && stream->ext_props.avg_time_per_frame != 0) {
1819 duration = stream->ext_props.avg_time_per_frame * 100;
1821 duration = payload->duration;
1823 GST_BUFFER_DURATION (payload->buf) = duration;
1825 /* FIXME: we should really set durations on buffers if we can */
1827 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1830 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1831 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1832 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1834 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1835 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1839 if (stream->active) {
1840 if (G_UNLIKELY (stream->first_buffer)) {
1841 if (stream->streamheader != NULL) {
1842 GST_DEBUG_OBJECT (stream->pad,
1843 "Pushing streamheader before first buffer");
1844 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1846 stream->first_buffer = FALSE;
1849 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1850 && timestamp > demux->segment.position) {
1851 demux->segment.position = timestamp;
1852 if (GST_CLOCK_TIME_IS_VALID (duration))
1853 demux->segment.position += timestamp;
1856 ret = gst_pad_push (stream->pad, payload->buf);
1858 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1861 gst_buffer_unref (payload->buf);
1864 payload->buf = NULL;
1865 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1866 && stream->reverse_kf_ready) {
1867 g_array_remove_index (stream->payloads, stream->kf_pos);
1870 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1872 stream->reverse_kf_ready = FALSE;
1875 g_array_remove_index (stream->payloads, 0);
1878 /* Break out as soon as we have an issue */
1879 if (G_UNLIKELY (ret != GST_FLOW_OK))
1887 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1891 g_assert (buf != NULL);
1893 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1895 gst_buffer_map (buf, &map, GST_MAP_READ);
1897 /* we return false on buffer too small */
1898 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1899 gst_buffer_unmap (buf, &map);
1903 /* check if it is a header */
1904 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1905 gst_buffer_unmap (buf, &map);
1906 if (obj.id == ASF_OBJ_HEADER) {
1913 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1915 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1916 GstFlowReturn ret = GST_FLOW_OK;
1917 GstBuffer *buf = NULL;
1918 gboolean header = FALSE;
1920 /* TODO maybe we should skip index objects after the data and look
1921 * further for a new header */
1922 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1923 g_assert (buf != NULL);
1924 /* check if it is a header */
1925 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1926 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1927 demux->base_offset = off;
1931 gst_buffer_unref (buf);
1938 gst_asf_demux_loop (GstASFDemux * demux)
1940 GstFlowReturn flow = GST_FLOW_OK;
1941 GstBuffer *buf = NULL;
1944 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1945 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1949 gst_asf_demux_pull_indices (demux);
1952 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1954 if (G_UNLIKELY (demux->num_packets != 0
1955 && demux->packet >= demux->num_packets))
1958 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1959 (guint) demux->num_packets);
1961 off = demux->data_offset + (demux->packet * demux->packet_size);
1963 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1964 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1965 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1966 if (flow == GST_FLOW_EOS) {
1968 } else if (flow == GST_FLOW_FLUSHING) {
1969 GST_DEBUG_OBJECT (demux, "Not fatal");
1976 if (G_LIKELY (demux->speed_packets == 1)) {
1977 GstAsfDemuxParsePacketError err;
1978 err = gst_asf_demux_parse_packet (demux, buf);
1979 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1980 /* when we don't know when the data object ends, we should check
1981 * for a chained asf */
1982 if (demux->num_packets == 0) {
1983 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1984 GST_INFO_OBJECT (demux, "Chained asf found");
1985 demux->base_offset = off;
1986 gst_asf_demux_reset (demux, TRUE);
1987 gst_buffer_unref (buf);
1991 /* FIXME: We should tally up fatal errors and error out only
1992 * after a few broken packets in a row? */
1994 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1995 gst_buffer_unref (buf);
1997 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
1998 && !demux->seek_to_cur_pos) {
2000 if (demux->packet < 0) {
2010 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2012 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2013 && !demux->seek_to_cur_pos) {
2015 if (demux->packet < 0) {
2024 for (n = 0; n < demux->speed_packets; n++) {
2026 GstAsfDemuxParsePacketError err;
2029 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2030 n * demux->packet_size, demux->packet_size);
2031 err = gst_asf_demux_parse_packet (demux, sub);
2032 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2033 /* when we don't know when the data object ends, we should check
2034 * for a chained asf */
2035 if (demux->num_packets == 0) {
2036 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2037 GST_INFO_OBJECT (demux, "Chained asf found");
2038 demux->base_offset = off + n * demux->packet_size;
2039 gst_asf_demux_reset (demux, TRUE);
2040 gst_buffer_unref (sub);
2041 gst_buffer_unref (buf);
2045 /* FIXME: We should tally up fatal errors and error out only
2046 * after a few broken packets in a row? */
2048 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2052 gst_buffer_unref (sub);
2054 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2055 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2061 /* reset speed pull */
2062 demux->speed_packets = 1;
2065 gst_buffer_unref (buf);
2067 if (G_UNLIKELY ((demux->num_packets > 0
2068 && demux->packet >= demux->num_packets)
2069 || flow == GST_FLOW_EOS)) {
2070 GST_LOG_OBJECT (demux, "reached EOS");
2074 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2075 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2079 /* check if we're at the end of the configured segment */
2080 /* FIXME: check if segment end reached etc. */
2086 /* if we haven't activated our streams yet, this might be because we have
2087 * less data queued than required for preroll; force stream activation and
2088 * send any pending payloads before sending EOS */
2089 if (!demux->activated_streams)
2090 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
2092 /* we want to push an eos or post a segment-done in any case */
2093 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2096 /* for segment playback we need to post when (in stream time)
2097 * we stopped, this is either stop (when set) or the duration. */
2098 if ((stop = demux->segment.stop) == -1)
2099 stop = demux->segment.duration;
2101 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2102 gst_element_post_message (GST_ELEMENT_CAST (demux),
2103 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2105 gst_asf_demux_send_event_unlocked (demux,
2106 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2107 } else if (flow != GST_FLOW_EOS) {
2108 /* check if we have a chained asf, in case, we don't eos yet */
2109 if (gst_asf_demux_check_chained_asf (demux)) {
2110 GST_INFO_OBJECT (demux, "Chained ASF starting");
2111 gst_asf_demux_reset (demux, TRUE);
2116 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2117 if (demux->activated_streams) {
2118 /* normal playback, send EOS to all linked pads */
2119 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2120 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2122 GST_WARNING_OBJECT (demux, "EOS without exposed streams");
2123 flow = GST_FLOW_EOS;
2126 /* ... and fall through to pause */
2130 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2131 gst_flow_get_name (flow));
2132 demux->segment_running = FALSE;
2133 gst_pad_pause_task (demux->sinkpad);
2135 /* For the error cases */
2136 if (flow == GST_FLOW_EOS && !demux->activated_streams) {
2137 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
2138 ("This doesn't seem to be an ASF file"));
2139 } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2140 /* Post an error. Hopefully something else already has, but if not... */
2141 GST_ELEMENT_FLOW_ERROR (demux, flow);
2142 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2151 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2152 flow = GST_FLOW_EOS;
2156 /* See FIXMEs above */
2159 gst_buffer_unref (buf);
2160 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2161 ("Error parsing ASF packet %u", (guint) demux->packet));
2162 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2163 flow = GST_FLOW_ERROR;
2169 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2170 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2171 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2174 gst_asf_demux_check_header (GstASFDemux * demux)
2177 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2178 ASF_OBJECT_HEADER_SIZE);
2179 if (cdata == NULL) /* need more data */
2180 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2182 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2183 if (obj.id != ASF_OBJ_HEADER) {
2184 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2186 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2190 static GstFlowReturn
2191 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2193 GstFlowReturn ret = GST_FLOW_OK;
2196 demux = GST_ASF_DEMUX (parent);
2198 GST_LOG_OBJECT (demux,
2199 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2200 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2201 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2203 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2204 GST_DEBUG_OBJECT (demux, "received DISCONT");
2205 gst_asf_demux_mark_discont (demux);
2208 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2209 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2210 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2211 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2212 ", interpolation gap: %" GST_TIME_FORMAT,
2213 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2216 gst_adapter_push (demux->adapter, buf);
2218 switch (demux->state) {
2219 case GST_ASF_DEMUX_STATE_INDEX:{
2220 gint result = gst_asf_demux_check_header (demux);
2221 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2224 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2225 /* we don't care about this, probably an index */
2226 /* TODO maybe would be smarter to skip all the indices
2227 * until we got a new header or EOS to decide */
2228 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2231 GST_INFO_OBJECT (demux, "Chained asf starting");
2232 /* cleanup and get ready for a chained asf */
2233 gst_asf_demux_reset (demux, TRUE);
2237 case GST_ASF_DEMUX_STATE_HEADER:{
2238 ret = gst_asf_demux_chain_headers (demux);
2239 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2241 /* otherwise fall through */
2243 case GST_ASF_DEMUX_STATE_DATA:
2247 data_size = demux->packet_size;
2249 while (gst_adapter_available (demux->adapter) >= data_size) {
2251 GstAsfDemuxParsePacketError err;
2253 /* we don't know the length of the stream
2254 * check for a chained asf everytime */
2255 if (demux->num_packets == 0) {
2256 gint result = gst_asf_demux_check_header (demux);
2258 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2259 GST_INFO_OBJECT (demux, "Chained asf starting");
2260 /* cleanup and get ready for a chained asf */
2261 gst_asf_demux_reset (demux, TRUE);
2264 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2265 && demux->packet >= demux->num_packets)) {
2266 /* do not overshoot data section when streaming */
2270 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2272 /* FIXME: We should tally up fatal errors and error out only
2273 * after a few broken packets in a row? */
2274 err = gst_asf_demux_parse_packet (demux, buf);
2276 gst_buffer_unref (buf);
2278 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2279 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2281 GST_WARNING_OBJECT (demux, "Parse error");
2283 if (demux->packet >= 0)
2286 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2287 && demux->packet >= demux->num_packets)) {
2288 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2293 g_assert_not_reached ();
2297 if (ret != GST_FLOW_OK)
2298 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2304 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2310 static inline gboolean
2311 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2313 if (*p_size < num_bytes)
2316 *p_data += num_bytes;
2317 *p_size -= num_bytes;
2321 static inline guint8
2322 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2326 g_assert (*p_size >= 1);
2327 ret = GST_READ_UINT8 (*p_data);
2328 *p_data += sizeof (guint8);
2329 *p_size -= sizeof (guint8);
2333 static inline guint16
2334 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2338 g_assert (*p_size >= 2);
2339 ret = GST_READ_UINT16_LE (*p_data);
2340 *p_data += sizeof (guint16);
2341 *p_size -= sizeof (guint16);
2345 static inline guint32
2346 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2350 g_assert (*p_size >= 4);
2351 ret = GST_READ_UINT32_LE (*p_data);
2352 *p_data += sizeof (guint32);
2353 *p_size -= sizeof (guint32);
2357 static inline guint64
2358 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2362 g_assert (*p_size >= 8);
2363 ret = GST_READ_UINT64_LE (*p_data);
2364 *p_data += sizeof (guint64);
2365 *p_size -= sizeof (guint64);
2370 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2371 guint8 ** p_data, guint64 * p_size)
2375 if (*p_size < num_bytes_to_read)
2378 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2379 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2381 *p_data += num_bytes_to_read;
2382 *p_size -= num_bytes_to_read;
2388 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2389 guint8 ** p_data, guint64 * p_size)
2393 if (*p_size < num_bytes_to_read)
2396 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2397 *p_data += num_bytes_to_read;
2398 *p_size -= num_bytes_to_read;
2403 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2404 guint8 ** p_data, guint64 * p_size)
2414 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2417 *p_strlen = s_length;
2419 if (s_length == 0) {
2420 GST_WARNING ("zero-length string");
2421 *p_str = g_strdup ("");
2425 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2428 g_assert (s != NULL);
2430 /* just because They don't exist doesn't
2431 * mean They are not out to get you ... */
2432 if (s[s_length - 1] != '\0') {
2433 s = g_realloc (s, s_length + 1);
2437 *p_str = (gchar *) s;
2443 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2445 g_assert (*p_size >= 4 * sizeof (guint32));
2447 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2448 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2449 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2450 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2454 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2457 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2460 /* WAVEFORMATEX Structure */
2461 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2462 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2463 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2464 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2465 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2466 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2467 /* Codec specific data size */
2468 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2473 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2476 if (*p_size < (4 + 4 + 1 + 2))
2479 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2480 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2481 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2482 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2487 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2488 guint8 ** p_data, guint64 * p_size)
2490 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2493 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2494 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2495 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2496 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2497 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2498 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2499 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2500 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2501 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2502 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2503 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2508 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2512 for (i = 0; i < demux->num_streams; i++) {
2513 if (demux->stream[i].id == id)
2514 return &demux->stream[i];
2517 if (gst_asf_demux_is_unknown_stream (demux, id))
2518 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2523 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2524 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2529 gst_pad_use_fixed_caps (src_pad);
2530 gst_pad_set_caps (src_pad, caps);
2532 gst_pad_set_event_function (src_pad,
2533 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2534 gst_pad_set_query_function (src_pad,
2535 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2537 stream = &demux->stream[demux->num_streams];
2538 stream->caps = caps;
2539 stream->pad = src_pad;
2541 stream->fps_known = !is_video; /* bit hacky for audio */
2542 stream->is_video = is_video;
2543 stream->pending_tags = tags;
2544 stream->discont = TRUE;
2545 stream->first_buffer = TRUE;
2546 stream->streamheader = streamheader;
2547 if (stream->streamheader) {
2548 stream->streamheader = gst_buffer_make_writable (streamheader);
2549 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2554 st = gst_caps_get_structure (caps, 0);
2555 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2556 par_x > 0 && par_y > 0) {
2557 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2558 stream->par_x = par_x;
2559 stream->par_y = par_y;
2563 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2565 /* TODO: create this array during reverse play? */
2566 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2568 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2569 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2571 ++demux->num_streams;
2573 stream->active = FALSE;
2579 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2580 GstBuffer * buffer, GstStructure * structure)
2582 GValue arr_val = G_VALUE_INIT;
2583 GValue buf_val = G_VALUE_INIT;
2585 g_value_init (&arr_val, GST_TYPE_ARRAY);
2586 g_value_init (&buf_val, GST_TYPE_BUFFER);
2588 gst_value_set_buffer (&buf_val, buffer);
2589 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2591 gst_structure_take_value (structure, "streamheader", &arr_val);
2595 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2596 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2598 GstTagList *tags = NULL;
2599 GstBuffer *extradata = NULL;
2602 guint16 size_left = 0;
2603 gchar *codec_name = NULL;
2606 size_left = audio->size;
2608 /* Create the audio pad */
2609 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2611 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2614 /* Swallow up any left over data and set up the
2615 * standard properties from the header info */
2617 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2618 "codec specific data", size_left);
2620 g_assert (size_left <= *p_size);
2621 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2624 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2625 * additional two bytes indicating extradata. */
2626 /* FIXME: Handle the channel reorder map here */
2627 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2628 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2631 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2632 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2635 /* Informing about that audio format we just added */
2637 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2638 g_free (codec_name);
2641 if (audio->byte_rate > 0) {
2642 /* Some ASF files have no bitrate props object (often seen with
2643 * ASF files that contain raw audio data). Example files can
2644 * be generated with FFmpeg (tested with v2.8.6), like this:
2646 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2648 * In this case, if audio->byte_rate is nonzero, use that as
2651 guint bitrate = audio->byte_rate * 8;
2654 tags = gst_tag_list_new_empty ();
2656 /* Add bitrate, but only if there is none set already, since
2657 * this is just a fallback in case there is no bitrate tag
2658 * already present */
2659 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2663 gst_buffer_unref (extradata);
2665 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2666 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2667 audio->codec_tag, tags);
2669 ++demux->num_audio_streams;
2671 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2675 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2676 asf_stream_video_format * video, guint16 id,
2677 guint8 ** p_data, guint64 * p_size)
2679 GstTagList *tags = NULL;
2680 GstStructure *caps_s;
2681 GstBuffer *extradata = NULL;
2686 gchar *codec_name = NULL;
2687 gint size_left = video->size - 40;
2688 GstBuffer *streamheader = NULL;
2689 guint par_w = 1, par_h = 1;
2691 /* Create the video pad */
2692 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2693 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2696 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2698 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2699 g_assert (size_left <= *p_size);
2700 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2703 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2705 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2706 caps = gst_riff_create_video_caps (video->tag, NULL,
2707 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2710 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2711 G_TYPE_UINT, video->tag, NULL);
2716 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2717 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2718 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2721 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2725 /* retry with the global metadata */
2726 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2727 demux->global_metadata);
2728 s = demux->global_metadata;
2729 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2730 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2731 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2732 if (ax > 0 && ay > 0) {
2735 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2740 s = gst_caps_get_structure (caps, 0);
2741 gst_structure_remove_field (s, "framerate");
2744 caps_s = gst_caps_get_structure (caps, 0);
2746 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2747 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2748 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2749 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2752 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2753 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2754 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2756 GstBuffer *buf = gst_value_get_buffer (value);
2759 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2760 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2761 /* this looks like a bytestream start */
2762 streamheader = gst_buffer_ref (buf);
2763 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2764 gst_structure_remove_field (caps_s, "codec_data");
2767 gst_buffer_unmap (buf, &mapinfo);
2772 /* For a 3D video, set multiview information into the caps based on
2773 * what was detected during object parsing */
2774 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2775 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2776 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2777 const gchar *mview_mode_str;
2779 switch (demux->asf_3D_mode) {
2780 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2781 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2783 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2784 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2785 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2787 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2788 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2790 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2791 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2792 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2794 case GST_ASF_3D_DUAL_STREAM:{
2795 gboolean is_right_view = FALSE;
2796 /* if Advanced_Mutual_Exclusion object exists, use it
2797 * to figure out which is the left view (lower ID) */
2798 if (demux->mut_ex_streams != NULL) {
2802 length = g_slist_length (demux->mut_ex_streams);
2804 for (i = 0; i < length; i++) {
2807 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2809 GST_DEBUG_OBJECT (demux,
2810 "has Mutual_Exclusion object. stream id in object is %d",
2811 GPOINTER_TO_INT (v_s_id));
2813 if (id > GPOINTER_TO_INT (v_s_id))
2814 is_right_view = TRUE;
2817 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2818 * first video stream encountered has the lower ID */
2819 if (demux->num_video_streams > 0) {
2820 /* This is not the first video stream, assuming right eye view */
2821 is_right_view = TRUE;
2825 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2827 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2834 GST_INFO_OBJECT (demux,
2835 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2838 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2839 if (mview_mode_str != NULL) {
2840 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2841 video->height, par_w, par_h))
2842 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2844 gst_caps_set_simple (caps,
2845 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2846 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2847 GST_FLAG_SET_MASK_EXACT, NULL);
2852 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2853 g_free (codec_name);
2857 gst_buffer_unref (extradata);
2859 GST_INFO ("Adding video stream #%u, id %u, codec %"
2860 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2861 GST_FOURCC_ARGS (video->tag), video->tag);
2863 ++demux->num_video_streams;
2865 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2866 streamheader, tags);
2870 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2872 if (!stream->active) {
2876 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2877 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2878 gst_pad_set_active (stream->pad, TRUE);
2881 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2882 "%03u", stream->id);
2885 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2887 if (gst_event_parse_group_id (event, &demux->group_id))
2888 demux->have_group_id = TRUE;
2890 demux->have_group_id = FALSE;
2891 gst_event_unref (event);
2892 } else if (!demux->have_group_id) {
2893 demux->have_group_id = TRUE;
2894 demux->group_id = gst_util_group_id_next ();
2897 event = gst_event_new_stream_start (stream_id);
2898 if (demux->have_group_id)
2899 gst_event_set_group_id (event, demux->group_id);
2901 gst_pad_push_event (stream->pad, event);
2903 gst_pad_set_caps (stream->pad, stream->caps);
2905 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2906 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2907 stream->active = TRUE;
2912 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2915 AsfCorrectionType correction_type;
2916 AsfStreamType stream_type;
2917 GstClockTime time_offset;
2918 gboolean is_encrypted G_GNUC_UNUSED;
2922 guint stream_specific_size;
2923 guint type_specific_size G_GNUC_UNUSED;
2924 guint unknown G_GNUC_UNUSED;
2925 gboolean inspect_payload = FALSE;
2926 AsfStream *stream = NULL;
2928 /* Get the rest of the header's header */
2929 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2930 goto not_enough_data;
2932 gst_asf_demux_get_guid (&guid, &data, &size);
2933 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2935 gst_asf_demux_get_guid (&guid, &data, &size);
2936 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2938 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2940 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2941 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2943 flags = gst_asf_demux_get_uint16 (&data, &size);
2944 stream_id = flags & 0x7f;
2945 is_encrypted = ! !((flags & 0x8000) << 15);
2946 unknown = gst_asf_demux_get_uint32 (&data, &size);
2948 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2949 stream_id, GST_TIME_ARGS (time_offset));
2951 /* dvr-ms has audio stream declared in stream specific data */
2952 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2953 AsfExtStreamType ext_stream_type;
2954 gst_asf_demux_get_guid (&guid, &data, &size);
2955 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2957 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2958 inspect_payload = TRUE;
2960 gst_asf_demux_get_guid (&guid, &data, &size);
2961 gst_asf_demux_get_uint32 (&data, &size);
2962 gst_asf_demux_get_uint32 (&data, &size);
2963 gst_asf_demux_get_uint32 (&data, &size);
2964 gst_asf_demux_get_guid (&guid, &data, &size);
2965 gst_asf_demux_get_uint32 (&data, &size);
2966 stream_type = ASF_STREAM_AUDIO;
2970 switch (stream_type) {
2971 case ASF_STREAM_AUDIO:{
2972 asf_stream_audio audio_object;
2974 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2975 goto not_enough_data;
2977 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2980 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2983 switch (correction_type) {
2984 case ASF_CORRECTION_ON:{
2985 guint span, packet_size, chunk_size, data_size, silence_data;
2987 GST_INFO ("Using error correction");
2989 if (size < (1 + 2 + 2 + 2 + 1))
2990 goto not_enough_data;
2992 span = gst_asf_demux_get_uint8 (&data, &size);
2993 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2994 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2995 data_size = gst_asf_demux_get_uint16 (&data, &size);
2996 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2998 stream->span = span;
3000 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
3001 packet_size, chunk_size, data_size, span, silence_data);
3003 if (stream->span > 1) {
3004 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
3005 /* Disable descrambling */
3008 /* FIXME: this else branch was added for
3009 * weird_al_yankovic - the saga begins.asf */
3010 stream->ds_packet_size = packet_size;
3011 stream->ds_chunk_size = chunk_size;
3014 /* Descambling is enabled */
3015 stream->ds_packet_size = packet_size;
3016 stream->ds_chunk_size = chunk_size;
3019 /* Now skip the rest of the silence data */
3021 gst_bytestream_flush (demux->bs, data_size - 1);
3023 /* FIXME: CHECKME. And why -1? */
3024 if (data_size > 1) {
3025 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3026 goto not_enough_data;
3032 case ASF_CORRECTION_OFF:{
3033 GST_INFO ("Error correction off");
3034 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3035 goto not_enough_data;
3039 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3040 ("Audio stream using unknown error correction"));
3047 case ASF_STREAM_VIDEO:{
3048 asf_stream_video_format video_format_object;
3049 asf_stream_video video_object;
3052 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3053 goto not_enough_data;
3055 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3057 GST_INFO ("object is a video stream with %u bytes of "
3058 "additional data", vsize);
3060 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3062 goto not_enough_data;
3065 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3066 stream_id, &data, &size);
3072 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3074 demux->other_streams =
3075 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3080 stream->inspect_payload = inspect_payload;
3085 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3086 /* we'll error out later if we found no streams */
3091 static const gchar *
3092 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3096 const gchar *asf_name;
3097 const gchar *gst_name;
3100 "WM/Genre", GST_TAG_GENRE}, {
3101 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3102 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3103 "WM/Picture", GST_TAG_IMAGE}, {
3104 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3105 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3106 "WM/Year", GST_TAG_DATE_TIME}
3107 /* { "WM/Composer", GST_TAG_COMPOSER } */
3112 if (name_utf8 == NULL) {
3113 GST_WARNING ("Failed to convert name to UTF8, skipping");
3117 out = strlen (name_utf8);
3119 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3120 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3121 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3122 return tags[i].gst_name;
3129 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3131 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3135 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3137 if (taglist == NULL)
3140 if (gst_tag_list_is_empty (taglist)) {
3141 gst_tag_list_unref (taglist);
3145 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3146 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3148 gst_tag_list_unref (demux->taglist);
3149 gst_tag_list_unref (taglist);
3151 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3154 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3155 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3156 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3157 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3160 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3164 const guint8 *img_data = NULL;
3165 guint32 img_data_len = 0;
3166 guint8 pic_type = 0;
3168 gst_byte_reader_init (&r, tag_data, tag_data_len);
3170 /* skip mime type string (we don't trust it and do our own typefinding),
3171 * and also skip the description string, since we don't use it */
3172 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3173 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3174 !gst_byte_reader_skip_string_utf16 (&r) ||
3175 !gst_byte_reader_skip_string_utf16 (&r) ||
3176 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3177 goto not_enough_data;
3181 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3182 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3188 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3189 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3194 /* Extended Content Description Object */
3195 static GstFlowReturn
3196 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3199 /* Other known (and unused) 'text/unicode' metadata available :
3202 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3203 * WMFSDKVersion = 9.00.00.2980
3204 * WMFSDKNeeded = 0.0.0.0000
3205 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3206 * WM/Publisher = 4AD
3208 * WM/ProviderRating = 8
3209 * WM/ProviderStyle = Rock (similar to WM/Genre)
3210 * WM/GenreID (similar to WM/Genre)
3211 * WM/TrackNumber (same as WM/Track but as a string)
3213 * Other known (and unused) 'non-text' metadata available :
3219 * We might want to read WM/TrackNumber and use atoi() if we don't have
3223 GstTagList *taglist;
3224 guint16 blockcount, i;
3225 gboolean content3D = FALSE;
3229 const gchar *interleave_name;
3230 GstASF3DMode interleaving_type;
3231 } stereoscopic_layout_map[] = {
3233 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3234 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3235 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3236 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3237 "DualStream", GST_ASF_3D_DUAL_STREAM}
3239 GST_INFO_OBJECT (demux, "object is an extended content description");
3241 taglist = gst_tag_list_new_empty ();
3243 /* Content Descriptor Count */
3245 goto not_enough_data;
3247 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3249 for (i = 1; i <= blockcount; ++i) {
3250 const gchar *gst_tag_name;
3254 GValue tag_value = { 0, };
3257 gchar *name_utf8 = NULL;
3261 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3262 goto not_enough_data;
3266 goto not_enough_data;
3268 /* Descriptor Value Data Type */
3269 datatype = gst_asf_demux_get_uint16 (&data, &size);
3271 /* Descriptor Value (not really a string, but same thing reading-wise) */
3272 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3274 goto not_enough_data;
3278 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3280 if (name_utf8 != NULL) {
3281 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3283 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3284 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3287 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3290 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3293 /* get rid of tags with empty value */
3294 if (value_utf8 != NULL && *value_utf8 != '\0') {
3295 GST_DEBUG ("string value %s", value_utf8);
3297 value_utf8[out] = '\0';
3299 if (gst_tag_name != NULL) {
3300 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3301 guint year = atoi (value_utf8);
3304 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3305 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3307 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3308 guint id3v1_genre_id;
3309 const gchar *genre_str;
3311 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3312 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3313 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3314 g_free (value_utf8);
3315 value_utf8 = g_strdup (genre_str);
3320 /* convert tag from string to other type if required */
3321 tag_type = gst_tag_get_type (gst_tag_name);
3322 g_value_init (&tag_value, tag_type);
3323 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3324 GValue from_val = { 0, };
3326 g_value_init (&from_val, G_TYPE_STRING);
3327 g_value_set_string (&from_val, value_utf8);
3328 if (!g_value_transform (&from_val, &tag_value)) {
3329 GST_WARNING_OBJECT (demux,
3330 "Could not transform string tag to " "%s tag type %s",
3331 gst_tag_name, g_type_name (tag_type));
3332 g_value_unset (&tag_value);
3334 g_value_unset (&from_val);
3339 GST_DEBUG ("Setting metadata");
3340 g_value_init (&tag_value, G_TYPE_STRING);
3341 g_value_set_string (&tag_value, value_utf8);
3342 /* If we found a stereoscopic marker, look for StereoscopicLayout
3346 if (strncmp ("StereoscopicLayout", name_utf8,
3347 strlen (name_utf8)) == 0) {
3348 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3349 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3351 demux->asf_3D_mode =
3352 stereoscopic_layout_map[i].interleaving_type;
3353 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3357 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3359 demux->asf_3D_mode = GST_ASF_3D_NONE;
3360 GST_INFO_OBJECT (demux, "None 3d type");
3363 } else if (value_utf8 == NULL) {
3364 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3366 GST_DEBUG ("Skipping empty string value for %s",
3367 GST_STR_NULL (gst_tag_name));
3369 g_free (value_utf8);
3372 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3374 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3375 GST_FIXME ("Unhandled byte array tag %s",
3376 GST_STR_NULL (gst_tag_name));
3379 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3385 case ASF_DEMUX_DATA_TYPE_DWORD:{
3386 guint uint_val = GST_READ_UINT32_LE (value);
3388 /* this is the track number */
3389 g_value_init (&tag_value, G_TYPE_UINT);
3391 /* WM/Track counts from 0 */
3392 if (!strcmp (name_utf8, "WM/Track"))
3395 g_value_set_uint (&tag_value, uint_val);
3399 case ASF_DEMUX_DATA_TYPE_BOOL:{
3400 gboolean bool_val = GST_READ_UINT32_LE (value);
3402 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3404 GST_INFO_OBJECT (demux, "This is 3D contents");
3407 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3415 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3420 if (G_IS_VALUE (&tag_value)) {
3422 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3424 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3425 * is supposed to have a 0 base but is often wrongly written to start
3426 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3427 * replace the value added earlier from WM/Track or put it first in
3428 * the list, so that it will get picked up by _get_uint() */
3429 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3430 merge_mode = GST_TAG_MERGE_REPLACE;
3432 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3435 GST_DEBUG ("Setting global metadata %s", name_utf8);
3436 gst_structure_set_value (demux->global_metadata, name_utf8,
3440 g_value_unset (&tag_value);
3449 gst_asf_demux_add_global_tags (demux, taglist);
3456 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3457 gst_tag_list_unref (taglist);
3458 return GST_FLOW_OK; /* not really fatal */
3462 static GstStructure *
3463 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3468 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3470 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3473 s = gst_caps_get_structure (demux->metadata, i);
3474 if (gst_structure_has_name (s, sname))
3478 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3480 /* try lookup again; demux->metadata took ownership of the structure, so we
3481 * can't really make any assumptions about what happened to it, so we can't
3482 * just return it directly after appending it */
3483 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3486 static GstFlowReturn
3487 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3490 guint16 blockcount, i;
3492 GST_INFO_OBJECT (demux, "object is a metadata object");
3494 /* Content Descriptor Count */
3496 goto not_enough_data;
3498 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3500 for (i = 0; i < blockcount; ++i) {
3502 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3503 guint32 data_len, ival;
3506 if (size < (2 + 2 + 2 + 2 + 4))
3507 goto not_enough_data;
3509 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3510 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3511 name_len = gst_asf_demux_get_uint16 (&data, &size);
3512 data_type = gst_asf_demux_get_uint16 (&data, &size);
3513 data_len = gst_asf_demux_get_uint32 (&data, &size);
3515 if (size < name_len + data_len)
3516 goto not_enough_data;
3518 /* convert name to UTF-8 */
3519 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3521 gst_asf_demux_skip_bytes (name_len, &data, &size);
3523 if (name_utf8 == NULL) {
3524 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3525 gst_asf_demux_skip_bytes (data_len, &data, &size);
3529 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3530 gst_asf_demux_skip_bytes (data_len, &data, &size);
3538 goto not_enough_data;
3541 ival = gst_asf_demux_get_uint32 (&data, &size);
3543 /* skip anything else there may be, just in case */
3544 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3546 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3547 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3551 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3557 GST_WARNING ("Unexpected end of data parsing metadata object");
3558 return GST_FLOW_OK; /* not really fatal */
3562 static GstFlowReturn
3563 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3565 GstFlowReturn ret = GST_FLOW_OK;
3566 guint32 i, num_objects;
3567 guint8 unknown G_GNUC_UNUSED;
3569 /* Get the rest of the header's header */
3570 if (size < (4 + 1 + 1))
3571 goto not_enough_data;
3573 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3574 unknown = gst_asf_demux_get_uint8 (&data, &size);
3575 unknown = gst_asf_demux_get_uint8 (&data, &size);
3577 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3578 demux->saw_file_header = FALSE;
3579 /* Loop through the header's objects, processing those */
3580 for (i = 0; i < num_objects; ++i) {
3581 GST_INFO_OBJECT (demux, "reading header part %u", i);
3582 ret = gst_asf_demux_process_object (demux, &data, &size);
3583 if (ret != GST_FLOW_OK) {
3584 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3588 if (!demux->saw_file_header) {
3589 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3590 ("Header does not have mandatory FILE section"));
3591 return GST_FLOW_ERROR;
3598 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3599 ("short read parsing HEADER object"));
3600 return GST_FLOW_ERROR;
3604 static GstFlowReturn
3605 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3607 guint64 creation_time G_GNUC_UNUSED;
3608 guint64 file_size G_GNUC_UNUSED;
3609 guint64 send_time G_GNUC_UNUSED;
3610 guint64 packets_count, play_time, preroll;
3611 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3613 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3614 goto not_enough_data;
3616 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3617 file_size = gst_asf_demux_get_uint64 (&data, &size);
3618 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3619 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3620 play_time = gst_asf_demux_get_uint64 (&data, &size);
3621 send_time = gst_asf_demux_get_uint64 (&data, &size);
3622 preroll = gst_asf_demux_get_uint64 (&data, &size);
3623 flags = gst_asf_demux_get_uint32 (&data, &size);
3624 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3625 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3626 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3628 demux->broadcast = ! !(flags & 0x01);
3629 demux->seekable = ! !(flags & 0x02);
3631 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3632 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3633 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3635 if (demux->broadcast) {
3636 /* these fields are invalid if the broadcast flag is set */
3641 if (min_pktsize != max_pktsize)
3642 goto non_fixed_packet_size;
3644 demux->packet_size = max_pktsize;
3646 /* FIXME: do we need send_time as well? what is it? */
3647 if ((play_time * 100) >= (preroll * GST_MSECOND))
3648 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3650 demux->play_time = 0;
3652 demux->preroll = preroll * GST_MSECOND;
3654 /* initial latency */
3655 demux->latency = demux->preroll;
3657 if (demux->play_time == 0)
3658 demux->seekable = FALSE;
3660 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3661 GST_TIME_ARGS (demux->play_time));
3662 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3663 GST_TIME_ARGS (demux->preroll));
3665 if (demux->play_time > 0) {
3666 demux->segment.duration = demux->play_time;
3669 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3671 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3673 demux->saw_file_header = TRUE;
3678 non_fixed_packet_size:
3680 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3681 ("packet size must be fixed"));
3682 return GST_FLOW_ERROR;
3686 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3687 ("short read parsing FILE object"));
3688 return GST_FLOW_ERROR;
3692 /* Content Description Object */
3693 static GstFlowReturn
3694 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3698 const gchar *gst_tag;
3703 GST_TAG_TITLE, 0, NULL}, {
3704 GST_TAG_ARTIST, 0, NULL}, {
3705 GST_TAG_COPYRIGHT, 0, NULL}, {
3706 GST_TAG_DESCRIPTION, 0, NULL}, {
3707 GST_TAG_COMMENT, 0, NULL}
3709 GstTagList *taglist;
3710 GValue value = { 0 };
3714 GST_INFO_OBJECT (demux, "object is a comment");
3716 if (size < (2 + 2 + 2 + 2 + 2))
3717 goto not_enough_data;
3719 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3720 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3721 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3722 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3723 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3725 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3726 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3727 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3729 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3730 if (size < tags[i].val_length)
3731 goto not_enough_data;
3733 /* might be just '/0', '/0'... */
3734 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3735 /* convert to UTF-8 */
3736 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3737 "UTF-8", "UTF-16LE", &in, &out, NULL);
3739 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3742 /* parse metadata into taglist */
3743 taglist = gst_tag_list_new_empty ();
3744 g_value_init (&value, G_TYPE_STRING);
3745 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3746 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3747 g_value_set_string (&value, tags[i].val_utf8);
3748 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3749 tags[i].gst_tag, &value, NULL);
3752 g_value_unset (&value);
3754 gst_asf_demux_add_global_tags (demux, taglist);
3756 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3757 g_free (tags[i].val_utf8);
3763 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3764 "comment tag section %d, skipping comment object", i);
3765 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3766 g_free (tags[i].val_utf8);
3767 return GST_FLOW_OK; /* not really fatal */
3771 static GstFlowReturn
3772 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3775 guint16 num_streams, i;
3779 goto not_enough_data;
3781 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3783 GST_INFO ("object is a bitrate properties object with %u streams",
3786 if (size < (num_streams * (2 + 4)))
3787 goto not_enough_data;
3789 for (i = 0; i < num_streams; ++i) {
3793 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3794 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3796 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3797 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3798 stream = gst_asf_demux_get_stream (demux, stream_id);
3800 if (stream->pending_tags == NULL)
3801 stream->pending_tags = gst_tag_list_new_empty ();
3802 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3803 GST_TAG_BITRATE, bitrate, NULL);
3805 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3808 GST_WARNING ("stream id %u is too large", stream_id);
3816 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3817 return GST_FLOW_OK; /* not really fatal */
3821 static GstFlowReturn
3822 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3825 GstFlowReturn ret = GST_FLOW_OK;
3828 /* Get the rest of the header's header */
3829 if (size < (16 + 2 + 4))
3830 goto not_enough_data;
3832 /* skip GUID and two other bytes */
3833 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3834 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3836 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3838 /* FIXME: does data_size include the rest of the header that we have read? */
3839 if (hdr_size > size)
3840 goto not_enough_data;
3842 while (hdr_size > 0) {
3843 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3844 if (ret != GST_FLOW_OK)
3852 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3853 ("short read parsing extended header object"));
3854 return GST_FLOW_ERROR;
3858 static GstFlowReturn
3859 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3865 goto not_enough_data;
3867 if (demux->languages) {
3868 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3869 g_strfreev (demux->languages);
3870 demux->languages = NULL;
3871 demux->num_languages = 0;
3874 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3875 GST_LOG ("%u languages:", demux->num_languages);
3877 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3878 for (i = 0; i < demux->num_languages; ++i) {
3879 guint8 len, *lang_data = NULL;
3882 goto not_enough_data;
3883 len = gst_asf_demux_get_uint8 (&data, &size);
3884 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3887 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3890 /* truncate "en-us" etc. to just "en" */
3891 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3894 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3895 demux->languages[i] = utf8;
3898 goto not_enough_data;
3906 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3907 g_free (demux->languages);
3908 demux->languages = NULL;
3909 return GST_FLOW_OK; /* not fatal */
3913 static GstFlowReturn
3914 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3917 GstClockTime interval;
3920 if (size < (16 + 8 + 4 + 4))
3921 goto not_enough_data;
3924 gst_asf_demux_skip_bytes (16, &data, &size);
3925 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3926 gst_asf_demux_skip_bytes (4, &data, &size);
3927 count = gst_asf_demux_get_uint32 (&data, &size);
3929 demux->sidx_interval = interval;
3930 demux->sidx_num_entries = count;
3931 g_free (demux->sidx_entries);
3932 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3934 for (i = 0; i < count; ++i) {
3935 if (G_UNLIKELY (size < 6)) {
3936 /* adjust for broken files, to avoid having entries at the end
3937 * of the parsed index that point to time=0. Resulting in seeking to
3938 * the end of the file leading back to the beginning */
3939 demux->sidx_num_entries -= (count - i);
3942 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3943 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3944 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3945 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3946 demux->sidx_entries[i].count);
3949 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3956 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3957 return GST_FLOW_OK; /* not fatal */
3961 static GstFlowReturn
3962 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3963 guint8 * data, guint64 size)
3968 if (size < 16 + 2 + (2 * 2))
3969 goto not_enough_data;
3971 gst_asf_demux_get_guid (&guid, &data, &size);
3972 num = gst_asf_demux_get_uint16 (&data, &size);
3975 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3979 if (size < (num * sizeof (guint16)))
3980 goto not_enough_data;
3982 /* read mutually exclusive stream numbers */
3983 for (i = 0; i < num; ++i) {
3985 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3986 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3988 demux->mut_ex_streams =
3989 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
3998 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3999 return GST_FLOW_OK; /* not absolutely fatal */
4004 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
4006 return g_slist_find (demux->other_streams,
4007 GINT_TO_POINTER (stream_num)) == NULL;
4010 static GstFlowReturn
4011 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
4014 AsfStreamExtProps esp;
4015 AsfStream *stream = NULL;
4016 AsfObject stream_obj;
4017 guint16 stream_name_count;
4018 guint16 num_payload_ext;
4020 guint8 *stream_obj_data = NULL;
4023 guint i, stream_num;
4026 obj_size = (guint) size;
4029 goto not_enough_data;
4032 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4033 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4034 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4035 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4036 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4037 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4038 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4039 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4040 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4041 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4042 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4043 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4044 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4045 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4046 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4048 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4049 GST_TIME_ARGS (esp.start_time));
4050 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4051 GST_TIME_ARGS (esp.end_time));
4052 GST_INFO ("flags = %08x", esp.flags);
4053 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4054 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4055 GST_INFO ("stream number = %u", stream_num);
4056 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4057 (esp.lang_idx < demux->num_languages) ?
4058 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4059 GST_INFO ("stream name count = %u", stream_name_count);
4061 /* read stream names */
4062 for (i = 0; i < stream_name_count; ++i) {
4063 guint16 stream_lang_idx G_GNUC_UNUSED;
4064 gchar *stream_name = NULL;
4067 goto not_enough_data;
4068 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4069 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4070 goto not_enough_data;
4071 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4072 g_free (stream_name); /* TODO: store names in struct */
4075 /* read payload extension systems stuff */
4076 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4078 if (num_payload_ext > 0)
4079 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4081 esp.payload_extensions = NULL;
4083 for (i = 0; i < num_payload_ext; ++i) {
4084 AsfPayloadExtension ext;
4086 guint32 sys_info_len;
4088 if (size < 16 + 2 + 4)
4089 goto not_enough_data;
4091 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4092 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4093 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4095 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4096 GST_LOG ("payload systems info len = %u", sys_info_len);
4097 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4098 goto not_enough_data;
4100 esp.payload_extensions[i] = ext;
4103 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4105 /* there might be an optional STREAM_INFO object here now; if not, we
4106 * should have parsed the corresponding stream info object already (since
4107 * we are parsing the extended stream properties objects delayed) */
4109 stream = gst_asf_demux_get_stream (demux, stream_num);
4113 /* get size of the stream object */
4114 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4115 goto not_enough_data;
4117 if (stream_obj.id != ASF_OBJ_STREAM)
4118 goto expected_stream_object;
4120 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4121 stream_obj.size > (10 * 1024 * 1024))
4122 goto not_enough_data;
4124 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4126 /* process this stream object later after all the other 'normal' ones
4127 * have been processed (since the others are more important/non-hidden) */
4128 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4129 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4130 goto not_enough_data;
4132 /* parse stream object */
4133 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4134 g_free (stream_obj_data);
4139 stream->ext_props = esp;
4141 /* try to set the framerate */
4142 if (stream->is_video && stream->caps) {
4143 GValue framerate = { 0 };
4147 g_value_init (&framerate, GST_TYPE_FRACTION);
4149 num = GST_SECOND / 100;
4150 denom = esp.avg_time_per_frame;
4152 /* avoid division by 0, assume 25/1 framerate */
4153 denom = GST_SECOND / 2500;
4156 gst_value_set_fraction (&framerate, num, denom);
4158 stream->caps = gst_caps_make_writable (stream->caps);
4159 s = gst_caps_get_structure (stream->caps, 0);
4160 gst_structure_set_value (s, "framerate", &framerate);
4161 g_value_unset (&framerate);
4162 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4163 num, denom, ((gdouble) num) / denom);
4166 /* add language info now if we have it */
4167 if (stream->ext_props.lang_idx < demux->num_languages) {
4168 if (stream->pending_tags == NULL)
4169 stream->pending_tags = gst_tag_list_new_empty ();
4170 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4171 demux->languages[stream->ext_props.lang_idx]);
4172 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4173 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4176 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4177 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4185 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4186 return GST_FLOW_OK; /* not absolutely fatal */
4188 expected_stream_object:
4190 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4191 "object: expected embedded stream object, but got %s object instead!",
4192 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4193 return GST_FLOW_OK; /* not absolutely fatal */
4197 static const gchar *
4198 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4202 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4203 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4204 nick += strlen ("ASF_OBJ_");
4206 if (demux->objpath == NULL) {
4207 demux->objpath = g_strdup (nick);
4211 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4212 g_free (demux->objpath);
4213 demux->objpath = newpath;
4216 return (const gchar *) demux->objpath;
4220 gst_asf_demux_pop_obj (GstASFDemux * demux)
4224 if ((s = g_strrstr (demux->objpath, "/"))) {
4227 g_free (demux->objpath);
4228 demux->objpath = NULL;
4233 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4238 /* Parse the queued extended stream property objects and add the info
4239 * to the existing streams or add the new embedded streams, but without
4240 * activating them yet */
4241 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4242 g_slist_length (demux->ext_stream_props));
4244 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4245 GstBuffer *buf = GST_BUFFER (l->data);
4248 gst_buffer_map (buf, &map, GST_MAP_READ);
4250 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4251 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4252 gst_buffer_unmap (buf, &map);
4253 gst_buffer_unref (buf);
4255 g_slist_free (demux->ext_stream_props);
4256 demux->ext_stream_props = NULL;
4261 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4265 for (i = 0; i < demux->num_streams; ++i) {
4270 stream = &demux->stream[i];
4272 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4274 if (stream->active) {
4275 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4280 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4283 /* check for each mutual exclusion whether it affects this stream */
4284 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4285 if (*mes == stream->id) {
4286 /* if yes, check if we've already added streams that are mutually
4287 * exclusive with the stream we're about to add */
4288 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4289 for (j = 0; j < demux->num_streams; ++j) {
4290 /* if the broadcast flag is set, assume the hidden streams aren't
4291 * actually streamed and hide them (or playbin won't work right),
4292 * otherwise assume their data is available */
4293 if (demux->stream[j].id == *mes && demux->broadcast) {
4295 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4296 "mutually exclusive with already existing stream ID %d, "
4297 "hiding stream", stream->id, demux->stream[j].id);
4309 /* FIXME: we should do stream activation based on preroll data in
4310 * streaming mode too */
4311 if (demux->streaming && !is_hidden)
4312 gst_asf_demux_activate_stream (demux, stream);
4317 static GstFlowReturn
4318 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4321 GstFlowReturn ret = GST_FLOW_OK;
4323 guint64 obj_data_size;
4325 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4326 return ASF_FLOW_NEED_MORE_DATA;
4328 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4329 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4331 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4333 if (*p_size < obj_data_size)
4334 return ASF_FLOW_NEED_MORE_DATA;
4336 gst_asf_demux_push_obj (demux, obj.id);
4338 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4341 case ASF_OBJ_STREAM:
4342 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4346 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4348 case ASF_OBJ_HEADER:
4349 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4351 case ASF_OBJ_COMMENT:
4352 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4355 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4357 case ASF_OBJ_BITRATE_PROPS:
4359 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4362 case ASF_OBJ_EXT_CONTENT_DESC:
4364 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4367 case ASF_OBJ_METADATA_OBJECT:
4368 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4370 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4373 /* process these later, we might not have parsed the corresponding
4374 * stream object yet */
4375 GST_LOG ("%s: queued for later parsing", demux->objpath);
4376 buf = gst_buffer_new_and_alloc (obj_data_size);
4377 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4378 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4382 case ASF_OBJ_LANGUAGE_LIST:
4383 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4385 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4386 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4389 case ASF_OBJ_SIMPLE_INDEX:
4390 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4392 case ASF_OBJ_CONTENT_ENCRYPTION:
4393 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4394 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4395 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4396 goto error_encrypted;
4397 case ASF_OBJ_CONCEAL_NONE:
4399 case ASF_OBJ_UNDEFINED:
4400 case ASF_OBJ_CODEC_COMMENT:
4402 case ASF_OBJ_PADDING:
4403 case ASF_OBJ_BITRATE_MUTEX:
4404 case ASF_OBJ_COMPATIBILITY:
4405 case ASF_OBJ_INDEX_PLACEHOLDER:
4406 case ASF_OBJ_INDEX_PARAMETERS:
4407 case ASF_OBJ_STREAM_PRIORITIZATION:
4408 case ASF_OBJ_SCRIPT_COMMAND:
4409 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4411 /* Unknown/unhandled object, skip it and hope for the best */
4412 GST_INFO ("%s: skipping object", demux->objpath);
4417 /* this can't fail, we checked the number of bytes available before */
4418 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4420 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4422 gst_asf_demux_pop_obj (demux);
4429 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4430 return GST_FLOW_ERROR;
4435 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4436 GstBuffer ** p_buffer)
4438 GstBuffer *descrambled_buffer;
4439 GstBuffer *scrambled_buffer;
4440 GstBuffer *sub_buffer;
4447 /* descrambled_buffer is initialised in the first iteration */
4448 descrambled_buffer = NULL;
4449 scrambled_buffer = *p_buffer;
4451 if (gst_buffer_get_size (scrambled_buffer) <
4452 stream->ds_packet_size * stream->span)
4455 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4456 offset += stream->ds_chunk_size) {
4457 off = offset / stream->ds_chunk_size;
4458 row = off / stream->span;
4459 col = off % stream->span;
4460 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4461 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4462 col, off, stream->ds_chunk_size);
4463 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4464 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4465 stream->span, stream->ds_packet_size);
4466 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4467 gst_buffer_get_size (scrambled_buffer));
4469 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4470 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4472 descrambled_buffer = sub_buffer;
4474 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4478 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4479 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4480 GST_BUFFER_DURATION (descrambled_buffer) =
4481 GST_BUFFER_DURATION (scrambled_buffer);
4482 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4483 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4484 GST_BUFFER_OFFSET_END (scrambled_buffer);
4486 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4488 gst_buffer_unref (scrambled_buffer);
4489 *p_buffer = descrambled_buffer;
4493 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4495 GstASFDemux *demux = GST_ASF_DEMUX (element);
4498 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4500 for (i = 0; i < demux->num_streams; ++i) {
4501 gst_event_ref (event);
4502 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4503 GST_OBJECT_CAST (element), event)) {
4504 gst_event_unref (event);
4509 gst_event_unref (event);
4513 /* takes ownership of the passed event */
4515 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4517 gboolean ret = TRUE;
4520 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4521 GST_EVENT_TYPE_NAME (event));
4523 for (i = 0; i < demux->num_streams; ++i) {
4524 gst_event_ref (event);
4525 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4527 gst_event_unref (event);
4532 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4536 gboolean res = FALSE;
4538 demux = GST_ASF_DEMUX (parent);
4540 GST_DEBUG ("handling %s query",
4541 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4543 switch (GST_QUERY_TYPE (query)) {
4544 case GST_QUERY_DURATION:
4548 gst_query_parse_duration (query, &format, NULL);
4550 if (format != GST_FORMAT_TIME) {
4551 GST_LOG ("only support duration queries in TIME format");
4555 res = gst_pad_query_default (pad, parent, query);
4557 GST_OBJECT_LOCK (demux);
4559 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4560 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4561 GST_TIME_ARGS (demux->segment.duration));
4563 gst_query_set_duration (query, GST_FORMAT_TIME,
4564 demux->segment.duration);
4568 GST_LOG ("duration not known yet");
4571 GST_OBJECT_UNLOCK (demux);
4576 case GST_QUERY_POSITION:{
4579 gst_query_parse_position (query, &format, NULL);
4581 if (format != GST_FORMAT_TIME) {
4582 GST_LOG ("only support position queries in TIME format");
4586 GST_OBJECT_LOCK (demux);
4588 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4589 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4590 GST_TIME_ARGS (demux->segment.position));
4592 gst_query_set_position (query, GST_FORMAT_TIME,
4593 demux->segment.position);
4597 GST_LOG ("position not known yet");
4600 GST_OBJECT_UNLOCK (demux);
4604 case GST_QUERY_SEEKING:{
4607 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4608 if (format == GST_FORMAT_TIME) {
4611 GST_OBJECT_LOCK (demux);
4612 duration = demux->segment.duration;
4613 GST_OBJECT_UNLOCK (demux);
4615 if (!demux->streaming || !demux->seekable) {
4616 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4623 /* try upstream first in TIME */
4624 res = gst_pad_query_default (pad, parent, query);
4626 gst_query_parse_seeking (query, &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 no luck, maybe in BYTES */
4630 if (!seekable || fmt != GST_FORMAT_TIME) {
4633 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4634 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4635 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4636 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4637 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4638 if (fmt != GST_FORMAT_BYTES)
4641 gst_query_unref (q);
4642 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4648 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4652 case GST_QUERY_LATENCY:
4655 GstClockTime min, max;
4657 /* preroll delay does not matter in non-live pipeline,
4658 * but we might end up in a live (rtsp) one ... */
4661 res = gst_pad_query_default (pad, parent, query);
4665 gst_query_parse_latency (query, &live, &min, &max);
4667 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4668 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4669 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4671 GST_OBJECT_LOCK (demux);
4672 min += demux->latency;
4674 max += demux->latency;
4675 GST_OBJECT_UNLOCK (demux);
4677 gst_query_set_latency (query, live, min, max);
4680 case GST_QUERY_SEGMENT:
4685 format = demux->segment.format;
4688 gst_segment_to_stream_time (&demux->segment, format,
4689 demux->segment.start);
4690 if ((stop = demux->segment.stop) == -1)
4691 stop = demux->segment.duration;
4693 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4695 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4700 res = gst_pad_query_default (pad, parent, query);
4707 static GstStateChangeReturn
4708 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4710 GstASFDemux *demux = GST_ASF_DEMUX (element);
4711 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4713 switch (transition) {
4714 case GST_STATE_CHANGE_NULL_TO_READY:{
4715 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4716 demux->need_newsegment = TRUE;
4717 demux->segment_running = FALSE;
4718 demux->keyunit_sync = FALSE;
4719 demux->accurate = FALSE;
4720 demux->adapter = gst_adapter_new ();
4721 demux->metadata = gst_caps_new_empty ();
4722 demux->global_metadata = gst_structure_new_empty ("metadata");
4723 demux->data_size = 0;
4724 demux->data_offset = 0;
4725 demux->index_offset = 0;
4726 demux->base_offset = 0;
4727 demux->flowcombiner = gst_flow_combiner_new ();
4735 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4736 if (ret == GST_STATE_CHANGE_FAILURE)
4739 switch (transition) {
4740 case GST_STATE_CHANGE_PAUSED_TO_READY:
4741 gst_asf_demux_reset (demux, FALSE);
4744 case GST_STATE_CHANGE_READY_TO_NULL:
4745 gst_asf_demux_reset (demux, FALSE);
4746 gst_flow_combiner_free (demux->flowcombiner);
4747 demux->flowcombiner = NULL;