1 /* GStreamer ASF/WMV/WMA demuxer
2 * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) 2006-2009 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
24 * stop if at end of segment if != end of file, ie. demux->segment.stop
26 * - fix packet parsing:
27 * there's something wrong with timestamps for packets with keyframes,
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <gst/video/video.h>
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_STATIC_CAPS ("video/x-ms-asf")
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE (16+8)
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA 99
76 #define gst_asf_get_flow_name(flow) \
77 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
78 "need-more-data" : gst_flow_get_name (flow)
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83 GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89 GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95 guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98 GstObject * parent, GstPadMode mode, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
103 GstFlowReturn * pflow);
104 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109 AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
123 GstElementClass *gstelement_class;
125 gstelement_class = (GstElementClass *) klass;
127 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
129 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 gst_element_class_add_static_pad_template (gstelement_class,
132 &audio_src_template);
133 gst_element_class_add_static_pad_template (gstelement_class,
134 &video_src_template);
135 gst_element_class_add_static_pad_template (gstelement_class,
136 &gst_asf_demux_sink_template);
138 gstelement_class->change_state =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140 gstelement_class->send_event =
141 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147 gst_caps_replace (&stream->caps, NULL);
148 if (stream->pending_tags) {
149 gst_tag_list_unref (stream->pending_tags);
150 stream->pending_tags = NULL;
152 if (stream->streamheader) {
153 gst_buffer_unref (stream->streamheader);
154 stream->streamheader = NULL;
157 if (stream->active) {
158 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
161 gst_object_unref (stream->pad);
165 if (stream->payloads) {
166 while (stream->payloads->len > 0) {
170 last = stream->payloads->len - 1;
171 payload = &g_array_index (stream->payloads, AsfPayload, last);
172 gst_buffer_replace (&payload->buf, NULL);
173 g_array_remove_index (stream->payloads, last);
175 g_array_free (stream->payloads, TRUE);
176 stream->payloads = NULL;
179 if (stream->payloads_rev) {
180 while (stream->payloads_rev->len > 0) {
184 last = stream->payloads_rev->len - 1;
185 payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186 gst_buffer_replace (&payload->buf, NULL);
187 g_array_remove_index (stream->payloads_rev, last);
189 g_array_free (stream->payloads_rev, TRUE);
190 stream->payloads_rev = NULL;
193 if (stream->ext_props.valid) {
194 g_free (stream->ext_props.payload_extensions);
195 stream->ext_props.payload_extensions = NULL;
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
202 GST_LOG_OBJECT (demux, "resetting");
204 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205 demux->segment_running = FALSE;
206 if (demux->adapter && !chain_reset) {
207 gst_adapter_clear (demux->adapter);
208 g_object_unref (demux->adapter);
209 demux->adapter = NULL;
211 if (demux->taglist) {
212 gst_tag_list_unref (demux->taglist);
213 demux->taglist = NULL;
215 if (demux->metadata) {
216 gst_caps_unref (demux->metadata);
217 demux->metadata = NULL;
219 if (demux->global_metadata) {
220 gst_structure_free (demux->global_metadata);
221 demux->global_metadata = NULL;
223 if (demux->mut_ex_streams) {
224 g_slist_free (demux->mut_ex_streams);
225 demux->mut_ex_streams = NULL;
228 demux->state = GST_ASF_DEMUX_STATE_HEADER;
229 g_free (demux->objpath);
230 demux->objpath = NULL;
231 g_strfreev (demux->languages);
232 demux->languages = NULL;
233 demux->num_languages = 0;
234 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
236 g_slist_free (demux->ext_stream_props);
237 demux->ext_stream_props = NULL;
239 while (demux->old_num_streams > 0) {
240 gst_asf_demux_free_stream (demux,
241 &demux->old_stream[demux->old_num_streams - 1]);
242 --demux->old_num_streams;
244 memset (demux->old_stream, 0, sizeof (demux->old_stream));
245 demux->old_num_streams = 0;
247 /* when resetting for a new chained asf, we don't want to remove the pads
248 * before adding the new ones */
250 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251 demux->old_num_streams = demux->num_streams;
252 demux->num_streams = 0;
255 while (demux->num_streams > 0) {
256 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257 --demux->num_streams;
259 memset (demux->stream, 0, sizeof (demux->stream));
261 /* do not remove those for not adding pads with same name */
262 demux->num_audio_streams = 0;
263 demux->num_video_streams = 0;
264 demux->have_group_id = FALSE;
265 demux->group_id = G_MAXUINT;
267 demux->num_streams = 0;
268 demux->activated_streams = FALSE;
269 demux->first_ts = GST_CLOCK_TIME_NONE;
270 demux->segment_ts = GST_CLOCK_TIME_NONE;
273 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274 demux->state = GST_ASF_DEMUX_STATE_HEADER;
275 demux->seekable = FALSE;
276 demux->broadcast = FALSE;
277 demux->sidx_interval = 0;
278 demux->sidx_num_entries = 0;
279 g_free (demux->sidx_entries);
280 demux->sidx_entries = NULL;
282 demux->speed_packets = 1;
284 demux->asf_3D_mode = GST_ASF_3D_NONE;
287 GST_LOG_OBJECT (demux, "Restarting");
288 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289 demux->need_newsegment = TRUE;
290 demux->segment_seqnum = 0;
291 demux->segment_running = FALSE;
292 demux->keyunit_sync = FALSE;
293 demux->accurate = FALSE;
294 demux->metadata = gst_caps_new_empty ();
295 demux->global_metadata = gst_structure_new_empty ("metadata");
296 demux->data_size = 0;
297 demux->data_offset = 0;
298 demux->index_offset = 0;
300 demux->base_offset = 0;
303 g_slist_free (demux->other_streams);
304 demux->other_streams = NULL;
308 gst_asf_demux_init (GstASFDemux * demux)
311 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312 gst_pad_set_chain_function (demux->sinkpad,
313 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314 gst_pad_set_event_function (demux->sinkpad,
315 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316 gst_pad_set_activate_function (demux->sinkpad,
317 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318 gst_pad_set_activatemode_function (demux->sinkpad,
319 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
322 /* set initial state */
323 gst_asf_demux_reset (demux, FALSE);
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
332 query = gst_query_new_scheduling ();
334 if (!gst_pad_peer_query (sinkpad, query)) {
335 gst_query_unref (query);
339 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341 gst_query_unref (query);
346 GST_DEBUG_OBJECT (sinkpad, "activating pull");
347 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
351 GST_DEBUG_OBJECT (sinkpad, "activating push");
352 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358 GstPadMode mode, gboolean active)
363 demux = GST_ASF_DEMUX (parent);
366 case GST_PAD_MODE_PUSH:
367 demux->state = GST_ASF_DEMUX_STATE_HEADER;
368 demux->streaming = TRUE;
371 case GST_PAD_MODE_PULL:
373 demux->state = GST_ASF_DEMUX_STATE_HEADER;
374 demux->streaming = FALSE;
376 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
379 res = gst_pad_stop_task (sinkpad);
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
395 demux = GST_ASF_DEMUX (parent);
397 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398 switch (GST_EVENT_TYPE (event)) {
399 case GST_EVENT_SEGMENT:{
400 const GstSegment *segment;
402 gst_event_parse_segment (event, &segment);
404 if (segment->format == GST_FORMAT_BYTES) {
405 if (demux->packet_size && segment->start > demux->data_offset)
406 demux->packet = (segment->start - demux->data_offset) /
410 } else if (segment->format == GST_FORMAT_TIME) {
411 /* do not know packet position, not really a problem */
414 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415 gst_event_unref (event);
419 /* record upstream segment for interpolation */
420 if (segment->format != demux->in_segment.format)
421 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422 gst_segment_copy_into (segment, &demux->in_segment);
424 /* in either case, clear some state and generate newsegment later on */
425 GST_OBJECT_LOCK (demux);
426 demux->segment_ts = GST_CLOCK_TIME_NONE;
427 demux->in_gap = GST_CLOCK_TIME_NONE;
428 demux->need_newsegment = TRUE;
429 demux->segment_seqnum = gst_event_get_seqnum (event);
430 gst_asf_demux_reset_stream_state_after_discont (demux);
431 /* if we seek back after reaching EOS, go back to packet reading state */
432 if (demux->data_offset > 0 && segment->start >= demux->data_offset
433 && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
434 demux->state = GST_ASF_DEMUX_STATE_DATA;
436 GST_OBJECT_UNLOCK (demux);
438 gst_event_unref (event);
444 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
445 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
446 (_("This stream contains no data.")),
447 ("got eos and didn't receive a complete header object"));
450 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
451 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
452 GST_ELEMENT_FLOW_ERROR (demux, flow);
456 GST_OBJECT_LOCK (demux);
457 gst_adapter_clear (demux->adapter);
458 GST_OBJECT_UNLOCK (demux);
459 gst_asf_demux_send_event_unlocked (demux, event);
463 case GST_EVENT_FLUSH_STOP:
464 GST_OBJECT_LOCK (demux);
465 gst_asf_demux_reset_stream_state_after_discont (demux);
466 GST_OBJECT_UNLOCK (demux);
467 gst_asf_demux_send_event_unlocked (demux, event);
468 /* upon activation, latency is no longer introduced, e.g. after seek */
469 if (demux->activated_streams)
474 ret = gst_pad_event_default (pad, parent, event);
482 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
483 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
484 gboolean next, gboolean * eos)
486 GstClockTime idx_time;
492 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
495 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
498 /* if we want the next keyframe, we have to go forward till we find
499 a different packet number */
501 if (idx >= demux->sidx_num_entries - 1) {
502 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
507 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
508 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
515 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
521 *packet = demux->sidx_entries[idx].packet;
523 *speed = demux->sidx_entries[idx].count;
525 /* so we get closer to the actual time of the packet ... actually, let's not
526 * do this, since we throw away superfluous payloads before the seek position
527 * anyway; this way, our key unit seek 'snap resolution' is a bit better
528 * (ie. same as index resolution) */
530 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
534 idx_time = demux->sidx_interval * idx;
535 if (G_LIKELY (idx_time >= demux->preroll))
536 idx_time -= demux->preroll;
538 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
539 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
540 GST_TIME_ARGS (idx_time));
542 if (G_LIKELY (p_idx_time))
543 *p_idx_time = idx_time;
549 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
553 gst_adapter_clear (demux->adapter);
555 GST_DEBUG_OBJECT (demux, "reset stream state");
557 gst_flow_combiner_reset (demux->flowcombiner);
558 for (n = 0; n < demux->num_streams; n++) {
559 demux->stream[n].discont = TRUE;
560 demux->stream[n].first_buffer = TRUE;
562 while (demux->stream[n].payloads->len > 0) {
566 last = demux->stream[n].payloads->len - 1;
567 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
568 gst_buffer_replace (&payload->buf, NULL);
569 g_array_remove_index (demux->stream[n].payloads, last);
575 gst_asf_demux_mark_discont (GstASFDemux * demux)
579 GST_DEBUG_OBJECT (demux, "Mark stream discont");
581 for (n = 0; n < demux->num_streams; n++)
582 demux->stream[n].discont = TRUE;
585 /* do a seek in push based mode */
587 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
592 GstSeekType cur_type, stop_type;
596 GstEvent *byte_event;
598 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
601 stop_type = GST_SEEK_TYPE_NONE;
604 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
606 /* determine packet, by index or by estimation */
607 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
610 (guint) gst_util_uint64_scale (demux->num_packets, cur,
614 if (packet > demux->num_packets) {
615 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
620 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
622 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
624 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
625 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
626 /* BYTE seek event */
627 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
628 cur, stop_type, stop);
629 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
630 res = gst_pad_push_event (demux->sinkpad, byte_event);
636 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
638 GstClockTime idx_time;
641 GstSeekType cur_type, stop_type;
643 gboolean only_need_update;
644 gboolean after, before, next;
649 guint packet, speed_count = 1;
655 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
658 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
659 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
663 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
664 * so first try to let it handle the seek event. */
665 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
668 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
669 demux->num_packets == 0 || demux->play_time == 0)) {
670 GST_LOG_OBJECT (demux, "stream is not seekable");
674 if (G_UNLIKELY (!demux->activated_streams)) {
675 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
679 if (G_UNLIKELY (rate <= 0.0)) {
680 GST_LOG_OBJECT (demux, "backward playback");
681 demux->seek_to_cur_pos = TRUE;
682 for (i = 0; i < demux->num_streams; i++) {
683 demux->stream[i].reverse_kf_ready = FALSE;
687 seqnum = gst_event_get_seqnum (event);
688 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
690 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
691 demux->keyunit_sync =
692 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
693 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
694 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
695 next = after && !before;
697 if (G_UNLIKELY (demux->streaming)) {
698 /* support it safely needs more segment handling, e.g. closing etc */
700 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
703 /* we can (re)construct the start later on, but not the end */
704 if (stop_type != GST_SEEK_TYPE_NONE &&
705 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
706 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
709 return gst_asf_demux_handle_seek_push (demux, event);
712 /* unlock the streaming thread */
713 if (G_LIKELY (flush)) {
714 fevent = gst_event_new_flush_start ();
716 gst_event_set_seqnum (fevent, seqnum);
717 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
718 gst_asf_demux_send_event_unlocked (demux, fevent);
720 gst_pad_pause_task (demux->sinkpad);
723 /* grab the stream lock so that streaming cannot continue, for
724 * non flushing seeks when the element is in PAUSED this could block
726 GST_PAD_STREAM_LOCK (demux->sinkpad);
728 /* we now can stop flushing, since we have the stream lock now */
729 fevent = gst_event_new_flush_stop (TRUE);
730 gst_event_set_seqnum (fevent, seqnum);
731 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
733 if (G_LIKELY (flush))
734 gst_asf_demux_send_event_unlocked (demux, fevent);
736 gst_event_unref (fevent);
738 /* operating on copy of segment until we know the seek worked */
739 segment = demux->segment;
741 if (G_UNLIKELY (demux->segment_running && !flush)) {
742 GstSegment newsegment;
745 /* create the segment event to close the current segment */
746 gst_segment_copy_into (&segment, &newsegment);
747 newseg = gst_event_new_segment (&newsegment);
748 gst_event_set_seqnum (newseg, seqnum);
750 gst_asf_demux_send_event_unlocked (demux, newseg);
753 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
754 cur, stop_type, stop, &only_need_update);
756 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
757 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
759 if (cur_type != GST_SEEK_TYPE_SET)
760 seek_time = segment.start;
764 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
765 * real start of data and segment_start to indexed time for key unit seek*/
766 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
767 &idx_time, &speed_count, next, &eos))) {
771 demux->packet = demux->num_packets;
775 /* First try to query our source to see if it can convert for us. This is
776 the case when our source is an mms stream, notice that in this case
777 gstmms will do a time based seek to get the byte offset, this is not a
778 problem as the seek to this offset needs to happen anway. */
779 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
780 GST_FORMAT_BYTES, &offset)) {
781 packet = (offset - demux->data_offset) / demux->packet_size;
782 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
783 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
784 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
785 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
786 demux->packet_size, packet);
788 /* FIXME: For streams containing video, seek to an earlier position in
789 * the hope of hitting a keyframe and let the sinks throw away the stuff
790 * before the segment start. For audio-only this is unnecessary as every
792 if (flush && (demux->accurate || (demux->keyunit_sync && !next))
793 && demux->num_video_streams > 0) {
794 seek_time -= 5 * GST_SECOND;
799 packet = (guint) gst_util_uint64_scale (demux->num_packets,
800 seek_time, demux->play_time);
802 if (packet > demux->num_packets)
803 packet = demux->num_packets;
806 if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
807 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
808 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
809 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
810 segment.start = idx_time;
811 segment.position = idx_time;
812 segment.time = idx_time;
816 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
818 GST_OBJECT_LOCK (demux);
819 demux->segment = segment;
820 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
821 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
822 stop, demux->play_time);
824 demux->packet = packet;
827 demux->need_newsegment = TRUE;
828 demux->segment_seqnum = seqnum;
829 demux->speed_packets =
830 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
831 gst_asf_demux_reset_stream_state_after_discont (demux);
832 GST_OBJECT_UNLOCK (demux);
835 /* restart our task since it might have been stopped when we did the flush */
836 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
839 /* streaming can continue now */
840 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
846 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
852 demux = GST_ASF_DEMUX (parent);
854 switch (GST_EVENT_TYPE (event)) {
856 GST_LOG_OBJECT (pad, "seek event");
857 ret = gst_asf_demux_handle_seek_event (demux, event);
858 gst_event_unref (event);
861 case GST_EVENT_NAVIGATION:
862 /* just drop these two silently */
863 gst_event_unref (event);
867 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
868 ret = gst_pad_event_default (pad, parent, event);
875 static inline guint32
876 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
880 ret = gst_asf_identify_guid (guids, guid);
882 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
883 gst_asf_get_guid_nick (guids, ret),
884 guid->v1, guid->v2, guid->v3, guid->v4);
896 /* expect is true when the user is expeting an object,
897 * when false, it will give no warnings if the object
901 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
902 guint data_len, AsfObject * object, gboolean expect)
906 if (data_len < ASF_OBJECT_HEADER_SIZE)
909 guid.v1 = GST_READ_UINT32_LE (data + 0);
910 guid.v2 = GST_READ_UINT32_LE (data + 4);
911 guid.v3 = GST_READ_UINT32_LE (data + 8);
912 guid.v4 = GST_READ_UINT32_LE (data + 12);
914 object->size = GST_READ_UINT64_LE (data + 16);
916 /* FIXME: make asf_demux_identify_object_guid() */
917 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
918 if (object->id == ASF_OBJ_UNDEFINED && expect) {
919 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
920 guid.v1, guid.v2, guid.v3, guid.v4);
927 gst_asf_demux_release_old_pads (GstASFDemux * demux)
929 GST_DEBUG_OBJECT (demux, "Releasing old pads");
931 while (demux->old_num_streams > 0) {
932 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
933 gst_event_new_eos ());
934 gst_asf_demux_free_stream (demux,
935 &demux->old_stream[demux->old_num_streams - 1]);
936 --demux->old_num_streams;
938 memset (demux->old_stream, 0, sizeof (demux->old_stream));
939 demux->old_num_streams = 0;
943 gst_asf_demux_chain_headers (GstASFDemux * demux)
947 guint8 *header_data, *data = NULL;
948 const guint8 *cdata = NULL;
951 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
955 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
956 if (obj.id != ASF_OBJ_HEADER)
959 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
961 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
962 if (gst_adapter_available (demux->adapter) < obj.size + 50)
965 data = gst_adapter_take (demux->adapter, obj.size + 50);
968 header_size = obj.size;
969 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
970 if (flow != GST_FLOW_OK)
973 /* calculate where the packet data starts */
974 demux->data_offset = obj.size + 50;
976 /* now parse the beginning of the ASF_OBJ_DATA object */
977 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
980 if (demux->num_streams == 0)
989 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
996 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
997 ("This doesn't seem to be an ASF file"));
999 return GST_FLOW_ERROR;
1004 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1005 ("header parsing failed, or no streams found, flow = %s",
1006 gst_flow_get_name (flow)));
1008 return GST_FLOW_ERROR;
1013 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1014 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1019 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1022 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1024 if (G_LIKELY (p_flow))
1027 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1028 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1029 "+%u", gst_flow_get_name (flow), offset, size);
1034 g_assert (*p_buf != NULL);
1036 buffer_size = gst_buffer_get_size (*p_buf);
1037 if (G_UNLIKELY (buffer_size < size)) {
1038 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1039 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1040 gst_buffer_unref (*p_buf);
1041 if (G_LIKELY (p_flow))
1042 *p_flow = GST_FLOW_EOS;
1051 gst_asf_demux_pull_indices (GstASFDemux * demux)
1053 GstBuffer *buf = NULL;
1057 offset = demux->index_offset;
1059 if (G_UNLIKELY (offset == 0)) {
1060 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1064 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1070 gst_buffer_map (buf, &map, GST_MAP_READ);
1071 g_assert (map.size >= 16 + 8);
1072 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1073 gst_buffer_unmap (buf, &map);
1074 gst_buffer_replace (&buf, NULL);
1076 /* check for sanity */
1077 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1078 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1082 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1086 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1087 ", size %u", offset, (guint) obj.size);
1089 offset += obj.size; /* increase before _process_object changes it */
1091 gst_buffer_map (buf, &map, GST_MAP_READ);
1092 g_assert (map.size >= obj.size);
1093 bufdata = (guint8 *) map.data;
1094 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1095 gst_buffer_unmap (buf, &map);
1096 gst_buffer_replace (&buf, NULL);
1098 if (G_UNLIKELY (flow != GST_FLOW_OK))
1103 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1111 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1112 if (obj.id != ASF_OBJ_DATA) {
1113 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1117 demux->state = GST_ASF_DEMUX_STATE_DATA;
1119 if (!demux->broadcast && obj.size > 50) {
1120 demux->data_size = obj.size - 50;
1121 /* CHECKME: for at least one file this is off by +158 bytes?! */
1122 demux->index_offset = demux->data_offset + demux->data_size;
1124 demux->data_size = 0;
1125 demux->index_offset = 0;
1130 if (!demux->broadcast) {
1131 /* skip object header (24 bytes) and file GUID (16 bytes) */
1132 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1134 demux->num_packets = 0;
1137 if (demux->num_packets == 0)
1138 demux->seekable = FALSE;
1140 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1141 if (demux->data_size == 0 && demux->num_packets > 0) {
1142 demux->data_size = demux->num_packets * demux->packet_size;
1143 demux->index_offset = demux->data_offset + demux->data_size;
1146 /* process pending stream objects and create pads for those */
1147 gst_asf_demux_process_queued_extended_stream_objects (demux);
1149 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1150 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1151 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1152 demux->data_offset, demux->data_size, demux->index_offset);
1158 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1160 GstFlowReturn flow = GST_FLOW_OK;
1162 GstBuffer *buf = NULL;
1167 GST_LOG_OBJECT (demux, "reading headers");
1169 /* pull HEADER object header, so we know its size */
1170 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1173 gst_buffer_map (buf, &map, GST_MAP_READ);
1174 g_assert (map.size >= 16 + 8);
1175 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1176 gst_buffer_unmap (buf, &map);
1177 gst_buffer_replace (&buf, NULL);
1179 if (obj.id != ASF_OBJ_HEADER)
1182 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1184 /* pull HEADER object */
1185 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1189 size = obj.size; /* don't want obj.size changed */
1190 gst_buffer_map (buf, &map, GST_MAP_READ);
1191 g_assert (map.size >= size);
1192 bufdata = (guint8 *) map.data;
1193 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1194 gst_buffer_unmap (buf, &map);
1195 gst_buffer_replace (&buf, NULL);
1197 if (flow != GST_FLOW_OK) {
1198 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1202 /* calculate where the packet data starts */
1203 demux->data_offset = demux->base_offset + obj.size + 50;
1205 /* now pull beginning of DATA object before packet data */
1206 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1210 gst_buffer_map (buf, &map, GST_MAP_READ);
1211 g_assert (map.size >= size);
1212 bufdata = (guint8 *) map.data;
1213 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1216 if (demux->num_streams == 0)
1219 gst_buffer_unmap (buf, &map);
1220 gst_buffer_replace (&buf, NULL);
1228 gst_buffer_unmap (buf, &map);
1229 gst_buffer_replace (&buf, NULL);
1231 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1232 ("This doesn't seem to be an ASF file"));
1233 *pflow = GST_FLOW_ERROR;
1238 flow = GST_FLOW_ERROR;
1239 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1240 ("header parsing failed, or no streams found, flow = %s",
1241 gst_flow_get_name (flow)));
1246 gst_buffer_unmap (buf, &map);
1247 gst_buffer_replace (&buf, NULL);
1254 all_streams_prerolled (GstASFDemux * demux)
1256 GstClockTime preroll_time;
1257 guint i, num_no_data = 0;
1259 /* Allow at least 500ms of preroll_time */
1260 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1262 /* returns TRUE as long as there isn't a stream which (a) has data queued
1263 * and (b) the timestamp of last piece of data queued is < demux->preroll
1264 * AND there is at least one other stream with data queued */
1265 for (i = 0; i < demux->num_streams; ++i) {
1266 AsfPayload *last_payload = NULL;
1270 stream = &demux->stream[i];
1271 if (G_UNLIKELY (stream->payloads->len == 0)) {
1273 GST_LOG_OBJECT (stream->pad, "no data queued");
1277 /* find last payload with timestamp */
1278 for (last_idx = stream->payloads->len - 1;
1279 last_idx >= 0 && (last_payload == NULL
1280 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1281 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1284 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1285 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1286 GST_TIME_ARGS (preroll_time));
1287 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1288 || last_payload->ts <= preroll_time)) {
1289 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1294 if (G_UNLIKELY (num_no_data > 0))
1302 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1307 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1310 /* check for each mutual exclusion group whether it affects this stream */
1311 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1312 if (*mes == stream->id) {
1313 /* we are in this group; let's check if we've already activated streams
1314 * that are in the same group (and hence mutually exclusive to this
1316 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1319 for (i = 0; i < demux->num_streams; ++i) {
1320 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1321 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1322 "to already active stream with ID %d", stream->id,
1323 demux->stream[i].id);
1328 /* we can only be in this group once, let's break out and move on to
1329 * the next mutual exclusion group */
1340 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1342 /* remember the first queued timestamp for the segment */
1343 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1344 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1345 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1346 GST_TIME_ARGS (demux->first_ts));
1347 demux->segment_ts = payload_ts;
1348 /* always note, but only determines segment when streaming */
1349 if (demux->streaming)
1350 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1351 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1352 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1357 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1359 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1360 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1363 /* go trhough each stream, find smallest timestamp */
1364 for (i = 0; i < demux->num_streams; ++i) {
1367 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1368 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1369 stream = &demux->stream[i];
1371 for (j = 0; j < stream->payloads->len; ++j) {
1372 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1373 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1374 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1375 || stream_min_ts > payload->ts)) {
1376 stream_min_ts = payload->ts;
1378 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1379 payload->ts > stream_min_ts &&
1380 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1381 || stream_min_ts2 > payload->ts)) {
1382 stream_min_ts2 = payload->ts;
1386 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1387 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1388 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1389 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1390 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1392 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1395 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1396 stream_min_ts = stream_min_ts2;
1398 /* if we don't have timestamp for this stream, wait for more data */
1399 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1402 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1403 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1404 first_ts = stream_min_ts;
1407 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1410 demux->first_ts = first_ts;
1412 /* update packets queued before we knew first timestamp */
1413 for (i = 0; i < demux->num_streams; ++i) {
1416 stream = &demux->stream[i];
1418 for (j = 0; j < stream->payloads->len; ++j) {
1419 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1420 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1421 if (payload->ts > first_ts)
1422 payload->ts -= first_ts;
1430 gst_asf_demux_check_segment_ts (demux, 0);
1436 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1438 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1439 and often set wrong, inspecting the data is the only way that seem to be working */
1440 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1441 GstCaps *caps = NULL;
1443 GstAdapter *adapter = gst_adapter_new ();
1445 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1447 AsfPayload *payload;
1450 payload = &g_array_index (stream->payloads, AsfPayload, i);
1451 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1452 len = gst_adapter_available (adapter);
1453 data = gst_adapter_map (adapter, len);
1457 #define MIN_LENGTH 128
1459 /* look for the sync points */
1461 if (len < MIN_LENGTH || /* give typefind something to work on */
1462 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1463 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1469 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1472 if (prob < GST_TYPE_FIND_LIKELY) {
1475 if (len > MIN_LENGTH)
1476 /* this wasn't it, look for another sync point */
1480 gst_adapter_unmap (adapter);
1483 gst_object_unref (adapter);
1486 gst_caps_take (&stream->caps, caps);
1494 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1498 if (demux->activated_streams)
1501 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1504 if (!all_streams_prerolled (demux) && !force) {
1505 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1509 for (i = 0; i < demux->num_streams; ++i) {
1510 AsfStream *stream = &demux->stream[i];
1512 if (stream->payloads->len > 0) {
1514 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1515 !stream->active && /* do not inspect active streams (caps were already set) */
1516 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1517 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1518 /* try to gather some more data */
1521 /* we don't check mutual exclusion stuff here; either we have data for
1522 * a stream, then we active it, or we don't, then we'll ignore it */
1523 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1524 gst_asf_demux_activate_stream (demux, stream);
1526 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1530 gst_asf_demux_release_old_pads (demux);
1532 demux->activated_streams = TRUE;
1533 GST_LOG_OBJECT (demux, "signalling no more pads");
1534 gst_element_no_more_pads (GST_ELEMENT (demux));
1538 /* returns the stream that has a complete payload with the lowest timestamp
1539 * queued, or NULL (we push things by timestamp because during the internal
1540 * prerolling we might accumulate more data then the external queues can take,
1541 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1543 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1545 AsfPayload *best_payload = NULL;
1546 AsfStream *best_stream = NULL;
1549 for (i = 0; i < demux->num_streams; ++i) {
1553 stream = &demux->stream[i];
1555 /* Don't push any data until we have at least one payload that falls within
1556 * the current segment. This way we can remove out-of-segment payloads that
1557 * don't need to be decoded after a seek, sending only data from the
1558 * keyframe directly before our segment start */
1559 if (stream->payloads->len > 0) {
1560 AsfPayload *payload = NULL;
1563 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1564 /* Reverse playback */
1566 if (stream->is_video) {
1567 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1568 if (stream->reverse_kf_ready) {
1570 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1571 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1572 /* TODO : remove payload from the list? */
1579 /* find first complete payload with timestamp */
1580 for (j = stream->payloads->len - 1;
1581 j >= 0 && (payload == NULL
1582 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1583 payload = &g_array_index (stream->payloads, AsfPayload, j);
1586 /* If there's a complete payload queued for this stream */
1587 if (!gst_asf_payload_is_complete (payload))
1593 /* find last payload with timestamp */
1594 for (last_idx = stream->payloads->len - 1;
1595 last_idx >= 0 && (payload == NULL
1596 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1597 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1600 /* if this is first payload after seek we might need to update the segment */
1601 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1602 gst_asf_demux_check_segment_ts (demux, payload->ts);
1604 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1605 (payload->ts < demux->segment.start))) {
1606 if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1607 && payload->keyframe)) {
1608 GST_DEBUG_OBJECT (stream->pad,
1609 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1610 GST_TIME_ARGS (payload->ts));
1611 demux->segment.start = payload->ts;
1612 demux->segment.time = payload->ts;
1614 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1615 GST_TIME_FORMAT " which is before our segment start %"
1616 GST_TIME_FORMAT ", not pushing yet",
1617 GST_TIME_ARGS (payload->ts),
1618 GST_TIME_ARGS (demux->segment.start));
1623 /* find first complete payload with timestamp */
1625 j < stream->payloads->len && (payload == NULL
1626 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1627 payload = &g_array_index (stream->payloads, AsfPayload, j);
1630 /* Now see if there's a complete payload queued for this stream */
1631 if (!gst_asf_payload_is_complete (payload))
1635 /* ... and whether its timestamp is lower than the current best */
1636 if (best_stream == NULL || best_payload->ts > payload->ts) {
1637 best_stream = stream;
1638 best_payload = payload;
1646 static GstFlowReturn
1647 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1650 GstFlowReturn ret = GST_FLOW_OK;
1652 if (G_UNLIKELY (!demux->activated_streams)) {
1653 if (!gst_asf_demux_check_activate_streams (demux, force))
1655 /* streams are now activated */
1658 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1659 AsfPayload *payload;
1660 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1661 GstClockTime duration = GST_CLOCK_TIME_NONE;
1663 /* wait until we had a chance to "lock on" some payload's timestamp */
1664 if (G_UNLIKELY (demux->need_newsegment
1665 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1668 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1669 && stream->payloads->len) {
1670 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1672 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1675 /* do we need to send a newsegment event */
1676 if ((G_UNLIKELY (demux->need_newsegment))) {
1677 GstEvent *segment_event;
1679 /* safe default if insufficient upstream info */
1680 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1683 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1684 demux->segment.duration > 0) {
1685 /* slight HACK; prevent clipping of last bit */
1686 demux->segment.stop = demux->segment.duration + demux->in_gap;
1689 /* FIXME : only if ACCURATE ! */
1690 if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1691 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1692 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1693 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1694 GST_TIME_ARGS (payload->ts));
1695 demux->segment.start = payload->ts;
1696 demux->segment.time = payload->ts;
1699 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1702 /* note: we fix up all timestamps to start from 0, so this should be ok */
1703 segment_event = gst_event_new_segment (&demux->segment);
1704 if (demux->segment_seqnum)
1705 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1706 gst_asf_demux_send_event_unlocked (demux, segment_event);
1708 /* now post any global tags we may have found */
1709 if (demux->taglist == NULL) {
1710 demux->taglist = gst_tag_list_new_empty ();
1711 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1714 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1715 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1717 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1718 gst_asf_demux_send_event_unlocked (demux,
1719 gst_event_new_tag (demux->taglist));
1720 demux->taglist = NULL;
1722 demux->need_newsegment = FALSE;
1723 demux->segment_seqnum = 0;
1724 demux->segment_running = TRUE;
1727 /* Do we have tags pending for this stream? */
1728 if (G_UNLIKELY (stream->pending_tags)) {
1729 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1730 gst_pad_push_event (stream->pad,
1731 gst_event_new_tag (stream->pending_tags));
1732 stream->pending_tags = NULL;
1735 /* We have the whole packet now so we should push the packet to
1736 * the src pad now. First though we should check if we need to do
1738 if (G_UNLIKELY (stream->span > 1)) {
1739 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1742 payload->buf = gst_buffer_make_writable (payload->buf);
1744 if (G_LIKELY (!payload->keyframe)) {
1745 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1748 if (G_UNLIKELY (stream->discont)) {
1749 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1750 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1751 stream->discont = FALSE;
1754 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1755 (payload->par_x != stream->par_x) &&
1756 (payload->par_y != stream->par_y))) {
1757 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1758 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1759 stream->par_x = payload->par_x;
1760 stream->par_y = payload->par_y;
1761 stream->caps = gst_caps_make_writable (stream->caps);
1762 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1763 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1764 gst_pad_set_caps (stream->pad, stream->caps);
1767 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1768 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1769 payload->interlaced);
1770 stream->interlaced = payload->interlaced;
1771 stream->caps = gst_caps_make_writable (stream->caps);
1772 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1773 (stream->interlaced ? "mixed" : "progressive"), NULL);
1774 gst_pad_set_caps (stream->pad, stream->caps);
1777 /* (sort of) interpolate timestamps using upstream "frame of reference",
1778 * typically useful for live src, but might (unavoidably) mess with
1779 * position reporting if a live src is playing not so live content
1780 * (e.g. rtspsrc taking some time to fall back to tcp) */
1781 timestamp = payload->ts;
1782 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1783 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1784 timestamp += demux->in_gap;
1786 /* Check if we're after the segment already, if so no need to push
1788 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1789 GST_DEBUG_OBJECT (stream->pad,
1790 "Payload after segment stop %" GST_TIME_FORMAT,
1791 GST_TIME_ARGS (demux->segment.stop));
1793 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1795 gst_buffer_unref (payload->buf);
1796 payload->buf = NULL;
1797 g_array_remove_index (stream->payloads, 0);
1798 /* Break out as soon as we have an issue */
1799 if (G_UNLIKELY (ret != GST_FLOW_OK))
1806 GST_BUFFER_PTS (payload->buf) = timestamp;
1808 if (payload->duration == GST_CLOCK_TIME_NONE
1809 && stream->ext_props.avg_time_per_frame != 0) {
1810 duration = stream->ext_props.avg_time_per_frame * 100;
1812 duration = payload->duration;
1814 GST_BUFFER_DURATION (payload->buf) = duration;
1816 /* FIXME: we should really set durations on buffers if we can */
1818 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1821 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1822 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1823 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1825 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1826 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1830 if (stream->active) {
1831 if (G_UNLIKELY (stream->first_buffer)) {
1832 if (stream->streamheader != NULL) {
1833 GST_DEBUG_OBJECT (stream->pad,
1834 "Pushing streamheader before first buffer");
1835 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1837 stream->first_buffer = FALSE;
1840 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1841 && timestamp > demux->segment.position) {
1842 demux->segment.position = timestamp;
1843 if (GST_CLOCK_TIME_IS_VALID (duration))
1844 demux->segment.position += timestamp;
1847 ret = gst_pad_push (stream->pad, payload->buf);
1849 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1852 gst_buffer_unref (payload->buf);
1855 payload->buf = NULL;
1856 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1857 && stream->reverse_kf_ready) {
1858 g_array_remove_index (stream->payloads, stream->kf_pos);
1861 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1863 stream->reverse_kf_ready = FALSE;
1866 g_array_remove_index (stream->payloads, 0);
1869 /* Break out as soon as we have an issue */
1870 if (G_UNLIKELY (ret != GST_FLOW_OK))
1878 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1882 g_assert (buf != NULL);
1884 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1886 gst_buffer_map (buf, &map, GST_MAP_READ);
1888 /* we return false on buffer too small */
1889 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1890 gst_buffer_unmap (buf, &map);
1894 /* check if it is a header */
1895 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1896 gst_buffer_unmap (buf, &map);
1897 if (obj.id == ASF_OBJ_HEADER) {
1904 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1906 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1907 GstFlowReturn ret = GST_FLOW_OK;
1908 GstBuffer *buf = NULL;
1909 gboolean header = FALSE;
1911 /* TODO maybe we should skip index objects after the data and look
1912 * further for a new header */
1913 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1914 g_assert (buf != NULL);
1915 /* check if it is a header */
1916 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1917 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1918 demux->base_offset = off;
1922 gst_buffer_unref (buf);
1929 gst_asf_demux_loop (GstASFDemux * demux)
1931 GstFlowReturn flow = GST_FLOW_OK;
1932 GstBuffer *buf = NULL;
1935 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1936 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1940 gst_asf_demux_pull_indices (demux);
1943 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1945 if (G_UNLIKELY (demux->num_packets != 0
1946 && demux->packet >= demux->num_packets))
1949 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1950 (guint) demux->num_packets);
1952 off = demux->data_offset + (demux->packet * demux->packet_size);
1954 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1955 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1956 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1957 if (flow == GST_FLOW_EOS) {
1959 } else if (flow == GST_FLOW_FLUSHING) {
1960 GST_DEBUG_OBJECT (demux, "Not fatal");
1967 if (G_LIKELY (demux->speed_packets == 1)) {
1968 GstAsfDemuxParsePacketError err;
1969 err = gst_asf_demux_parse_packet (demux, buf);
1970 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1971 /* when we don't know when the data object ends, we should check
1972 * for a chained asf */
1973 if (demux->num_packets == 0) {
1974 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1975 GST_INFO_OBJECT (demux, "Chained asf found");
1976 demux->base_offset = off;
1977 gst_asf_demux_reset (demux, TRUE);
1978 gst_buffer_unref (buf);
1982 /* FIXME: We should tally up fatal errors and error out only
1983 * after a few broken packets in a row? */
1985 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1986 gst_buffer_unref (buf);
1988 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
1989 && !demux->seek_to_cur_pos) {
1991 if (demux->packet < 0) {
2001 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2003 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2004 && !demux->seek_to_cur_pos) {
2006 if (demux->packet < 0) {
2015 for (n = 0; n < demux->speed_packets; n++) {
2017 GstAsfDemuxParsePacketError err;
2020 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2021 n * demux->packet_size, demux->packet_size);
2022 err = gst_asf_demux_parse_packet (demux, sub);
2023 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2024 /* when we don't know when the data object ends, we should check
2025 * for a chained asf */
2026 if (demux->num_packets == 0) {
2027 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2028 GST_INFO_OBJECT (demux, "Chained asf found");
2029 demux->base_offset = off + n * demux->packet_size;
2030 gst_asf_demux_reset (demux, TRUE);
2031 gst_buffer_unref (sub);
2032 gst_buffer_unref (buf);
2036 /* FIXME: We should tally up fatal errors and error out only
2037 * after a few broken packets in a row? */
2039 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2043 gst_buffer_unref (sub);
2045 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2046 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2052 /* reset speed pull */
2053 demux->speed_packets = 1;
2056 gst_buffer_unref (buf);
2058 if (G_UNLIKELY ((demux->num_packets > 0
2059 && demux->packet >= demux->num_packets)
2060 || flow == GST_FLOW_EOS)) {
2061 GST_LOG_OBJECT (demux, "reached EOS");
2065 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2066 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2070 /* check if we're at the end of the configured segment */
2071 /* FIXME: check if segment end reached etc. */
2077 /* if we haven't activated our streams yet, this might be because we have
2078 * less data queued than required for preroll; force stream activation and
2079 * send any pending payloads before sending EOS */
2080 if (!demux->activated_streams)
2081 gst_asf_demux_push_complete_payloads (demux, TRUE);
2083 /* we want to push an eos or post a segment-done in any case */
2084 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2087 /* for segment playback we need to post when (in stream time)
2088 * we stopped, this is either stop (when set) or the duration. */
2089 if ((stop = demux->segment.stop) == -1)
2090 stop = demux->segment.duration;
2092 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2093 gst_element_post_message (GST_ELEMENT_CAST (demux),
2094 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2096 gst_asf_demux_send_event_unlocked (demux,
2097 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2098 } else if (flow != GST_FLOW_EOS) {
2099 /* check if we have a chained asf, in case, we don't eos yet */
2100 if (gst_asf_demux_check_chained_asf (demux)) {
2101 GST_INFO_OBJECT (demux, "Chained ASF starting");
2102 gst_asf_demux_reset (demux, TRUE);
2107 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2108 /* normal playback, send EOS to all linked pads */
2109 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2110 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2112 /* ... and fall through to pause */
2116 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2117 gst_flow_get_name (flow));
2118 demux->segment_running = FALSE;
2119 gst_pad_pause_task (demux->sinkpad);
2121 /* For the error cases */
2122 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2123 /* Post an error. Hopefully something else already has, but if not... */
2124 GST_ELEMENT_FLOW_ERROR (demux, flow);
2125 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2134 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2135 flow = GST_FLOW_EOS;
2139 /* See FIXMEs above */
2142 gst_buffer_unref (buf);
2143 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2144 ("Error parsing ASF packet %u", (guint) demux->packet));
2145 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2146 flow = GST_FLOW_ERROR;
2152 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2153 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2154 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2157 gst_asf_demux_check_header (GstASFDemux * demux)
2160 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2161 ASF_OBJECT_HEADER_SIZE);
2162 if (cdata == NULL) /* need more data */
2163 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2165 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2166 if (obj.id != ASF_OBJ_HEADER) {
2167 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2169 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2173 static GstFlowReturn
2174 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2176 GstFlowReturn ret = GST_FLOW_OK;
2179 demux = GST_ASF_DEMUX (parent);
2181 GST_LOG_OBJECT (demux,
2182 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2183 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2184 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2186 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2187 GST_DEBUG_OBJECT (demux, "received DISCONT");
2188 gst_asf_demux_mark_discont (demux);
2191 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2192 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2193 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2194 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2195 ", interpolation gap: %" GST_TIME_FORMAT,
2196 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2199 gst_adapter_push (demux->adapter, buf);
2201 switch (demux->state) {
2202 case GST_ASF_DEMUX_STATE_INDEX:{
2203 gint result = gst_asf_demux_check_header (demux);
2204 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2207 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2208 /* we don't care about this, probably an index */
2209 /* TODO maybe would be smarter to skip all the indices
2210 * until we got a new header or EOS to decide */
2211 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2214 GST_INFO_OBJECT (demux, "Chained asf starting");
2215 /* cleanup and get ready for a chained asf */
2216 gst_asf_demux_reset (demux, TRUE);
2220 case GST_ASF_DEMUX_STATE_HEADER:{
2221 ret = gst_asf_demux_chain_headers (demux);
2222 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2224 /* otherwise fall through */
2226 case GST_ASF_DEMUX_STATE_DATA:
2230 data_size = demux->packet_size;
2232 while (gst_adapter_available (demux->adapter) >= data_size) {
2234 GstAsfDemuxParsePacketError err;
2236 /* we don't know the length of the stream
2237 * check for a chained asf everytime */
2238 if (demux->num_packets == 0) {
2239 gint result = gst_asf_demux_check_header (demux);
2241 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2242 GST_INFO_OBJECT (demux, "Chained asf starting");
2243 /* cleanup and get ready for a chained asf */
2244 gst_asf_demux_reset (demux, TRUE);
2247 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2248 && demux->packet >= demux->num_packets)) {
2249 /* do not overshoot data section when streaming */
2253 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2255 /* FIXME: We should tally up fatal errors and error out only
2256 * after a few broken packets in a row? */
2257 err = gst_asf_demux_parse_packet (demux, buf);
2259 gst_buffer_unref (buf);
2261 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2262 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2264 GST_WARNING_OBJECT (demux, "Parse error");
2266 if (demux->packet >= 0)
2269 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2270 && demux->packet >= demux->num_packets)) {
2271 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2276 g_assert_not_reached ();
2280 if (ret != GST_FLOW_OK)
2281 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2287 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2293 static inline gboolean
2294 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2296 if (*p_size < num_bytes)
2299 *p_data += num_bytes;
2300 *p_size -= num_bytes;
2304 static inline guint8
2305 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2309 g_assert (*p_size >= 1);
2310 ret = GST_READ_UINT8 (*p_data);
2311 *p_data += sizeof (guint8);
2312 *p_size -= sizeof (guint8);
2316 static inline guint16
2317 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2321 g_assert (*p_size >= 2);
2322 ret = GST_READ_UINT16_LE (*p_data);
2323 *p_data += sizeof (guint16);
2324 *p_size -= sizeof (guint16);
2328 static inline guint32
2329 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2333 g_assert (*p_size >= 4);
2334 ret = GST_READ_UINT32_LE (*p_data);
2335 *p_data += sizeof (guint32);
2336 *p_size -= sizeof (guint32);
2340 static inline guint64
2341 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2345 g_assert (*p_size >= 8);
2346 ret = GST_READ_UINT64_LE (*p_data);
2347 *p_data += sizeof (guint64);
2348 *p_size -= sizeof (guint64);
2353 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2354 guint8 ** p_data, guint64 * p_size)
2358 if (*p_size < num_bytes_to_read)
2361 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2362 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2364 *p_data += num_bytes_to_read;
2365 *p_size -= num_bytes_to_read;
2371 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2372 guint8 ** p_data, guint64 * p_size)
2376 if (*p_size < num_bytes_to_read)
2379 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2380 *p_data += num_bytes_to_read;
2381 *p_size -= num_bytes_to_read;
2386 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2387 guint8 ** p_data, guint64 * p_size)
2397 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2400 *p_strlen = s_length;
2402 if (s_length == 0) {
2403 GST_WARNING ("zero-length string");
2404 *p_str = g_strdup ("");
2408 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2411 g_assert (s != NULL);
2413 /* just because They don't exist doesn't
2414 * mean They are not out to get you ... */
2415 if (s[s_length - 1] != '\0') {
2416 s = g_realloc (s, s_length + 1);
2420 *p_str = (gchar *) s;
2426 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2428 g_assert (*p_size >= 4 * sizeof (guint32));
2430 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2431 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2432 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2433 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2437 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2440 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2443 /* WAVEFORMATEX Structure */
2444 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2445 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2446 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2447 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2448 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2449 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2450 /* Codec specific data size */
2451 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2456 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2459 if (*p_size < (4 + 4 + 1 + 2))
2462 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2463 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2464 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2465 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2470 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2471 guint8 ** p_data, guint64 * p_size)
2473 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2476 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2477 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2478 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2479 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2480 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2481 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2482 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2483 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2484 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2485 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2486 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2491 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2495 for (i = 0; i < demux->num_streams; i++) {
2496 if (demux->stream[i].id == id)
2497 return &demux->stream[i];
2500 if (gst_asf_demux_is_unknown_stream (demux, id))
2501 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2506 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2507 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2512 gst_pad_use_fixed_caps (src_pad);
2513 gst_pad_set_caps (src_pad, caps);
2515 gst_pad_set_event_function (src_pad,
2516 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2517 gst_pad_set_query_function (src_pad,
2518 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2520 stream = &demux->stream[demux->num_streams];
2521 stream->caps = caps;
2522 stream->pad = src_pad;
2524 stream->fps_known = !is_video; /* bit hacky for audio */
2525 stream->is_video = is_video;
2526 stream->pending_tags = tags;
2527 stream->discont = TRUE;
2528 stream->first_buffer = TRUE;
2529 stream->streamheader = streamheader;
2530 if (stream->streamheader) {
2531 stream->streamheader = gst_buffer_make_writable (streamheader);
2532 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2537 st = gst_caps_get_structure (caps, 0);
2538 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2539 par_x > 0 && par_y > 0) {
2540 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2541 stream->par_x = par_x;
2542 stream->par_y = par_y;
2546 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2548 /* TODO: create this array during reverse play? */
2549 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2551 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2552 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2554 ++demux->num_streams;
2556 stream->active = FALSE;
2562 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2563 GstBuffer * buffer, GstStructure * structure)
2565 GValue arr_val = G_VALUE_INIT;
2566 GValue buf_val = G_VALUE_INIT;
2568 g_value_init (&arr_val, GST_TYPE_ARRAY);
2569 g_value_init (&buf_val, GST_TYPE_BUFFER);
2571 gst_value_set_buffer (&buf_val, buffer);
2572 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2574 gst_structure_take_value (structure, "streamheader", &arr_val);
2578 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2579 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2581 GstTagList *tags = NULL;
2582 GstBuffer *extradata = NULL;
2585 guint16 size_left = 0;
2586 gchar *codec_name = NULL;
2589 size_left = audio->size;
2591 /* Create the audio pad */
2592 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2594 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2597 /* Swallow up any left over data and set up the
2598 * standard properties from the header info */
2600 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2601 "codec specific data", size_left);
2603 g_assert (size_left <= *p_size);
2604 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2607 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2608 * additional two bytes indicating extradata. */
2609 /* FIXME: Handle the channel reorder map here */
2610 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2611 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2614 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2615 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2618 /* Informing about that audio format we just added */
2620 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2621 g_free (codec_name);
2624 if (audio->byte_rate > 0) {
2625 /* Some ASF files have no bitrate props object (often seen with
2626 * ASF files that contain raw audio data). Example files can
2627 * be generated with FFmpeg (tested with v2.8.6), like this:
2629 * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
2631 * In this case, if audio->byte_rate is nonzero, use that as
2634 guint bitrate = audio->byte_rate * 8;
2637 tags = gst_tag_list_new_empty ();
2639 /* Add bitrate, but only if there is none set already, since
2640 * this is just a fallback in case there is no bitrate tag
2641 * already present */
2642 gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
2646 gst_buffer_unref (extradata);
2648 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2649 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2650 audio->codec_tag, tags);
2652 ++demux->num_audio_streams;
2654 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2658 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2659 asf_stream_video_format * video, guint16 id,
2660 guint8 ** p_data, guint64 * p_size)
2662 GstTagList *tags = NULL;
2663 GstStructure *caps_s;
2664 GstBuffer *extradata = NULL;
2669 gchar *codec_name = NULL;
2670 gint size_left = video->size - 40;
2671 GstBuffer *streamheader = NULL;
2672 guint par_w = 1, par_h = 1;
2674 /* Create the video pad */
2675 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2676 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2679 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2681 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2682 g_assert (size_left <= *p_size);
2683 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2686 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2688 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2689 caps = gst_riff_create_video_caps (video->tag, NULL,
2690 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2693 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2694 G_TYPE_UINT, video->tag, NULL);
2699 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2700 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2701 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2704 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2708 /* retry with the global metadata */
2709 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2710 demux->global_metadata);
2711 s = demux->global_metadata;
2712 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2713 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2714 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2715 if (ax > 0 && ay > 0) {
2718 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2723 s = gst_caps_get_structure (caps, 0);
2724 gst_structure_remove_field (s, "framerate");
2727 caps_s = gst_caps_get_structure (caps, 0);
2729 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2730 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2731 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2732 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2735 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2736 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2737 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2739 GstBuffer *buf = gst_value_get_buffer (value);
2742 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2743 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2744 /* this looks like a bytestream start */
2745 streamheader = gst_buffer_ref (buf);
2746 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2747 gst_structure_remove_field (caps_s, "codec_data");
2750 gst_buffer_unmap (buf, &mapinfo);
2755 /* For a 3D video, set multiview information into the caps based on
2756 * what was detected during object parsing */
2757 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2758 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2759 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2760 const gchar *mview_mode_str;
2762 switch (demux->asf_3D_mode) {
2763 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2764 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2766 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2767 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2768 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2770 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2771 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2773 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2774 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2775 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2777 case GST_ASF_3D_DUAL_STREAM:{
2778 gboolean is_right_view = FALSE;
2779 /* if Advanced_Mutual_Exclusion object exists, use it
2780 * to figure out which is the left view (lower ID) */
2781 if (demux->mut_ex_streams != NULL) {
2785 length = g_slist_length (demux->mut_ex_streams);
2787 for (i = 0; i < length; i++) {
2790 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2792 GST_DEBUG_OBJECT (demux,
2793 "has Mutual_Exclusion object. stream id in object is %d",
2794 GPOINTER_TO_INT (v_s_id));
2796 if (id > GPOINTER_TO_INT (v_s_id))
2797 is_right_view = TRUE;
2800 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2801 * first video stream encountered has the lower ID */
2802 if (demux->num_video_streams > 0) {
2803 /* This is not the first video stream, assuming right eye view */
2804 is_right_view = TRUE;
2808 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2810 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2817 GST_INFO_OBJECT (demux,
2818 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2821 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2822 if (mview_mode_str != NULL) {
2823 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2824 video->height, par_w, par_h))
2825 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2827 gst_caps_set_simple (caps,
2828 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2829 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2830 GST_FLAG_SET_MASK_EXACT, NULL);
2835 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2836 g_free (codec_name);
2840 gst_buffer_unref (extradata);
2842 GST_INFO ("Adding video stream #%u, id %u, codec %"
2843 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2844 GST_FOURCC_ARGS (video->tag), video->tag);
2846 ++demux->num_video_streams;
2848 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2849 streamheader, tags);
2853 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2855 if (!stream->active) {
2859 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2860 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2861 gst_pad_set_active (stream->pad, TRUE);
2864 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2865 "%03u", stream->id);
2868 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2870 if (gst_event_parse_group_id (event, &demux->group_id))
2871 demux->have_group_id = TRUE;
2873 demux->have_group_id = FALSE;
2874 gst_event_unref (event);
2875 } else if (!demux->have_group_id) {
2876 demux->have_group_id = TRUE;
2877 demux->group_id = gst_util_group_id_next ();
2880 event = gst_event_new_stream_start (stream_id);
2881 if (demux->have_group_id)
2882 gst_event_set_group_id (event, demux->group_id);
2884 gst_pad_push_event (stream->pad, event);
2886 gst_pad_set_caps (stream->pad, stream->caps);
2888 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2889 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2890 stream->active = TRUE;
2895 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2898 AsfCorrectionType correction_type;
2899 AsfStreamType stream_type;
2900 GstClockTime time_offset;
2901 gboolean is_encrypted G_GNUC_UNUSED;
2905 guint stream_specific_size;
2906 guint type_specific_size G_GNUC_UNUSED;
2907 guint unknown G_GNUC_UNUSED;
2908 gboolean inspect_payload = FALSE;
2909 AsfStream *stream = NULL;
2911 /* Get the rest of the header's header */
2912 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2913 goto not_enough_data;
2915 gst_asf_demux_get_guid (&guid, &data, &size);
2916 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2918 gst_asf_demux_get_guid (&guid, &data, &size);
2919 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2921 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2923 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2924 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2926 flags = gst_asf_demux_get_uint16 (&data, &size);
2927 stream_id = flags & 0x7f;
2928 is_encrypted = ! !((flags & 0x8000) << 15);
2929 unknown = gst_asf_demux_get_uint32 (&data, &size);
2931 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2932 stream_id, GST_TIME_ARGS (time_offset));
2934 /* dvr-ms has audio stream declared in stream specific data */
2935 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2936 AsfExtStreamType ext_stream_type;
2937 gst_asf_demux_get_guid (&guid, &data, &size);
2938 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2940 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2941 inspect_payload = TRUE;
2943 gst_asf_demux_get_guid (&guid, &data, &size);
2944 gst_asf_demux_get_uint32 (&data, &size);
2945 gst_asf_demux_get_uint32 (&data, &size);
2946 gst_asf_demux_get_uint32 (&data, &size);
2947 gst_asf_demux_get_guid (&guid, &data, &size);
2948 gst_asf_demux_get_uint32 (&data, &size);
2949 stream_type = ASF_STREAM_AUDIO;
2953 switch (stream_type) {
2954 case ASF_STREAM_AUDIO:{
2955 asf_stream_audio audio_object;
2957 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2958 goto not_enough_data;
2960 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2963 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2966 switch (correction_type) {
2967 case ASF_CORRECTION_ON:{
2968 guint span, packet_size, chunk_size, data_size, silence_data;
2970 GST_INFO ("Using error correction");
2972 if (size < (1 + 2 + 2 + 2 + 1))
2973 goto not_enough_data;
2975 span = gst_asf_demux_get_uint8 (&data, &size);
2976 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2977 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2978 data_size = gst_asf_demux_get_uint16 (&data, &size);
2979 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2981 stream->span = span;
2983 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2984 packet_size, chunk_size, data_size, span, silence_data);
2986 if (stream->span > 1) {
2987 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2988 /* Disable descrambling */
2991 /* FIXME: this else branch was added for
2992 * weird_al_yankovic - the saga begins.asf */
2993 stream->ds_packet_size = packet_size;
2994 stream->ds_chunk_size = chunk_size;
2997 /* Descambling is enabled */
2998 stream->ds_packet_size = packet_size;
2999 stream->ds_chunk_size = chunk_size;
3002 /* Now skip the rest of the silence data */
3004 gst_bytestream_flush (demux->bs, data_size - 1);
3006 /* FIXME: CHECKME. And why -1? */
3007 if (data_size > 1) {
3008 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
3009 goto not_enough_data;
3015 case ASF_CORRECTION_OFF:{
3016 GST_INFO ("Error correction off");
3017 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
3018 goto not_enough_data;
3022 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3023 ("Audio stream using unknown error correction"));
3030 case ASF_STREAM_VIDEO:{
3031 asf_stream_video_format video_format_object;
3032 asf_stream_video video_object;
3035 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3036 goto not_enough_data;
3038 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3040 GST_INFO ("object is a video stream with %u bytes of "
3041 "additional data", vsize);
3043 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3045 goto not_enough_data;
3048 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3049 stream_id, &data, &size);
3055 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3057 demux->other_streams =
3058 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3063 stream->inspect_payload = inspect_payload;
3068 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3069 /* we'll error out later if we found no streams */
3074 static const gchar *
3075 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3079 const gchar *asf_name;
3080 const gchar *gst_name;
3083 "WM/Genre", GST_TAG_GENRE}, {
3084 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3085 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3086 "WM/Picture", GST_TAG_IMAGE}, {
3087 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3088 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3089 "WM/Year", GST_TAG_DATE_TIME}
3090 /* { "WM/Composer", GST_TAG_COMPOSER } */
3095 if (name_utf8 == NULL) {
3096 GST_WARNING ("Failed to convert name to UTF8, skipping");
3100 out = strlen (name_utf8);
3102 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3103 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3104 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3105 return tags[i].gst_name;
3112 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3114 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3118 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3120 if (taglist == NULL)
3123 if (gst_tag_list_is_empty (taglist)) {
3124 gst_tag_list_unref (taglist);
3128 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3129 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3131 gst_tag_list_unref (demux->taglist);
3132 gst_tag_list_unref (taglist);
3134 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3137 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3138 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3139 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3140 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3143 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3147 const guint8 *img_data = NULL;
3148 guint32 img_data_len = 0;
3149 guint8 pic_type = 0;
3151 gst_byte_reader_init (&r, tag_data, tag_data_len);
3153 /* skip mime type string (we don't trust it and do our own typefinding),
3154 * and also skip the description string, since we don't use it */
3155 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3156 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3157 !gst_byte_reader_skip_string_utf16 (&r) ||
3158 !gst_byte_reader_skip_string_utf16 (&r) ||
3159 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3160 goto not_enough_data;
3164 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3165 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3171 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3172 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3177 /* Extended Content Description Object */
3178 static GstFlowReturn
3179 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3182 /* Other known (and unused) 'text/unicode' metadata available :
3185 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3186 * WMFSDKVersion = 9.00.00.2980
3187 * WMFSDKNeeded = 0.0.0.0000
3188 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3189 * WM/Publisher = 4AD
3191 * WM/ProviderRating = 8
3192 * WM/ProviderStyle = Rock (similar to WM/Genre)
3193 * WM/GenreID (similar to WM/Genre)
3194 * WM/TrackNumber (same as WM/Track but as a string)
3196 * Other known (and unused) 'non-text' metadata available :
3202 * We might want to read WM/TrackNumber and use atoi() if we don't have
3206 GstTagList *taglist;
3207 guint16 blockcount, i;
3208 gboolean content3D = FALSE;
3212 const gchar *interleave_name;
3213 GstASF3DMode interleaving_type;
3214 } stereoscopic_layout_map[] = {
3216 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3217 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3218 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3219 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3220 "DualStream", GST_ASF_3D_DUAL_STREAM}
3222 GST_INFO_OBJECT (demux, "object is an extended content description");
3224 taglist = gst_tag_list_new_empty ();
3226 /* Content Descriptor Count */
3228 goto not_enough_data;
3230 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3232 for (i = 1; i <= blockcount; ++i) {
3233 const gchar *gst_tag_name;
3237 GValue tag_value = { 0, };
3240 gchar *name_utf8 = NULL;
3244 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3245 goto not_enough_data;
3249 goto not_enough_data;
3251 /* Descriptor Value Data Type */
3252 datatype = gst_asf_demux_get_uint16 (&data, &size);
3254 /* Descriptor Value (not really a string, but same thing reading-wise) */
3255 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3257 goto not_enough_data;
3261 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3263 if (name_utf8 != NULL) {
3264 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3266 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3267 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3270 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3273 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3276 /* get rid of tags with empty value */
3277 if (value_utf8 != NULL && *value_utf8 != '\0') {
3278 GST_DEBUG ("string value %s", value_utf8);
3280 value_utf8[out] = '\0';
3282 if (gst_tag_name != NULL) {
3283 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3284 guint year = atoi (value_utf8);
3287 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3288 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3290 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3291 guint id3v1_genre_id;
3292 const gchar *genre_str;
3294 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3295 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3296 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3297 g_free (value_utf8);
3298 value_utf8 = g_strdup (genre_str);
3303 /* convert tag from string to other type if required */
3304 tag_type = gst_tag_get_type (gst_tag_name);
3305 g_value_init (&tag_value, tag_type);
3306 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3307 GValue from_val = { 0, };
3309 g_value_init (&from_val, G_TYPE_STRING);
3310 g_value_set_string (&from_val, value_utf8);
3311 if (!g_value_transform (&from_val, &tag_value)) {
3312 GST_WARNING_OBJECT (demux,
3313 "Could not transform string tag to " "%s tag type %s",
3314 gst_tag_name, g_type_name (tag_type));
3315 g_value_unset (&tag_value);
3317 g_value_unset (&from_val);
3322 GST_DEBUG ("Setting metadata");
3323 g_value_init (&tag_value, G_TYPE_STRING);
3324 g_value_set_string (&tag_value, value_utf8);
3325 /* If we found a stereoscopic marker, look for StereoscopicLayout
3329 if (strncmp ("StereoscopicLayout", name_utf8,
3330 strlen (name_utf8)) == 0) {
3331 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3332 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3334 demux->asf_3D_mode =
3335 stereoscopic_layout_map[i].interleaving_type;
3336 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3340 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3342 demux->asf_3D_mode = GST_ASF_3D_NONE;
3343 GST_INFO_OBJECT (demux, "None 3d type");
3346 } else if (value_utf8 == NULL) {
3347 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3349 GST_DEBUG ("Skipping empty string value for %s",
3350 GST_STR_NULL (gst_tag_name));
3352 g_free (value_utf8);
3355 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3357 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3358 GST_FIXME ("Unhandled byte array tag %s",
3359 GST_STR_NULL (gst_tag_name));
3362 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3368 case ASF_DEMUX_DATA_TYPE_DWORD:{
3369 guint uint_val = GST_READ_UINT32_LE (value);
3371 /* this is the track number */
3372 g_value_init (&tag_value, G_TYPE_UINT);
3374 /* WM/Track counts from 0 */
3375 if (!strcmp (name_utf8, "WM/Track"))
3378 g_value_set_uint (&tag_value, uint_val);
3382 case ASF_DEMUX_DATA_TYPE_BOOL:{
3383 gboolean bool_val = GST_READ_UINT32_LE (value);
3385 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3387 GST_INFO_OBJECT (demux, "This is 3D contents");
3390 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3398 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3403 if (G_IS_VALUE (&tag_value)) {
3405 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3407 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3408 * is supposed to have a 0 base but is often wrongly written to start
3409 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3410 * replace the value added earlier from WM/Track or put it first in
3411 * the list, so that it will get picked up by _get_uint() */
3412 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3413 merge_mode = GST_TAG_MERGE_REPLACE;
3415 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3418 GST_DEBUG ("Setting global metadata %s", name_utf8);
3419 gst_structure_set_value (demux->global_metadata, name_utf8,
3423 g_value_unset (&tag_value);
3432 gst_asf_demux_add_global_tags (demux, taglist);
3439 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3440 gst_tag_list_unref (taglist);
3441 return GST_FLOW_OK; /* not really fatal */
3445 static GstStructure *
3446 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3451 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3453 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3456 s = gst_caps_get_structure (demux->metadata, i);
3457 if (gst_structure_has_name (s, sname))
3461 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3463 /* try lookup again; demux->metadata took ownership of the structure, so we
3464 * can't really make any assumptions about what happened to it, so we can't
3465 * just return it directly after appending it */
3466 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3469 static GstFlowReturn
3470 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3473 guint16 blockcount, i;
3475 GST_INFO_OBJECT (demux, "object is a metadata object");
3477 /* Content Descriptor Count */
3479 goto not_enough_data;
3481 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3483 for (i = 0; i < blockcount; ++i) {
3485 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3486 guint32 data_len, ival;
3489 if (size < (2 + 2 + 2 + 2 + 4))
3490 goto not_enough_data;
3492 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3493 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3494 name_len = gst_asf_demux_get_uint16 (&data, &size);
3495 data_type = gst_asf_demux_get_uint16 (&data, &size);
3496 data_len = gst_asf_demux_get_uint32 (&data, &size);
3498 if (size < name_len + data_len)
3499 goto not_enough_data;
3501 /* convert name to UTF-8 */
3502 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3504 gst_asf_demux_skip_bytes (name_len, &data, &size);
3506 if (name_utf8 == NULL) {
3507 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3508 gst_asf_demux_skip_bytes (data_len, &data, &size);
3512 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3513 gst_asf_demux_skip_bytes (data_len, &data, &size);
3521 goto not_enough_data;
3524 ival = gst_asf_demux_get_uint32 (&data, &size);
3526 /* skip anything else there may be, just in case */
3527 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3529 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3530 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3534 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3540 GST_WARNING ("Unexpected end of data parsing metadata object");
3541 return GST_FLOW_OK; /* not really fatal */
3545 static GstFlowReturn
3546 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3548 GstFlowReturn ret = GST_FLOW_OK;
3549 guint32 i, num_objects;
3550 guint8 unknown G_GNUC_UNUSED;
3552 /* Get the rest of the header's header */
3553 if (size < (4 + 1 + 1))
3554 goto not_enough_data;
3556 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3557 unknown = gst_asf_demux_get_uint8 (&data, &size);
3558 unknown = gst_asf_demux_get_uint8 (&data, &size);
3560 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3562 /* Loop through the header's objects, processing those */
3563 for (i = 0; i < num_objects; ++i) {
3564 GST_INFO_OBJECT (demux, "reading header part %u", i);
3565 ret = gst_asf_demux_process_object (demux, &data, &size);
3566 if (ret != GST_FLOW_OK) {
3567 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3576 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3577 ("short read parsing HEADER object"));
3578 return GST_FLOW_ERROR;
3582 static GstFlowReturn
3583 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3585 guint64 creation_time G_GNUC_UNUSED;
3586 guint64 file_size G_GNUC_UNUSED;
3587 guint64 send_time G_GNUC_UNUSED;
3588 guint64 packets_count, play_time, preroll;
3589 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3591 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3592 goto not_enough_data;
3594 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3595 file_size = gst_asf_demux_get_uint64 (&data, &size);
3596 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3597 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3598 play_time = gst_asf_demux_get_uint64 (&data, &size);
3599 send_time = gst_asf_demux_get_uint64 (&data, &size);
3600 preroll = gst_asf_demux_get_uint64 (&data, &size);
3601 flags = gst_asf_demux_get_uint32 (&data, &size);
3602 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3603 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3604 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3606 demux->broadcast = ! !(flags & 0x01);
3607 demux->seekable = ! !(flags & 0x02);
3609 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3610 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3611 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3613 if (demux->broadcast) {
3614 /* these fields are invalid if the broadcast flag is set */
3619 if (min_pktsize != max_pktsize)
3620 goto non_fixed_packet_size;
3622 demux->packet_size = max_pktsize;
3624 /* FIXME: do we need send_time as well? what is it? */
3625 if ((play_time * 100) >= (preroll * GST_MSECOND))
3626 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3628 demux->play_time = 0;
3630 demux->preroll = preroll * GST_MSECOND;
3632 /* initial latency */
3633 demux->latency = demux->preroll;
3635 if (demux->play_time == 0)
3636 demux->seekable = FALSE;
3638 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3639 GST_TIME_ARGS (demux->play_time));
3640 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3641 GST_TIME_ARGS (demux->preroll));
3643 if (demux->play_time > 0) {
3644 demux->segment.duration = demux->play_time;
3647 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3649 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3654 non_fixed_packet_size:
3656 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3657 ("packet size must be fixed"));
3658 return GST_FLOW_ERROR;
3662 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3663 ("short read parsing FILE object"));
3664 return GST_FLOW_ERROR;
3668 /* Content Description Object */
3669 static GstFlowReturn
3670 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3674 const gchar *gst_tag;
3679 GST_TAG_TITLE, 0, NULL}, {
3680 GST_TAG_ARTIST, 0, NULL}, {
3681 GST_TAG_COPYRIGHT, 0, NULL}, {
3682 GST_TAG_DESCRIPTION, 0, NULL}, {
3683 GST_TAG_COMMENT, 0, NULL}
3685 GstTagList *taglist;
3686 GValue value = { 0 };
3690 GST_INFO_OBJECT (demux, "object is a comment");
3692 if (size < (2 + 2 + 2 + 2 + 2))
3693 goto not_enough_data;
3695 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3696 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3697 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3698 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3699 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3701 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3702 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3703 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3705 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3706 if (size < tags[i].val_length)
3707 goto not_enough_data;
3709 /* might be just '/0', '/0'... */
3710 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3711 /* convert to UTF-8 */
3712 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3713 "UTF-8", "UTF-16LE", &in, &out, NULL);
3715 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3718 /* parse metadata into taglist */
3719 taglist = gst_tag_list_new_empty ();
3720 g_value_init (&value, G_TYPE_STRING);
3721 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3722 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3723 g_value_set_string (&value, tags[i].val_utf8);
3724 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3725 tags[i].gst_tag, &value, NULL);
3728 g_value_unset (&value);
3730 gst_asf_demux_add_global_tags (demux, taglist);
3732 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3733 g_free (tags[i].val_utf8);
3739 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3740 "comment tag section %d, skipping comment object", i);
3741 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3742 g_free (tags[i].val_utf8);
3743 return GST_FLOW_OK; /* not really fatal */
3747 static GstFlowReturn
3748 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3751 guint16 num_streams, i;
3755 goto not_enough_data;
3757 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3759 GST_INFO ("object is a bitrate properties object with %u streams",
3762 if (size < (num_streams * (2 + 4)))
3763 goto not_enough_data;
3765 for (i = 0; i < num_streams; ++i) {
3769 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3770 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3772 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3773 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3774 stream = gst_asf_demux_get_stream (demux, stream_id);
3776 if (stream->pending_tags == NULL)
3777 stream->pending_tags = gst_tag_list_new_empty ();
3778 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3779 GST_TAG_BITRATE, bitrate, NULL);
3781 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3784 GST_WARNING ("stream id %u is too large", stream_id);
3792 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3793 return GST_FLOW_OK; /* not really fatal */
3797 static GstFlowReturn
3798 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3801 GstFlowReturn ret = GST_FLOW_OK;
3804 /* Get the rest of the header's header */
3805 if (size < (16 + 2 + 4))
3806 goto not_enough_data;
3808 /* skip GUID and two other bytes */
3809 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3810 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3812 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3814 /* FIXME: does data_size include the rest of the header that we have read? */
3815 if (hdr_size > size)
3816 goto not_enough_data;
3818 while (hdr_size > 0) {
3819 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3820 if (ret != GST_FLOW_OK)
3828 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3829 ("short read parsing extended header object"));
3830 return GST_FLOW_ERROR;
3834 static GstFlowReturn
3835 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3841 goto not_enough_data;
3843 if (demux->languages) {
3844 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3845 g_strfreev (demux->languages);
3846 demux->languages = NULL;
3847 demux->num_languages = 0;
3850 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3851 GST_LOG ("%u languages:", demux->num_languages);
3853 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3854 for (i = 0; i < demux->num_languages; ++i) {
3855 guint8 len, *lang_data = NULL;
3858 goto not_enough_data;
3859 len = gst_asf_demux_get_uint8 (&data, &size);
3860 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3863 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3866 /* truncate "en-us" etc. to just "en" */
3867 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3870 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3871 demux->languages[i] = utf8;
3874 goto not_enough_data;
3882 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3883 g_free (demux->languages);
3884 demux->languages = NULL;
3885 return GST_FLOW_OK; /* not fatal */
3889 static GstFlowReturn
3890 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3893 GstClockTime interval;
3896 if (size < (16 + 8 + 4 + 4))
3897 goto not_enough_data;
3900 gst_asf_demux_skip_bytes (16, &data, &size);
3901 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3902 gst_asf_demux_skip_bytes (4, &data, &size);
3903 count = gst_asf_demux_get_uint32 (&data, &size);
3905 demux->sidx_interval = interval;
3906 demux->sidx_num_entries = count;
3907 g_free (demux->sidx_entries);
3908 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3910 for (i = 0; i < count; ++i) {
3911 if (G_UNLIKELY (size < 6)) {
3912 /* adjust for broken files, to avoid having entries at the end
3913 * of the parsed index that point to time=0. Resulting in seeking to
3914 * the end of the file leading back to the beginning */
3915 demux->sidx_num_entries -= (count - i);
3918 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3919 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3920 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3921 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3922 demux->sidx_entries[i].count);
3925 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3932 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3933 return GST_FLOW_OK; /* not fatal */
3937 static GstFlowReturn
3938 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3939 guint8 * data, guint64 size)
3944 if (size < 16 + 2 + (2 * 2))
3945 goto not_enough_data;
3947 gst_asf_demux_get_guid (&guid, &data, &size);
3948 num = gst_asf_demux_get_uint16 (&data, &size);
3951 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3955 if (size < (num * sizeof (guint16)))
3956 goto not_enough_data;
3958 /* read mutually exclusive stream numbers */
3959 for (i = 0; i < num; ++i) {
3961 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3962 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3964 demux->mut_ex_streams =
3965 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
3974 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3975 return GST_FLOW_OK; /* not absolutely fatal */
3980 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3982 return g_slist_find (demux->other_streams,
3983 GINT_TO_POINTER (stream_num)) == NULL;
3986 static GstFlowReturn
3987 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3990 AsfStreamExtProps esp;
3991 AsfStream *stream = NULL;
3992 AsfObject stream_obj;
3993 guint16 stream_name_count;
3994 guint16 num_payload_ext;
3996 guint8 *stream_obj_data = NULL;
3999 guint i, stream_num;
4002 obj_size = (guint) size;
4005 goto not_enough_data;
4008 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4009 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
4010 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
4011 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
4012 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
4013 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
4014 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
4015 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
4016 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
4017 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
4018 stream_num = gst_asf_demux_get_uint16 (&data, &size);
4019 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4020 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
4021 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4022 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4024 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4025 GST_TIME_ARGS (esp.start_time));
4026 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4027 GST_TIME_ARGS (esp.end_time));
4028 GST_INFO ("flags = %08x", esp.flags);
4029 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4030 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4031 GST_INFO ("stream number = %u", stream_num);
4032 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4033 (esp.lang_idx < demux->num_languages) ?
4034 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4035 GST_INFO ("stream name count = %u", stream_name_count);
4037 /* read stream names */
4038 for (i = 0; i < stream_name_count; ++i) {
4039 guint16 stream_lang_idx G_GNUC_UNUSED;
4040 gchar *stream_name = NULL;
4043 goto not_enough_data;
4044 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4045 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4046 goto not_enough_data;
4047 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4048 g_free (stream_name); /* TODO: store names in struct */
4051 /* read payload extension systems stuff */
4052 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4054 if (num_payload_ext > 0)
4055 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4057 esp.payload_extensions = NULL;
4059 for (i = 0; i < num_payload_ext; ++i) {
4060 AsfPayloadExtension ext;
4062 guint32 sys_info_len;
4064 if (size < 16 + 2 + 4)
4065 goto not_enough_data;
4067 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4068 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4069 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4071 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4072 GST_LOG ("payload systems info len = %u", sys_info_len);
4073 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4074 goto not_enough_data;
4076 esp.payload_extensions[i] = ext;
4079 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4081 /* there might be an optional STREAM_INFO object here now; if not, we
4082 * should have parsed the corresponding stream info object already (since
4083 * we are parsing the extended stream properties objects delayed) */
4085 stream = gst_asf_demux_get_stream (demux, stream_num);
4089 /* get size of the stream object */
4090 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4091 goto not_enough_data;
4093 if (stream_obj.id != ASF_OBJ_STREAM)
4094 goto expected_stream_object;
4096 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4097 stream_obj.size > (10 * 1024 * 1024))
4098 goto not_enough_data;
4100 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4102 /* process this stream object later after all the other 'normal' ones
4103 * have been processed (since the others are more important/non-hidden) */
4104 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4105 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4106 goto not_enough_data;
4108 /* parse stream object */
4109 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4110 g_free (stream_obj_data);
4115 stream->ext_props = esp;
4117 /* try to set the framerate */
4118 if (stream->is_video && stream->caps) {
4119 GValue framerate = { 0 };
4123 g_value_init (&framerate, GST_TYPE_FRACTION);
4125 num = GST_SECOND / 100;
4126 denom = esp.avg_time_per_frame;
4128 /* avoid division by 0, assume 25/1 framerate */
4129 denom = GST_SECOND / 2500;
4132 gst_value_set_fraction (&framerate, num, denom);
4134 stream->caps = gst_caps_make_writable (stream->caps);
4135 s = gst_caps_get_structure (stream->caps, 0);
4136 gst_structure_set_value (s, "framerate", &framerate);
4137 g_value_unset (&framerate);
4138 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4139 num, denom, ((gdouble) num) / denom);
4142 /* add language info now if we have it */
4143 if (stream->ext_props.lang_idx < demux->num_languages) {
4144 if (stream->pending_tags == NULL)
4145 stream->pending_tags = gst_tag_list_new_empty ();
4146 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4147 demux->languages[stream->ext_props.lang_idx]);
4148 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4149 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4152 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4153 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4161 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4162 return GST_FLOW_OK; /* not absolutely fatal */
4164 expected_stream_object:
4166 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4167 "object: expected embedded stream object, but got %s object instead!",
4168 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4169 return GST_FLOW_OK; /* not absolutely fatal */
4173 static const gchar *
4174 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4178 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4179 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4180 nick += strlen ("ASF_OBJ_");
4182 if (demux->objpath == NULL) {
4183 demux->objpath = g_strdup (nick);
4187 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4188 g_free (demux->objpath);
4189 demux->objpath = newpath;
4192 return (const gchar *) demux->objpath;
4196 gst_asf_demux_pop_obj (GstASFDemux * demux)
4200 if ((s = g_strrstr (demux->objpath, "/"))) {
4203 g_free (demux->objpath);
4204 demux->objpath = NULL;
4209 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4214 /* Parse the queued extended stream property objects and add the info
4215 * to the existing streams or add the new embedded streams, but without
4216 * activating them yet */
4217 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4218 g_slist_length (demux->ext_stream_props));
4220 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4221 GstBuffer *buf = GST_BUFFER (l->data);
4224 gst_buffer_map (buf, &map, GST_MAP_READ);
4226 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4227 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4228 gst_buffer_unmap (buf, &map);
4229 gst_buffer_unref (buf);
4231 g_slist_free (demux->ext_stream_props);
4232 demux->ext_stream_props = NULL;
4237 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4241 for (i = 0; i < demux->num_streams; ++i) {
4246 stream = &demux->stream[i];
4248 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4250 if (stream->active) {
4251 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4256 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4259 /* check for each mutual exclusion whether it affects this stream */
4260 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4261 if (*mes == stream->id) {
4262 /* if yes, check if we've already added streams that are mutually
4263 * exclusive with the stream we're about to add */
4264 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4265 for (j = 0; j < demux->num_streams; ++j) {
4266 /* if the broadcast flag is set, assume the hidden streams aren't
4267 * actually streamed and hide them (or playbin won't work right),
4268 * otherwise assume their data is available */
4269 if (demux->stream[j].id == *mes && demux->broadcast) {
4271 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4272 "mutually exclusive with already existing stream ID %d, "
4273 "hiding stream", stream->id, demux->stream[j].id);
4285 /* FIXME: we should do stream activation based on preroll data in
4286 * streaming mode too */
4287 if (demux->streaming && !is_hidden)
4288 gst_asf_demux_activate_stream (demux, stream);
4293 static GstFlowReturn
4294 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4297 GstFlowReturn ret = GST_FLOW_OK;
4299 guint64 obj_data_size;
4301 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4302 return ASF_FLOW_NEED_MORE_DATA;
4304 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4305 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4307 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4309 if (*p_size < obj_data_size)
4310 return ASF_FLOW_NEED_MORE_DATA;
4312 gst_asf_demux_push_obj (demux, obj.id);
4314 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4317 case ASF_OBJ_STREAM:
4318 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4322 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4324 case ASF_OBJ_HEADER:
4325 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4327 case ASF_OBJ_COMMENT:
4328 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4331 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4333 case ASF_OBJ_BITRATE_PROPS:
4335 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4338 case ASF_OBJ_EXT_CONTENT_DESC:
4340 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4343 case ASF_OBJ_METADATA_OBJECT:
4344 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4346 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4349 /* process these later, we might not have parsed the corresponding
4350 * stream object yet */
4351 GST_LOG ("%s: queued for later parsing", demux->objpath);
4352 buf = gst_buffer_new_and_alloc (obj_data_size);
4353 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4354 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4358 case ASF_OBJ_LANGUAGE_LIST:
4359 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4361 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4362 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4365 case ASF_OBJ_SIMPLE_INDEX:
4366 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4368 case ASF_OBJ_CONTENT_ENCRYPTION:
4369 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4370 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4371 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4372 goto error_encrypted;
4373 case ASF_OBJ_CONCEAL_NONE:
4375 case ASF_OBJ_UNDEFINED:
4376 case ASF_OBJ_CODEC_COMMENT:
4378 case ASF_OBJ_PADDING:
4379 case ASF_OBJ_BITRATE_MUTEX:
4380 case ASF_OBJ_COMPATIBILITY:
4381 case ASF_OBJ_INDEX_PLACEHOLDER:
4382 case ASF_OBJ_INDEX_PARAMETERS:
4383 case ASF_OBJ_STREAM_PRIORITIZATION:
4384 case ASF_OBJ_SCRIPT_COMMAND:
4385 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4387 /* Unknown/unhandled object, skip it and hope for the best */
4388 GST_INFO ("%s: skipping object", demux->objpath);
4393 /* this can't fail, we checked the number of bytes available before */
4394 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4396 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4398 gst_asf_demux_pop_obj (demux);
4405 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4406 return GST_FLOW_ERROR;
4411 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4412 GstBuffer ** p_buffer)
4414 GstBuffer *descrambled_buffer;
4415 GstBuffer *scrambled_buffer;
4416 GstBuffer *sub_buffer;
4423 /* descrambled_buffer is initialised in the first iteration */
4424 descrambled_buffer = NULL;
4425 scrambled_buffer = *p_buffer;
4427 if (gst_buffer_get_size (scrambled_buffer) <
4428 stream->ds_packet_size * stream->span)
4431 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4432 offset += stream->ds_chunk_size) {
4433 off = offset / stream->ds_chunk_size;
4434 row = off / stream->span;
4435 col = off % stream->span;
4436 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4437 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4438 col, off, stream->ds_chunk_size);
4439 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4440 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4441 stream->span, stream->ds_packet_size);
4442 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4443 gst_buffer_get_size (scrambled_buffer));
4445 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4446 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4448 descrambled_buffer = sub_buffer;
4450 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4454 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4455 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4456 GST_BUFFER_DURATION (descrambled_buffer) =
4457 GST_BUFFER_DURATION (scrambled_buffer);
4458 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4459 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4460 GST_BUFFER_OFFSET_END (scrambled_buffer);
4462 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4464 gst_buffer_unref (scrambled_buffer);
4465 *p_buffer = descrambled_buffer;
4469 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4471 GstASFDemux *demux = GST_ASF_DEMUX (element);
4474 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4476 for (i = 0; i < demux->num_streams; ++i) {
4477 gst_event_ref (event);
4478 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4479 GST_OBJECT_CAST (element), event)) {
4480 gst_event_unref (event);
4485 gst_event_unref (event);
4489 /* takes ownership of the passed event */
4491 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4493 gboolean ret = TRUE;
4496 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4497 GST_EVENT_TYPE_NAME (event));
4499 for (i = 0; i < demux->num_streams; ++i) {
4500 gst_event_ref (event);
4501 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4503 gst_event_unref (event);
4508 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4512 gboolean res = FALSE;
4514 demux = GST_ASF_DEMUX (parent);
4516 GST_DEBUG ("handling %s query",
4517 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4519 switch (GST_QUERY_TYPE (query)) {
4520 case GST_QUERY_DURATION:
4524 gst_query_parse_duration (query, &format, NULL);
4526 if (format != GST_FORMAT_TIME) {
4527 GST_LOG ("only support duration queries in TIME format");
4531 res = gst_pad_query_default (pad, parent, query);
4533 GST_OBJECT_LOCK (demux);
4535 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4536 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4537 GST_TIME_ARGS (demux->segment.duration));
4539 gst_query_set_duration (query, GST_FORMAT_TIME,
4540 demux->segment.duration);
4544 GST_LOG ("duration not known yet");
4547 GST_OBJECT_UNLOCK (demux);
4552 case GST_QUERY_POSITION:{
4555 gst_query_parse_position (query, &format, NULL);
4557 if (format != GST_FORMAT_TIME) {
4558 GST_LOG ("only support position queries in TIME format");
4562 GST_OBJECT_LOCK (demux);
4564 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4565 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4566 GST_TIME_ARGS (demux->segment.position));
4568 gst_query_set_position (query, GST_FORMAT_TIME,
4569 demux->segment.position);
4573 GST_LOG ("position not known yet");
4576 GST_OBJECT_UNLOCK (demux);
4580 case GST_QUERY_SEEKING:{
4583 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4584 if (format == GST_FORMAT_TIME) {
4587 GST_OBJECT_LOCK (demux);
4588 duration = demux->segment.duration;
4589 GST_OBJECT_UNLOCK (demux);
4591 if (!demux->streaming || !demux->seekable) {
4592 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4599 /* try upstream first in TIME */
4600 res = gst_pad_query_default (pad, parent, query);
4602 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4603 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4604 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4605 /* if no luck, maybe in BYTES */
4606 if (!seekable || fmt != GST_FORMAT_TIME) {
4609 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4610 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4611 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4612 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4613 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4614 if (fmt != GST_FORMAT_BYTES)
4617 gst_query_unref (q);
4618 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4624 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4628 case GST_QUERY_LATENCY:
4631 GstClockTime min, max;
4633 /* preroll delay does not matter in non-live pipeline,
4634 * but we might end up in a live (rtsp) one ... */
4637 res = gst_pad_query_default (pad, parent, query);
4641 gst_query_parse_latency (query, &live, &min, &max);
4643 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4644 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4645 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4647 GST_OBJECT_LOCK (demux);
4648 min += demux->latency;
4650 max += demux->latency;
4651 GST_OBJECT_UNLOCK (demux);
4653 gst_query_set_latency (query, live, min, max);
4656 case GST_QUERY_SEGMENT:
4661 format = demux->segment.format;
4664 gst_segment_to_stream_time (&demux->segment, format,
4665 demux->segment.start);
4666 if ((stop = demux->segment.stop) == -1)
4667 stop = demux->segment.duration;
4669 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4671 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4676 res = gst_pad_query_default (pad, parent, query);
4683 static GstStateChangeReturn
4684 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4686 GstASFDemux *demux = GST_ASF_DEMUX (element);
4687 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4689 switch (transition) {
4690 case GST_STATE_CHANGE_NULL_TO_READY:{
4691 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4692 demux->need_newsegment = TRUE;
4693 demux->segment_running = FALSE;
4694 demux->keyunit_sync = FALSE;
4695 demux->accurate = FALSE;
4696 demux->adapter = gst_adapter_new ();
4697 demux->metadata = gst_caps_new_empty ();
4698 demux->global_metadata = gst_structure_new_empty ("metadata");
4699 demux->data_size = 0;
4700 demux->data_offset = 0;
4701 demux->index_offset = 0;
4702 demux->base_offset = 0;
4703 demux->flowcombiner = gst_flow_combiner_new ();
4711 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4712 if (ret == GST_STATE_CHANGE_FAILURE)
4715 switch (transition) {
4716 case GST_STATE_CHANGE_PAUSED_TO_READY:
4717 gst_asf_demux_reset (demux, FALSE);
4720 case GST_STATE_CHANGE_READY_TO_NULL:
4721 gst_asf_demux_reset (demux, FALSE);
4722 gst_flow_combiner_free (demux->flowcombiner);
4723 demux->flowcombiner = NULL;