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_pad_template (gstelement_class,
132 gst_static_pad_template_get (&audio_src_template));
133 gst_element_class_add_pad_template (gstelement_class,
134 gst_static_pad_template_get (&video_src_template));
135 gst_element_class_add_pad_template (gstelement_class,
136 gst_static_pad_template_get (&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->metadata = gst_caps_new_empty ();
294 demux->global_metadata = gst_structure_new_empty ("metadata");
295 demux->data_size = 0;
296 demux->data_offset = 0;
297 demux->index_offset = 0;
299 demux->base_offset = 0;
302 g_slist_free (demux->other_streams);
303 demux->other_streams = NULL;
307 gst_asf_demux_init (GstASFDemux * demux)
310 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
311 gst_pad_set_chain_function (demux->sinkpad,
312 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
313 gst_pad_set_event_function (demux->sinkpad,
314 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
315 gst_pad_set_activate_function (demux->sinkpad,
316 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
317 gst_pad_set_activatemode_function (demux->sinkpad,
318 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
319 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
321 /* set initial state */
322 gst_asf_demux_reset (demux, FALSE);
326 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
331 query = gst_query_new_scheduling ();
333 if (!gst_pad_peer_query (sinkpad, query)) {
334 gst_query_unref (query);
338 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
339 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
340 gst_query_unref (query);
345 GST_DEBUG_OBJECT (sinkpad, "activating pull");
346 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
350 GST_DEBUG_OBJECT (sinkpad, "activating push");
351 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
356 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
357 GstPadMode mode, gboolean active)
362 demux = GST_ASF_DEMUX (parent);
365 case GST_PAD_MODE_PUSH:
366 demux->state = GST_ASF_DEMUX_STATE_HEADER;
367 demux->streaming = TRUE;
370 case GST_PAD_MODE_PULL:
372 demux->state = GST_ASF_DEMUX_STATE_HEADER;
373 demux->streaming = FALSE;
375 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
378 res = gst_pad_stop_task (sinkpad);
389 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
394 demux = GST_ASF_DEMUX (parent);
396 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
397 switch (GST_EVENT_TYPE (event)) {
398 case GST_EVENT_SEGMENT:{
399 const GstSegment *segment;
401 gst_event_parse_segment (event, &segment);
403 if (segment->format == GST_FORMAT_BYTES) {
404 if (demux->packet_size && segment->start > demux->data_offset)
405 demux->packet = (segment->start - demux->data_offset) /
409 } else if (segment->format == GST_FORMAT_TIME) {
410 /* do not know packet position, not really a problem */
413 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
414 gst_event_unref (event);
418 /* record upstream segment for interpolation */
419 if (segment->format != demux->in_segment.format)
420 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
421 gst_segment_copy_into (segment, &demux->in_segment);
423 /* in either case, clear some state and generate newsegment later on */
424 GST_OBJECT_LOCK (demux);
425 demux->segment_ts = GST_CLOCK_TIME_NONE;
426 demux->in_gap = GST_CLOCK_TIME_NONE;
427 demux->need_newsegment = TRUE;
428 demux->segment_seqnum = gst_event_get_seqnum (event);
429 gst_asf_demux_reset_stream_state_after_discont (demux);
430 GST_OBJECT_UNLOCK (demux);
432 gst_event_unref (event);
438 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
439 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
440 (_("This stream contains no data.")),
441 ("got eos and didn't receive a complete header object"));
444 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
445 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
446 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
447 (_("Internal data stream error.")),
448 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
452 GST_OBJECT_LOCK (demux);
453 gst_adapter_clear (demux->adapter);
454 GST_OBJECT_UNLOCK (demux);
455 gst_asf_demux_send_event_unlocked (demux, event);
459 case GST_EVENT_FLUSH_STOP:
460 GST_OBJECT_LOCK (demux);
461 gst_asf_demux_reset_stream_state_after_discont (demux);
462 GST_OBJECT_UNLOCK (demux);
463 gst_asf_demux_send_event_unlocked (demux, event);
464 /* upon activation, latency is no longer introduced, e.g. after seek */
465 if (demux->activated_streams)
470 ret = gst_pad_event_default (pad, parent, event);
478 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
479 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
480 gboolean next, gboolean * eos)
482 GstClockTime idx_time;
488 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
491 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
494 /* if we want the next keyframe, we have to go forward till we find
495 a different packet number */
497 if (idx >= demux->sidx_num_entries - 1) {
498 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
503 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
504 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
511 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
517 *packet = demux->sidx_entries[idx].packet;
519 *speed = demux->sidx_entries[idx].count;
521 /* so we get closer to the actual time of the packet ... actually, let's not
522 * do this, since we throw away superfluous payloads before the seek position
523 * anyway; this way, our key unit seek 'snap resolution' is a bit better
524 * (ie. same as index resolution) */
526 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
530 idx_time = demux->sidx_interval * idx;
531 if (G_LIKELY (idx_time >= demux->preroll))
532 idx_time -= demux->preroll;
534 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
535 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
536 GST_TIME_ARGS (idx_time));
538 if (G_LIKELY (p_idx_time))
539 *p_idx_time = idx_time;
545 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
549 gst_adapter_clear (demux->adapter);
551 GST_DEBUG_OBJECT (demux, "reset stream state");
553 gst_flow_combiner_reset (demux->flowcombiner);
554 for (n = 0; n < demux->num_streams; n++) {
555 demux->stream[n].discont = TRUE;
556 demux->stream[n].first_buffer = TRUE;
558 while (demux->stream[n].payloads->len > 0) {
562 last = demux->stream[n].payloads->len - 1;
563 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
564 gst_buffer_replace (&payload->buf, NULL);
565 g_array_remove_index (demux->stream[n].payloads, last);
571 gst_asf_demux_mark_discont (GstASFDemux * demux)
575 GST_DEBUG_OBJECT (demux, "Mark stream discont");
577 for (n = 0; n < demux->num_streams; n++)
578 demux->stream[n].discont = TRUE;
581 /* do a seek in push based mode */
583 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
588 GstSeekType cur_type, stop_type;
592 GstEvent *byte_event;
594 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
597 stop_type = GST_SEEK_TYPE_NONE;
600 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
602 /* determine packet, by index or by estimation */
603 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
606 (guint) gst_util_uint64_scale (demux->num_packets, cur,
610 if (packet > demux->num_packets) {
611 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
616 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
618 cur = demux->data_offset + ((guint64) packet * demux->packet_size);
620 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
621 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
622 /* BYTE seek event */
623 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
624 cur, stop_type, stop);
625 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
626 res = gst_pad_push_event (demux->sinkpad, byte_event);
632 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
634 GstClockTime idx_time;
637 GstSeekType cur_type, stop_type;
639 gboolean only_need_update;
640 gboolean accurate, after, before, next;
645 guint packet, speed_count = 1;
651 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
654 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
655 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
659 /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
660 * so first try to let it handle the seek event. */
661 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
664 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
665 demux->num_packets == 0 || demux->play_time == 0)) {
666 GST_LOG_OBJECT (demux, "stream is not seekable");
670 if (G_UNLIKELY (!demux->activated_streams)) {
671 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
675 if (G_UNLIKELY (rate <= 0.0)) {
676 GST_LOG_OBJECT (demux, "backward playback");
677 demux->seek_to_cur_pos = TRUE;
678 for (i = 0; i < demux->num_streams; i++) {
679 demux->stream[i].reverse_kf_ready = FALSE;
683 seqnum = gst_event_get_seqnum (event);
684 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
685 accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
686 demux->keyunit_sync =
687 ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
688 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
689 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
690 next = after && !before;
692 if (G_UNLIKELY (demux->streaming)) {
693 /* support it safely needs more segment handling, e.g. closing etc */
695 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
698 /* we can (re)construct the start later on, but not the end */
699 if (stop_type != GST_SEEK_TYPE_NONE &&
700 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
701 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
704 return gst_asf_demux_handle_seek_push (demux, event);
707 /* unlock the streaming thread */
708 if (G_LIKELY (flush)) {
709 fevent = gst_event_new_flush_start ();
711 gst_event_set_seqnum (fevent, seqnum);
712 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
713 gst_asf_demux_send_event_unlocked (demux, fevent);
715 gst_pad_pause_task (demux->sinkpad);
718 /* grab the stream lock so that streaming cannot continue, for
719 * non flushing seeks when the element is in PAUSED this could block
721 GST_PAD_STREAM_LOCK (demux->sinkpad);
723 /* we now can stop flushing, since we have the stream lock now */
724 fevent = gst_event_new_flush_stop (TRUE);
725 gst_event_set_seqnum (fevent, seqnum);
726 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
728 if (G_LIKELY (flush))
729 gst_asf_demux_send_event_unlocked (demux, fevent);
731 gst_event_unref (fevent);
733 /* operating on copy of segment until we know the seek worked */
734 segment = demux->segment;
736 if (G_UNLIKELY (demux->segment_running && !flush)) {
737 GstSegment newsegment;
740 /* create the segment event to close the current segment */
741 gst_segment_copy_into (&segment, &newsegment);
742 newseg = gst_event_new_segment (&newsegment);
743 gst_event_set_seqnum (newseg, seqnum);
745 gst_asf_demux_send_event_unlocked (demux, newseg);
748 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
749 cur, stop_type, stop, &only_need_update);
751 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
752 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
754 if (cur_type != GST_SEEK_TYPE_SET)
755 seek_time = segment.start;
759 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
760 * real start of data and segment_start to indexed time for key unit seek*/
761 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
762 &idx_time, &speed_count, next, &eos))) {
766 demux->packet = demux->num_packets;
770 /* First try to query our source to see if it can convert for us. This is
771 the case when our source is an mms stream, notice that in this case
772 gstmms will do a time based seek to get the byte offset, this is not a
773 problem as the seek to this offset needs to happen anway. */
774 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
775 GST_FORMAT_BYTES, &offset)) {
776 packet = (offset - demux->data_offset) / demux->packet_size;
777 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
778 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
779 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
780 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
781 demux->packet_size, packet);
783 /* FIXME: For streams containing video, seek to an earlier position in
784 * the hope of hitting a keyframe and let the sinks throw away the stuff
785 * before the segment start. For audio-only this is unnecessary as every
787 if (flush && (accurate || (demux->keyunit_sync && !next))
788 && demux->num_video_streams > 0) {
789 seek_time -= 5 * GST_SECOND;
794 packet = (guint) gst_util_uint64_scale (demux->num_packets,
795 seek_time, demux->play_time);
797 if (packet > demux->num_packets)
798 packet = demux->num_packets;
801 if (G_LIKELY (demux->keyunit_sync)) {
802 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
803 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
804 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
805 segment.start = idx_time;
806 segment.position = idx_time;
807 segment.time = idx_time;
811 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
813 GST_OBJECT_LOCK (demux);
814 demux->segment = segment;
815 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
816 demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
817 stop, demux->play_time);
819 demux->packet = packet;
822 demux->need_newsegment = TRUE;
823 demux->segment_seqnum = seqnum;
824 demux->speed_packets =
825 GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
826 gst_asf_demux_reset_stream_state_after_discont (demux);
827 GST_OBJECT_UNLOCK (demux);
830 /* restart our task since it might have been stopped when we did the flush */
831 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
834 /* streaming can continue now */
835 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
841 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
847 demux = GST_ASF_DEMUX (parent);
849 switch (GST_EVENT_TYPE (event)) {
851 GST_LOG_OBJECT (pad, "seek event");
852 ret = gst_asf_demux_handle_seek_event (demux, event);
853 gst_event_unref (event);
856 case GST_EVENT_NAVIGATION:
857 /* just drop these two silently */
858 gst_event_unref (event);
862 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
863 ret = gst_pad_event_default (pad, parent, event);
870 static inline guint32
871 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
875 ret = gst_asf_identify_guid (guids, guid);
877 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
878 gst_asf_get_guid_nick (guids, ret),
879 guid->v1, guid->v2, guid->v3, guid->v4);
891 /* expect is true when the user is expeting an object,
892 * when false, it will give no warnings if the object
896 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
897 guint data_len, AsfObject * object, gboolean expect)
901 if (data_len < ASF_OBJECT_HEADER_SIZE)
904 guid.v1 = GST_READ_UINT32_LE (data + 0);
905 guid.v2 = GST_READ_UINT32_LE (data + 4);
906 guid.v3 = GST_READ_UINT32_LE (data + 8);
907 guid.v4 = GST_READ_UINT32_LE (data + 12);
909 object->size = GST_READ_UINT64_LE (data + 16);
911 /* FIXME: make asf_demux_identify_object_guid() */
912 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
913 if (object->id == ASF_OBJ_UNDEFINED && expect) {
914 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
915 guid.v1, guid.v2, guid.v3, guid.v4);
922 gst_asf_demux_release_old_pads (GstASFDemux * demux)
924 GST_DEBUG_OBJECT (demux, "Releasing old pads");
926 while (demux->old_num_streams > 0) {
927 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
928 gst_event_new_eos ());
929 gst_asf_demux_free_stream (demux,
930 &demux->old_stream[demux->old_num_streams - 1]);
931 --demux->old_num_streams;
933 memset (demux->old_stream, 0, sizeof (demux->old_stream));
934 demux->old_num_streams = 0;
938 gst_asf_demux_chain_headers (GstASFDemux * demux)
942 guint8 *header_data, *data = NULL;
943 const guint8 *cdata = NULL;
946 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
950 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
951 if (obj.id != ASF_OBJ_HEADER)
954 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
956 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
957 if (gst_adapter_available (demux->adapter) < obj.size + 50)
960 data = gst_adapter_take (demux->adapter, obj.size + 50);
963 header_size = obj.size;
964 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
965 if (flow != GST_FLOW_OK)
968 /* calculate where the packet data starts */
969 demux->data_offset = obj.size + 50;
971 /* now parse the beginning of the ASF_OBJ_DATA object */
972 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
975 if (demux->num_streams == 0)
984 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
991 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
992 ("This doesn't seem to be an ASF file"));
994 return GST_FLOW_ERROR;
999 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1000 ("header parsing failed, or no streams found, flow = %s",
1001 gst_flow_get_name (flow)));
1003 return GST_FLOW_ERROR;
1008 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1009 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1014 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1017 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1019 if (G_LIKELY (p_flow))
1022 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1023 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1024 "+%u", gst_flow_get_name (flow), offset, size);
1029 g_assert (*p_buf != NULL);
1031 buffer_size = gst_buffer_get_size (*p_buf);
1032 if (G_UNLIKELY (buffer_size < size)) {
1033 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1034 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1035 gst_buffer_unref (*p_buf);
1036 if (G_LIKELY (p_flow))
1037 *p_flow = GST_FLOW_EOS;
1046 gst_asf_demux_pull_indices (GstASFDemux * demux)
1048 GstBuffer *buf = NULL;
1052 offset = demux->index_offset;
1054 if (G_UNLIKELY (offset == 0)) {
1055 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1059 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1065 gst_buffer_map (buf, &map, GST_MAP_READ);
1066 g_assert (map.size >= 16 + 8);
1067 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1068 gst_buffer_unmap (buf, &map);
1069 gst_buffer_replace (&buf, NULL);
1071 /* check for sanity */
1072 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1073 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1077 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1081 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1082 ", size %u", offset, (guint) obj.size);
1084 offset += obj.size; /* increase before _process_object changes it */
1086 gst_buffer_map (buf, &map, GST_MAP_READ);
1087 g_assert (map.size >= obj.size);
1088 bufdata = (guint8 *) map.data;
1089 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1090 gst_buffer_unmap (buf, &map);
1091 gst_buffer_replace (&buf, NULL);
1093 if (G_UNLIKELY (flow != GST_FLOW_OK))
1098 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1102 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1106 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1107 if (obj.id != ASF_OBJ_DATA) {
1108 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1112 demux->state = GST_ASF_DEMUX_STATE_DATA;
1114 if (!demux->broadcast && obj.size > 50) {
1115 demux->data_size = obj.size - 50;
1116 /* CHECKME: for at least one file this is off by +158 bytes?! */
1117 demux->index_offset = demux->data_offset + demux->data_size;
1119 demux->data_size = 0;
1120 demux->index_offset = 0;
1125 if (!demux->broadcast) {
1126 /* skip object header (24 bytes) and file GUID (16 bytes) */
1127 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1129 demux->num_packets = 0;
1132 if (demux->num_packets == 0)
1133 demux->seekable = FALSE;
1135 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1136 if (demux->data_size == 0 && demux->num_packets > 0) {
1137 demux->data_size = demux->num_packets * demux->packet_size;
1138 demux->index_offset = demux->data_offset + demux->data_size;
1141 /* process pending stream objects and create pads for those */
1142 gst_asf_demux_process_queued_extended_stream_objects (demux);
1144 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1145 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1146 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1147 demux->data_offset, demux->data_size, demux->index_offset);
1153 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1155 GstFlowReturn flow = GST_FLOW_OK;
1157 GstBuffer *buf = NULL;
1162 GST_LOG_OBJECT (demux, "reading headers");
1164 /* pull HEADER object header, so we know its size */
1165 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1168 gst_buffer_map (buf, &map, GST_MAP_READ);
1169 g_assert (map.size >= 16 + 8);
1170 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1171 gst_buffer_unmap (buf, &map);
1172 gst_buffer_replace (&buf, NULL);
1174 if (obj.id != ASF_OBJ_HEADER)
1177 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1179 /* pull HEADER object */
1180 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1184 size = obj.size; /* don't want obj.size changed */
1185 gst_buffer_map (buf, &map, GST_MAP_READ);
1186 g_assert (map.size >= size);
1187 bufdata = (guint8 *) map.data;
1188 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1189 gst_buffer_unmap (buf, &map);
1190 gst_buffer_replace (&buf, NULL);
1192 if (flow != GST_FLOW_OK) {
1193 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1197 /* calculate where the packet data starts */
1198 demux->data_offset = demux->base_offset + obj.size + 50;
1200 /* now pull beginning of DATA object before packet data */
1201 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1205 gst_buffer_map (buf, &map, GST_MAP_READ);
1206 g_assert (map.size >= size);
1207 bufdata = (guint8 *) map.data;
1208 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1211 if (demux->num_streams == 0)
1214 gst_buffer_unmap (buf, &map);
1215 gst_buffer_replace (&buf, NULL);
1223 gst_buffer_unmap (buf, &map);
1224 gst_buffer_replace (&buf, NULL);
1226 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1227 ("This doesn't seem to be an ASF file"));
1228 *pflow = GST_FLOW_ERROR;
1233 flow = GST_FLOW_ERROR;
1234 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1235 ("header parsing failed, or no streams found, flow = %s",
1236 gst_flow_get_name (flow)));
1241 gst_buffer_unmap (buf, &map);
1242 gst_buffer_replace (&buf, NULL);
1249 all_streams_prerolled (GstASFDemux * demux)
1251 GstClockTime preroll_time;
1252 guint i, num_no_data = 0;
1254 /* Allow at least 500ms of preroll_time */
1255 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1257 /* returns TRUE as long as there isn't a stream which (a) has data queued
1258 * and (b) the timestamp of last piece of data queued is < demux->preroll
1259 * AND there is at least one other stream with data queued */
1260 for (i = 0; i < demux->num_streams; ++i) {
1261 AsfPayload *last_payload = NULL;
1265 stream = &demux->stream[i];
1266 if (G_UNLIKELY (stream->payloads->len == 0)) {
1268 GST_LOG_OBJECT (stream->pad, "no data queued");
1272 /* find last payload with timestamp */
1273 for (last_idx = stream->payloads->len - 1;
1274 last_idx >= 0 && (last_payload == NULL
1275 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1276 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1279 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1280 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1281 GST_TIME_ARGS (preroll_time));
1282 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1283 || last_payload->ts <= preroll_time)) {
1284 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1289 if (G_UNLIKELY (num_no_data > 0))
1297 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1302 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1305 /* check for each mutual exclusion group whether it affects this stream */
1306 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1307 if (*mes == stream->id) {
1308 /* we are in this group; let's check if we've already activated streams
1309 * that are in the same group (and hence mutually exclusive to this
1311 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1314 for (i = 0; i < demux->num_streams; ++i) {
1315 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1316 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1317 "to already active stream with ID %d", stream->id,
1318 demux->stream[i].id);
1323 /* we can only be in this group once, let's break out and move on to
1324 * the next mutual exclusion group */
1335 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1337 /* remember the first queued timestamp for the segment */
1338 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1339 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1340 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1341 GST_TIME_ARGS (demux->first_ts));
1342 demux->segment_ts = payload_ts;
1343 /* always note, but only determines segment when streaming */
1344 if (demux->streaming)
1345 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1346 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1347 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1352 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1354 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1355 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1358 /* go trhough each stream, find smallest timestamp */
1359 for (i = 0; i < demux->num_streams; ++i) {
1362 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1363 GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE; /* second smallest timestamp */
1364 stream = &demux->stream[i];
1366 for (j = 0; j < stream->payloads->len; ++j) {
1367 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1368 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1369 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1370 || stream_min_ts > payload->ts)) {
1371 stream_min_ts = payload->ts;
1373 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1374 payload->ts > stream_min_ts &&
1375 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1376 || stream_min_ts2 > payload->ts)) {
1377 stream_min_ts2 = payload->ts;
1381 /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1382 regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1383 which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
1384 from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1385 and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1387 if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
1390 if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1391 stream_min_ts = stream_min_ts2;
1393 /* if we don't have timestamp for this stream, wait for more data */
1394 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1397 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1398 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1399 first_ts = stream_min_ts;
1402 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1405 demux->first_ts = first_ts;
1407 /* update packets queued before we knew first timestamp */
1408 for (i = 0; i < demux->num_streams; ++i) {
1411 stream = &demux->stream[i];
1413 for (j = 0; j < stream->payloads->len; ++j) {
1414 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1415 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1416 if (payload->ts > first_ts)
1417 payload->ts -= first_ts;
1425 gst_asf_demux_check_segment_ts (demux, 0);
1431 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1433 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1434 and often set wrong, inspecting the data is the only way that seem to be working */
1435 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1436 GstCaps *caps = NULL;
1438 GstAdapter *adapter = gst_adapter_new ();
1440 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1442 AsfPayload *payload;
1445 payload = &g_array_index (stream->payloads, AsfPayload, i);
1446 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1447 len = gst_adapter_available (adapter);
1448 data = gst_adapter_map (adapter, len);
1452 #define MIN_LENGTH 128
1454 /* look for the sync points */
1456 if (len < MIN_LENGTH || /* give typefind something to work on */
1457 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1458 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1464 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1467 if (prob < GST_TYPE_FIND_LIKELY) {
1470 if (len > MIN_LENGTH)
1471 /* this wasn't it, look for another sync point */
1475 gst_adapter_unmap (adapter);
1478 gst_object_unref (adapter);
1481 gst_caps_take (&stream->caps, caps);
1489 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1493 if (demux->activated_streams)
1496 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1499 if (!all_streams_prerolled (demux) && !force) {
1500 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1504 for (i = 0; i < demux->num_streams; ++i) {
1505 AsfStream *stream = &demux->stream[i];
1507 if (stream->payloads->len > 0) {
1509 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1510 !stream->active && /* do not inspect active streams (caps were already set) */
1511 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1512 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1513 /* try to gather some more data */
1516 /* we don't check mutual exclusion stuff here; either we have data for
1517 * a stream, then we active it, or we don't, then we'll ignore it */
1518 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1519 gst_asf_demux_activate_stream (demux, stream);
1521 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1525 gst_asf_demux_release_old_pads (demux);
1527 demux->activated_streams = TRUE;
1528 GST_LOG_OBJECT (demux, "signalling no more pads");
1529 gst_element_no_more_pads (GST_ELEMENT (demux));
1533 /* returns the stream that has a complete payload with the lowest timestamp
1534 * queued, or NULL (we push things by timestamp because during the internal
1535 * prerolling we might accumulate more data then the external queues can take,
1536 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1538 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1540 AsfPayload *best_payload = NULL;
1541 AsfStream *best_stream = NULL;
1544 for (i = 0; i < demux->num_streams; ++i) {
1548 stream = &demux->stream[i];
1550 /* Don't push any data until we have at least one payload that falls within
1551 * the current segment. This way we can remove out-of-segment payloads that
1552 * don't need to be decoded after a seek, sending only data from the
1553 * keyframe directly before our segment start */
1554 if (stream->payloads->len > 0) {
1555 AsfPayload *payload = NULL;
1558 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1559 /* Reverse playback */
1561 if (stream->is_video) {
1562 /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1563 if (stream->reverse_kf_ready) {
1565 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1566 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1567 /* TODO : remove payload from the list? */
1574 /* find first complete payload with timestamp */
1575 for (j = stream->payloads->len - 1;
1576 j >= 0 && (payload == NULL
1577 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1578 payload = &g_array_index (stream->payloads, AsfPayload, j);
1581 /* If there's a complete payload queued for this stream */
1582 if (!gst_asf_payload_is_complete (payload))
1588 /* find last payload with timestamp */
1589 for (last_idx = stream->payloads->len - 1;
1590 last_idx >= 0 && (payload == NULL
1591 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1592 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1595 /* if this is first payload after seek we might need to update the segment */
1596 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1597 gst_asf_demux_check_segment_ts (demux, payload->ts);
1599 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1600 (payload->ts < demux->segment.start))) {
1601 if (G_UNLIKELY ((!demux->keyunit_sync) && payload->keyframe)) {
1602 GST_DEBUG_OBJECT (stream->pad,
1603 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1604 GST_TIME_ARGS (payload->ts));
1605 demux->segment.start = payload->ts;
1606 demux->segment.time = payload->ts;
1608 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1609 GST_TIME_FORMAT " which is before our segment start %"
1610 GST_TIME_FORMAT ", not pushing yet",
1611 GST_TIME_ARGS (payload->ts),
1612 GST_TIME_ARGS (demux->segment.start));
1617 /* find first complete payload with timestamp */
1619 j < stream->payloads->len && (payload == NULL
1620 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1621 payload = &g_array_index (stream->payloads, AsfPayload, j);
1624 /* Now see if there's a complete payload queued for this stream */
1625 if (!gst_asf_payload_is_complete (payload))
1629 /* ... and whether its timestamp is lower than the current best */
1630 if (best_stream == NULL || best_payload->ts > payload->ts) {
1631 best_stream = stream;
1632 best_payload = payload;
1640 static GstFlowReturn
1641 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1644 GstFlowReturn ret = GST_FLOW_OK;
1646 if (G_UNLIKELY (!demux->activated_streams)) {
1647 if (!gst_asf_demux_check_activate_streams (demux, force))
1649 /* streams are now activated */
1652 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1653 AsfPayload *payload;
1654 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1655 GstClockTime duration = GST_CLOCK_TIME_NONE;
1657 /* wait until we had a chance to "lock on" some payload's timestamp */
1658 if (G_UNLIKELY (demux->need_newsegment
1659 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1662 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1663 && stream->payloads->len) {
1664 payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1666 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1669 /* do we need to send a newsegment event */
1670 if ((G_UNLIKELY (demux->need_newsegment))) {
1671 GstEvent *segment_event;
1673 /* safe default if insufficient upstream info */
1674 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1677 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1678 demux->segment.duration > 0) {
1679 /* slight HACK; prevent clipping of last bit */
1680 demux->segment.stop = demux->segment.duration + demux->in_gap;
1683 /* FIXME : only if ACCURATE ! */
1684 if (G_LIKELY (!demux->keyunit_sync
1685 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1686 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1687 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1688 GST_TIME_ARGS (payload->ts));
1689 demux->segment.start = payload->ts;
1690 demux->segment.time = payload->ts;
1693 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1696 /* note: we fix up all timestamps to start from 0, so this should be ok */
1697 segment_event = gst_event_new_segment (&demux->segment);
1698 if (demux->segment_seqnum)
1699 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1700 gst_asf_demux_send_event_unlocked (demux, segment_event);
1702 /* now post any global tags we may have found */
1703 if (demux->taglist == NULL) {
1704 demux->taglist = gst_tag_list_new_empty ();
1705 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1708 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1709 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1711 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1712 gst_asf_demux_send_event_unlocked (demux,
1713 gst_event_new_tag (demux->taglist));
1714 demux->taglist = NULL;
1716 demux->need_newsegment = FALSE;
1717 demux->segment_seqnum = 0;
1718 demux->segment_running = TRUE;
1721 /* Do we have tags pending for this stream? */
1722 if (G_UNLIKELY (stream->pending_tags)) {
1723 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1724 gst_pad_push_event (stream->pad,
1725 gst_event_new_tag (stream->pending_tags));
1726 stream->pending_tags = NULL;
1729 /* We have the whole packet now so we should push the packet to
1730 * the src pad now. First though we should check if we need to do
1732 if (G_UNLIKELY (stream->span > 1)) {
1733 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1736 payload->buf = gst_buffer_make_writable (payload->buf);
1738 if (G_LIKELY (!payload->keyframe)) {
1739 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1742 if (G_UNLIKELY (stream->discont)) {
1743 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1744 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1745 stream->discont = FALSE;
1748 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1749 (payload->par_x != stream->par_x) &&
1750 (payload->par_y != stream->par_y))) {
1751 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1752 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1753 stream->par_x = payload->par_x;
1754 stream->par_y = payload->par_y;
1755 stream->caps = gst_caps_make_writable (stream->caps);
1756 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1757 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1758 gst_pad_set_caps (stream->pad, stream->caps);
1761 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1762 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1763 payload->interlaced);
1764 stream->interlaced = payload->interlaced;
1765 stream->caps = gst_caps_make_writable (stream->caps);
1766 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1767 (stream->interlaced ? "mixed" : "progressive"), NULL);
1768 gst_pad_set_caps (stream->pad, stream->caps);
1771 /* (sort of) interpolate timestamps using upstream "frame of reference",
1772 * typically useful for live src, but might (unavoidably) mess with
1773 * position reporting if a live src is playing not so live content
1774 * (e.g. rtspsrc taking some time to fall back to tcp) */
1775 timestamp = payload->ts;
1776 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1777 && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1778 timestamp += demux->in_gap;
1780 /* Check if we're after the segment already, if so no need to push
1782 if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1783 GST_DEBUG_OBJECT (stream->pad,
1784 "Payload after segment stop %" GST_TIME_FORMAT,
1785 GST_TIME_ARGS (demux->segment.stop));
1787 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1789 gst_buffer_unref (payload->buf);
1790 payload->buf = NULL;
1791 g_array_remove_index (stream->payloads, 0);
1792 /* Break out as soon as we have an issue */
1793 if (G_UNLIKELY (ret != GST_FLOW_OK))
1800 GST_BUFFER_PTS (payload->buf) = timestamp;
1802 if (payload->duration == GST_CLOCK_TIME_NONE
1803 && stream->ext_props.avg_time_per_frame != 0) {
1804 duration = stream->ext_props.avg_time_per_frame * 100;
1806 duration = payload->duration;
1808 GST_BUFFER_DURATION (payload->buf) = duration;
1810 /* FIXME: we should really set durations on buffers if we can */
1812 GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1815 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1816 if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1817 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1819 } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1820 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1824 if (stream->active) {
1825 if (G_UNLIKELY (stream->first_buffer)) {
1826 if (stream->streamheader != NULL) {
1827 GST_DEBUG_OBJECT (stream->pad,
1828 "Pushing streamheader before first buffer");
1829 gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1831 stream->first_buffer = FALSE;
1834 if (GST_CLOCK_TIME_IS_VALID (timestamp)
1835 && timestamp > demux->segment.position) {
1836 demux->segment.position = timestamp;
1837 if (GST_CLOCK_TIME_IS_VALID (duration))
1838 demux->segment.position += timestamp;
1841 ret = gst_pad_push (stream->pad, payload->buf);
1843 gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1846 gst_buffer_unref (payload->buf);
1849 payload->buf = NULL;
1850 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1851 && stream->reverse_kf_ready) {
1852 g_array_remove_index (stream->payloads, stream->kf_pos);
1855 if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1857 stream->reverse_kf_ready = FALSE;
1860 g_array_remove_index (stream->payloads, 0);
1863 /* Break out as soon as we have an issue */
1864 if (G_UNLIKELY (ret != GST_FLOW_OK))
1872 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1876 g_assert (buf != NULL);
1878 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1880 gst_buffer_map (buf, &map, GST_MAP_READ);
1882 /* we return false on buffer too small */
1883 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1884 gst_buffer_unmap (buf, &map);
1888 /* check if it is a header */
1889 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1890 gst_buffer_unmap (buf, &map);
1891 if (obj.id == ASF_OBJ_HEADER) {
1898 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1900 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1901 GstFlowReturn ret = GST_FLOW_OK;
1902 GstBuffer *buf = NULL;
1903 gboolean header = FALSE;
1905 /* TODO maybe we should skip index objects after the data and look
1906 * further for a new header */
1907 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1908 g_assert (buf != NULL);
1909 /* check if it is a header */
1910 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1911 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1912 demux->base_offset = off;
1916 gst_buffer_unref (buf);
1923 gst_asf_demux_loop (GstASFDemux * demux)
1925 GstFlowReturn flow = GST_FLOW_OK;
1926 GstBuffer *buf = NULL;
1929 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1930 if (!gst_asf_demux_pull_headers (demux, &flow)) {
1934 gst_asf_demux_pull_indices (demux);
1937 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1939 if (G_UNLIKELY (demux->num_packets != 0
1940 && demux->packet >= demux->num_packets))
1943 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1944 (guint) demux->num_packets);
1946 off = demux->data_offset + (demux->packet * demux->packet_size);
1948 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1949 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1950 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1951 if (flow == GST_FLOW_EOS) {
1953 } else if (flow == GST_FLOW_FLUSHING) {
1954 GST_DEBUG_OBJECT (demux, "Not fatal");
1961 if (G_LIKELY (demux->speed_packets == 1)) {
1962 GstAsfDemuxParsePacketError err;
1963 err = gst_asf_demux_parse_packet (demux, buf);
1964 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1965 /* when we don't know when the data object ends, we should check
1966 * for a chained asf */
1967 if (demux->num_packets == 0) {
1968 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1969 GST_INFO_OBJECT (demux, "Chained asf found");
1970 demux->base_offset = off;
1971 gst_asf_demux_reset (demux, TRUE);
1972 gst_buffer_unref (buf);
1976 /* FIXME: We should tally up fatal errors and error out only
1977 * after a few broken packets in a row? */
1979 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1980 gst_buffer_unref (buf);
1982 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
1983 && !demux->seek_to_cur_pos) {
1985 if (demux->packet < 0) {
1995 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1997 if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
1998 && !demux->seek_to_cur_pos) {
2000 if (demux->packet < 0) {
2009 for (n = 0; n < demux->speed_packets; n++) {
2011 GstAsfDemuxParsePacketError err;
2014 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2015 n * demux->packet_size, demux->packet_size);
2016 err = gst_asf_demux_parse_packet (demux, sub);
2017 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2018 /* when we don't know when the data object ends, we should check
2019 * for a chained asf */
2020 if (demux->num_packets == 0) {
2021 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2022 GST_INFO_OBJECT (demux, "Chained asf found");
2023 demux->base_offset = off + n * demux->packet_size;
2024 gst_asf_demux_reset (demux, TRUE);
2025 gst_buffer_unref (sub);
2026 gst_buffer_unref (buf);
2030 /* FIXME: We should tally up fatal errors and error out only
2031 * after a few broken packets in a row? */
2033 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2037 gst_buffer_unref (sub);
2039 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2040 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2046 /* reset speed pull */
2047 demux->speed_packets = 1;
2050 gst_buffer_unref (buf);
2052 if (G_UNLIKELY ((demux->num_packets > 0
2053 && demux->packet >= demux->num_packets)
2054 || flow == GST_FLOW_EOS)) {
2055 GST_LOG_OBJECT (demux, "reached EOS");
2059 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2060 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2064 /* check if we're at the end of the configured segment */
2065 /* FIXME: check if segment end reached etc. */
2071 /* if we haven't activated our streams yet, this might be because we have
2072 * less data queued than required for preroll; force stream activation and
2073 * send any pending payloads before sending EOS */
2074 if (!demux->activated_streams)
2075 gst_asf_demux_push_complete_payloads (demux, TRUE);
2077 /* we want to push an eos or post a segment-done in any case */
2078 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2081 /* for segment playback we need to post when (in stream time)
2082 * we stopped, this is either stop (when set) or the duration. */
2083 if ((stop = demux->segment.stop) == -1)
2084 stop = demux->segment.duration;
2086 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2087 gst_element_post_message (GST_ELEMENT_CAST (demux),
2088 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2090 gst_asf_demux_send_event_unlocked (demux,
2091 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2092 } else if (flow != GST_FLOW_EOS) {
2093 /* check if we have a chained asf, in case, we don't eos yet */
2094 if (gst_asf_demux_check_chained_asf (demux)) {
2095 GST_INFO_OBJECT (demux, "Chained ASF starting");
2096 gst_asf_demux_reset (demux, TRUE);
2101 if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2102 /* normal playback, send EOS to all linked pads */
2103 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2104 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2106 /* ... and fall through to pause */
2110 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2111 gst_flow_get_name (flow));
2112 demux->segment_running = FALSE;
2113 gst_pad_pause_task (demux->sinkpad);
2115 /* For the error cases */
2116 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2117 /* Post an error. Hopefully something else already has, but if not... */
2118 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2119 (_("Internal data stream error.")),
2120 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
2121 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2130 GST_DEBUG_OBJECT (demux, "Read failed, doh");
2131 flow = GST_FLOW_EOS;
2135 /* See FIXMEs above */
2138 gst_buffer_unref (buf);
2139 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2140 ("Error parsing ASF packet %u", (guint) demux->packet));
2141 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2142 flow = GST_FLOW_ERROR;
2148 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2149 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2150 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2153 gst_asf_demux_check_header (GstASFDemux * demux)
2156 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2157 ASF_OBJECT_HEADER_SIZE);
2158 if (cdata == NULL) /* need more data */
2159 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2161 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2162 if (obj.id != ASF_OBJ_HEADER) {
2163 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2165 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2169 static GstFlowReturn
2170 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2172 GstFlowReturn ret = GST_FLOW_OK;
2175 demux = GST_ASF_DEMUX (parent);
2177 GST_LOG_OBJECT (demux,
2178 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2179 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2180 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2182 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2183 GST_DEBUG_OBJECT (demux, "received DISCONT");
2184 gst_asf_demux_mark_discont (demux);
2187 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2188 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2189 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2190 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2191 ", interpolation gap: %" GST_TIME_FORMAT,
2192 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2195 gst_adapter_push (demux->adapter, buf);
2197 switch (demux->state) {
2198 case GST_ASF_DEMUX_STATE_INDEX:{
2199 gint result = gst_asf_demux_check_header (demux);
2200 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2203 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2204 /* we don't care about this, probably an index */
2205 /* TODO maybe would be smarter to skip all the indices
2206 * until we got a new header or EOS to decide */
2207 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2210 GST_INFO_OBJECT (demux, "Chained asf starting");
2211 /* cleanup and get ready for a chained asf */
2212 gst_asf_demux_reset (demux, TRUE);
2216 case GST_ASF_DEMUX_STATE_HEADER:{
2217 ret = gst_asf_demux_chain_headers (demux);
2218 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2220 /* otherwise fall through */
2222 case GST_ASF_DEMUX_STATE_DATA:
2226 data_size = demux->packet_size;
2228 while (gst_adapter_available (demux->adapter) >= data_size) {
2230 GstAsfDemuxParsePacketError err;
2232 /* we don't know the length of the stream
2233 * check for a chained asf everytime */
2234 if (demux->num_packets == 0) {
2235 gint result = gst_asf_demux_check_header (demux);
2237 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2238 GST_INFO_OBJECT (demux, "Chained asf starting");
2239 /* cleanup and get ready for a chained asf */
2240 gst_asf_demux_reset (demux, TRUE);
2243 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2244 && demux->packet >= demux->num_packets)) {
2245 /* do not overshoot data section when streaming */
2249 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2251 /* FIXME: We should tally up fatal errors and error out only
2252 * after a few broken packets in a row? */
2253 err = gst_asf_demux_parse_packet (demux, buf);
2255 gst_buffer_unref (buf);
2257 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2258 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2260 GST_WARNING_OBJECT (demux, "Parse error");
2262 if (demux->packet >= 0)
2265 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2266 && demux->packet >= demux->num_packets)) {
2267 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2272 g_assert_not_reached ();
2276 if (ret != GST_FLOW_OK)
2277 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2283 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2289 static inline gboolean
2290 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2292 if (*p_size < num_bytes)
2295 *p_data += num_bytes;
2296 *p_size -= num_bytes;
2300 static inline guint8
2301 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2305 g_assert (*p_size >= 1);
2306 ret = GST_READ_UINT8 (*p_data);
2307 *p_data += sizeof (guint8);
2308 *p_size -= sizeof (guint8);
2312 static inline guint16
2313 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2317 g_assert (*p_size >= 2);
2318 ret = GST_READ_UINT16_LE (*p_data);
2319 *p_data += sizeof (guint16);
2320 *p_size -= sizeof (guint16);
2324 static inline guint32
2325 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2329 g_assert (*p_size >= 4);
2330 ret = GST_READ_UINT32_LE (*p_data);
2331 *p_data += sizeof (guint32);
2332 *p_size -= sizeof (guint32);
2336 static inline guint64
2337 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2341 g_assert (*p_size >= 8);
2342 ret = GST_READ_UINT64_LE (*p_data);
2343 *p_data += sizeof (guint64);
2344 *p_size -= sizeof (guint64);
2349 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2350 guint8 ** p_data, guint64 * p_size)
2354 if (*p_size < num_bytes_to_read)
2357 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2358 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2360 *p_data += num_bytes_to_read;
2361 *p_size -= num_bytes_to_read;
2367 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2368 guint8 ** p_data, guint64 * p_size)
2372 if (*p_size < num_bytes_to_read)
2375 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2376 *p_data += num_bytes_to_read;
2377 *p_size -= num_bytes_to_read;
2382 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2383 guint8 ** p_data, guint64 * p_size)
2393 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2396 *p_strlen = s_length;
2398 if (s_length == 0) {
2399 GST_WARNING ("zero-length string");
2400 *p_str = g_strdup ("");
2404 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2407 g_assert (s != NULL);
2409 /* just because They don't exist doesn't
2410 * mean They are not out to get you ... */
2411 if (s[s_length - 1] != '\0') {
2412 s = g_realloc (s, s_length + 1);
2416 *p_str = (gchar *) s;
2422 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2424 g_assert (*p_size >= 4 * sizeof (guint32));
2426 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2427 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2428 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2429 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2433 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2436 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2439 /* WAVEFORMATEX Structure */
2440 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2441 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2442 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2443 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2444 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2445 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2446 /* Codec specific data size */
2447 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2452 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2455 if (*p_size < (4 + 4 + 1 + 2))
2458 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2459 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2460 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2461 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2466 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2467 guint8 ** p_data, guint64 * p_size)
2469 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2472 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2473 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2474 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2475 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2476 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2477 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2478 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2479 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2480 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2481 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2482 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2487 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2491 for (i = 0; i < demux->num_streams; i++) {
2492 if (demux->stream[i].id == id)
2493 return &demux->stream[i];
2496 if (gst_asf_demux_is_unknown_stream (demux, id))
2497 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2502 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2503 GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2508 gst_pad_use_fixed_caps (src_pad);
2509 gst_pad_set_caps (src_pad, caps);
2511 gst_pad_set_event_function (src_pad,
2512 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2513 gst_pad_set_query_function (src_pad,
2514 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2516 stream = &demux->stream[demux->num_streams];
2517 stream->caps = caps;
2518 stream->pad = src_pad;
2520 stream->fps_known = !is_video; /* bit hacky for audio */
2521 stream->is_video = is_video;
2522 stream->pending_tags = tags;
2523 stream->discont = TRUE;
2524 stream->first_buffer = TRUE;
2525 stream->streamheader = streamheader;
2526 if (stream->streamheader) {
2527 stream->streamheader = gst_buffer_make_writable (streamheader);
2528 GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2533 st = gst_caps_get_structure (caps, 0);
2534 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2535 par_x > 0 && par_y > 0) {
2536 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2537 stream->par_x = par_x;
2538 stream->par_y = par_y;
2542 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2544 /* TODO: create this array during reverse play? */
2545 stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2547 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2548 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2550 ++demux->num_streams;
2552 stream->active = FALSE;
2558 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2559 GstBuffer * buffer, GstStructure * structure)
2561 GValue arr_val = G_VALUE_INIT;
2562 GValue buf_val = G_VALUE_INIT;
2564 g_value_init (&arr_val, GST_TYPE_ARRAY);
2565 g_value_init (&buf_val, GST_TYPE_BUFFER);
2567 gst_value_set_buffer (&buf_val, buffer);
2568 gst_value_array_append_and_take_value (&arr_val, &buf_val);
2570 gst_structure_take_value (structure, "streamheader", &arr_val);
2574 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2575 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2577 GstTagList *tags = NULL;
2578 GstBuffer *extradata = NULL;
2581 guint16 size_left = 0;
2582 gchar *codec_name = NULL;
2585 size_left = audio->size;
2587 /* Create the audio pad */
2588 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2590 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2593 /* Swallow up any left over data and set up the
2594 * standard properties from the header info */
2596 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2597 "codec specific data", size_left);
2599 g_assert (size_left <= *p_size);
2600 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2603 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2604 * additional two bytes indicating extradata. */
2605 /* FIXME: Handle the channel reorder map here */
2606 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2607 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2610 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2611 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2614 /* Informing about that audio format we just added */
2616 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2617 g_free (codec_name);
2621 gst_buffer_unref (extradata);
2623 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2624 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2625 audio->codec_tag, tags);
2627 ++demux->num_audio_streams;
2629 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2633 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2634 asf_stream_video_format * video, guint16 id,
2635 guint8 ** p_data, guint64 * p_size)
2637 GstTagList *tags = NULL;
2638 GstStructure *caps_s;
2639 GstBuffer *extradata = NULL;
2644 gchar *codec_name = NULL;
2645 gint size_left = video->size - 40;
2646 GstBuffer *streamheader = NULL;
2647 guint par_w = 1, par_h = 1;
2649 /* Create the video pad */
2650 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2651 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2654 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2656 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2657 g_assert (size_left <= *p_size);
2658 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2661 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2663 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2664 caps = gst_riff_create_video_caps (video->tag, NULL,
2665 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2668 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2669 G_TYPE_UINT, video->tag, NULL);
2674 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2675 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2676 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2679 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2683 /* retry with the global metadata */
2684 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2685 demux->global_metadata);
2686 s = demux->global_metadata;
2687 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2688 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2689 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2690 if (ax > 0 && ay > 0) {
2693 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2698 s = gst_caps_get_structure (caps, 0);
2699 gst_structure_remove_field (s, "framerate");
2702 caps_s = gst_caps_get_structure (caps, 0);
2704 /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2705 if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2706 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2707 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2710 /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2711 } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2712 const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2714 GstBuffer *buf = gst_value_get_buffer (value);
2717 if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2718 if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2719 /* this looks like a bytestream start */
2720 streamheader = gst_buffer_ref (buf);
2721 gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2722 gst_structure_remove_field (caps_s, "codec_data");
2725 gst_buffer_unmap (buf, &mapinfo);
2730 /* For a 3D video, set multiview information into the caps based on
2731 * what was detected during object parsing */
2732 if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2733 GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2734 GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2735 const gchar *mview_mode_str;
2737 switch (demux->asf_3D_mode) {
2738 case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2739 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2741 case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2742 mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2743 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2745 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2746 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2748 case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2749 mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2750 mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2752 case GST_ASF_3D_DUAL_STREAM:{
2753 gboolean is_right_view = FALSE;
2754 /* if Advanced_Mutual_Exclusion object exists, use it
2755 * to figure out which is the left view (lower ID) */
2756 if (demux->mut_ex_streams != NULL) {
2760 length = g_slist_length (demux->mut_ex_streams);
2762 for (i = 0; i < length; i++) {
2765 v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2767 GST_DEBUG_OBJECT (demux,
2768 "has Mutual_Exclusion object. stream id in object is %d",
2769 GPOINTER_TO_INT (v_s_id));
2771 if (id > GPOINTER_TO_INT (v_s_id))
2772 is_right_view = TRUE;
2775 /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2776 * first video stream encountered has the lower ID */
2777 if (demux->num_video_streams > 0) {
2778 /* This is not the first video stream, assuming right eye view */
2779 is_right_view = TRUE;
2783 mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2785 mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2792 GST_INFO_OBJECT (demux,
2793 "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2796 mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2797 if (mview_mode_str != NULL) {
2798 if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2799 video->height, par_w, par_h))
2800 mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2802 gst_caps_set_simple (caps,
2803 "multiview-mode", G_TYPE_STRING, mview_mode_str,
2804 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2805 GST_FLAG_SET_MASK_EXACT, NULL);
2810 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2811 g_free (codec_name);
2815 gst_buffer_unref (extradata);
2817 GST_INFO ("Adding video stream #%u, id %u, codec %"
2818 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2819 GST_FOURCC_ARGS (video->tag), video->tag);
2821 ++demux->num_video_streams;
2823 return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2824 streamheader, tags);
2828 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2830 if (!stream->active) {
2834 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2835 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2836 gst_pad_set_active (stream->pad, TRUE);
2839 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2840 "%03u", stream->id);
2843 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2845 if (gst_event_parse_group_id (event, &demux->group_id))
2846 demux->have_group_id = TRUE;
2848 demux->have_group_id = FALSE;
2849 gst_event_unref (event);
2850 } else if (!demux->have_group_id) {
2851 demux->have_group_id = TRUE;
2852 demux->group_id = gst_util_group_id_next ();
2855 event = gst_event_new_stream_start (stream_id);
2856 if (demux->have_group_id)
2857 gst_event_set_group_id (event, demux->group_id);
2859 gst_pad_push_event (stream->pad, event);
2861 gst_pad_set_caps (stream->pad, stream->caps);
2863 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2864 gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2865 stream->active = TRUE;
2870 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2873 AsfCorrectionType correction_type;
2874 AsfStreamType stream_type;
2875 GstClockTime time_offset;
2876 gboolean is_encrypted G_GNUC_UNUSED;
2880 guint stream_specific_size;
2881 guint type_specific_size G_GNUC_UNUSED;
2882 guint unknown G_GNUC_UNUSED;
2883 gboolean inspect_payload = FALSE;
2884 AsfStream *stream = NULL;
2886 /* Get the rest of the header's header */
2887 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2888 goto not_enough_data;
2890 gst_asf_demux_get_guid (&guid, &data, &size);
2891 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2893 gst_asf_demux_get_guid (&guid, &data, &size);
2894 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2896 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2898 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2899 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2901 flags = gst_asf_demux_get_uint16 (&data, &size);
2902 stream_id = flags & 0x7f;
2903 is_encrypted = ! !((flags & 0x8000) << 15);
2904 unknown = gst_asf_demux_get_uint32 (&data, &size);
2906 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2907 stream_id, GST_TIME_ARGS (time_offset));
2909 /* dvr-ms has audio stream declared in stream specific data */
2910 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2911 AsfExtStreamType ext_stream_type;
2912 gst_asf_demux_get_guid (&guid, &data, &size);
2913 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2915 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2916 inspect_payload = TRUE;
2918 gst_asf_demux_get_guid (&guid, &data, &size);
2919 gst_asf_demux_get_uint32 (&data, &size);
2920 gst_asf_demux_get_uint32 (&data, &size);
2921 gst_asf_demux_get_uint32 (&data, &size);
2922 gst_asf_demux_get_guid (&guid, &data, &size);
2923 gst_asf_demux_get_uint32 (&data, &size);
2924 stream_type = ASF_STREAM_AUDIO;
2928 switch (stream_type) {
2929 case ASF_STREAM_AUDIO:{
2930 asf_stream_audio audio_object;
2932 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2933 goto not_enough_data;
2935 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2938 stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2941 switch (correction_type) {
2942 case ASF_CORRECTION_ON:{
2943 guint span, packet_size, chunk_size, data_size, silence_data;
2945 GST_INFO ("Using error correction");
2947 if (size < (1 + 2 + 2 + 2 + 1))
2948 goto not_enough_data;
2950 span = gst_asf_demux_get_uint8 (&data, &size);
2951 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2952 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2953 data_size = gst_asf_demux_get_uint16 (&data, &size);
2954 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2956 stream->span = span;
2958 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2959 packet_size, chunk_size, data_size, span, silence_data);
2961 if (stream->span > 1) {
2962 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2963 /* Disable descrambling */
2966 /* FIXME: this else branch was added for
2967 * weird_al_yankovic - the saga begins.asf */
2968 stream->ds_packet_size = packet_size;
2969 stream->ds_chunk_size = chunk_size;
2972 /* Descambling is enabled */
2973 stream->ds_packet_size = packet_size;
2974 stream->ds_chunk_size = chunk_size;
2977 /* Now skip the rest of the silence data */
2979 gst_bytestream_flush (demux->bs, data_size - 1);
2981 /* FIXME: CHECKME. And why -1? */
2982 if (data_size > 1) {
2983 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2984 goto not_enough_data;
2990 case ASF_CORRECTION_OFF:{
2991 GST_INFO ("Error correction off");
2992 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2993 goto not_enough_data;
2997 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2998 ("Audio stream using unknown error correction"));
3005 case ASF_STREAM_VIDEO:{
3006 asf_stream_video_format video_format_object;
3007 asf_stream_video video_object;
3010 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3011 goto not_enough_data;
3013 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
3015 GST_INFO ("object is a video stream with %u bytes of "
3016 "additional data", vsize);
3018 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3020 goto not_enough_data;
3023 stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3024 stream_id, &data, &size);
3030 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3032 demux->other_streams =
3033 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3038 stream->inspect_payload = inspect_payload;
3043 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3044 /* we'll error out later if we found no streams */
3049 static const gchar *
3050 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3054 const gchar *asf_name;
3055 const gchar *gst_name;
3058 "WM/Genre", GST_TAG_GENRE}, {
3059 "WM/AlbumTitle", GST_TAG_ALBUM}, {
3060 "WM/AlbumArtist", GST_TAG_ARTIST}, {
3061 "WM/Picture", GST_TAG_IMAGE}, {
3062 "WM/Track", GST_TAG_TRACK_NUMBER}, {
3063 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3064 "WM/Year", GST_TAG_DATE_TIME}
3065 /* { "WM/Composer", GST_TAG_COMPOSER } */
3070 if (name_utf8 == NULL) {
3071 GST_WARNING ("Failed to convert name to UTF8, skipping");
3075 out = strlen (name_utf8);
3077 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3078 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3079 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3080 return tags[i].gst_name;
3087 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3089 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3093 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3095 if (taglist == NULL)
3098 if (gst_tag_list_is_empty (taglist)) {
3099 gst_tag_list_unref (taglist);
3103 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3104 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3106 gst_tag_list_unref (demux->taglist);
3107 gst_tag_list_unref (taglist);
3109 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3112 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
3113 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
3114 #define ASF_DEMUX_DATA_TYPE_BOOL 2
3115 #define ASF_DEMUX_DATA_TYPE_DWORD 3
3118 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3122 const guint8 *img_data = NULL;
3123 guint32 img_data_len = 0;
3124 guint8 pic_type = 0;
3126 gst_byte_reader_init (&r, tag_data, tag_data_len);
3128 /* skip mime type string (we don't trust it and do our own typefinding),
3129 * and also skip the description string, since we don't use it */
3130 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3131 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3132 !gst_byte_reader_skip_string_utf16 (&r) ||
3133 !gst_byte_reader_skip_string_utf16 (&r) ||
3134 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3135 goto not_enough_data;
3139 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3140 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3146 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3147 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3152 /* Extended Content Description Object */
3153 static GstFlowReturn
3154 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3157 /* Other known (and unused) 'text/unicode' metadata available :
3160 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3161 * WMFSDKVersion = 9.00.00.2980
3162 * WMFSDKNeeded = 0.0.0.0000
3163 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
3164 * WM/Publisher = 4AD
3166 * WM/ProviderRating = 8
3167 * WM/ProviderStyle = Rock (similar to WM/Genre)
3168 * WM/GenreID (similar to WM/Genre)
3169 * WM/TrackNumber (same as WM/Track but as a string)
3171 * Other known (and unused) 'non-text' metadata available :
3177 * We might want to read WM/TrackNumber and use atoi() if we don't have
3181 GstTagList *taglist;
3182 guint16 blockcount, i;
3183 gboolean content3D = FALSE;
3187 const gchar *interleave_name;
3188 GstASF3DMode interleaving_type;
3189 } stereoscopic_layout_map[] = {
3191 "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3192 "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3193 "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3194 "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3195 "DualStream", GST_ASF_3D_DUAL_STREAM}
3197 GST_INFO_OBJECT (demux, "object is an extended content description");
3199 taglist = gst_tag_list_new_empty ();
3201 /* Content Descriptor Count */
3203 goto not_enough_data;
3205 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3207 for (i = 1; i <= blockcount; ++i) {
3208 const gchar *gst_tag_name;
3212 GValue tag_value = { 0, };
3215 gchar *name_utf8 = NULL;
3219 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3220 goto not_enough_data;
3224 goto not_enough_data;
3226 /* Descriptor Value Data Type */
3227 datatype = gst_asf_demux_get_uint16 (&data, &size);
3229 /* Descriptor Value (not really a string, but same thing reading-wise) */
3230 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3232 goto not_enough_data;
3236 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3238 if (name_utf8 != NULL) {
3239 GST_DEBUG ("Found tag/metadata %s", name_utf8);
3241 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3242 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3245 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3248 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3251 /* get rid of tags with empty value */
3252 if (value_utf8 != NULL && *value_utf8 != '\0') {
3253 GST_DEBUG ("string value %s", value_utf8);
3255 value_utf8[out] = '\0';
3257 if (gst_tag_name != NULL) {
3258 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3259 guint year = atoi (value_utf8);
3262 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3263 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3265 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3266 guint id3v1_genre_id;
3267 const gchar *genre_str;
3269 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3270 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3271 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3272 g_free (value_utf8);
3273 value_utf8 = g_strdup (genre_str);
3278 /* convert tag from string to other type if required */
3279 tag_type = gst_tag_get_type (gst_tag_name);
3280 g_value_init (&tag_value, tag_type);
3281 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3282 GValue from_val = { 0, };
3284 g_value_init (&from_val, G_TYPE_STRING);
3285 g_value_set_string (&from_val, value_utf8);
3286 if (!g_value_transform (&from_val, &tag_value)) {
3287 GST_WARNING_OBJECT (demux,
3288 "Could not transform string tag to " "%s tag type %s",
3289 gst_tag_name, g_type_name (tag_type));
3290 g_value_unset (&tag_value);
3292 g_value_unset (&from_val);
3297 GST_DEBUG ("Setting metadata");
3298 g_value_init (&tag_value, G_TYPE_STRING);
3299 g_value_set_string (&tag_value, value_utf8);
3300 /* If we found a stereoscopic marker, look for StereoscopicLayout
3304 if (strncmp ("StereoscopicLayout", name_utf8,
3305 strlen (name_utf8)) == 0) {
3306 for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3307 if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3309 demux->asf_3D_mode =
3310 stereoscopic_layout_map[i].interleaving_type;
3311 GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3315 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3317 demux->asf_3D_mode = GST_ASF_3D_NONE;
3318 GST_INFO_OBJECT (demux, "None 3d type");
3321 } else if (value_utf8 == NULL) {
3322 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3324 GST_DEBUG ("Skipping empty string value for %s",
3325 GST_STR_NULL (gst_tag_name));
3327 g_free (value_utf8);
3330 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3332 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3333 GST_FIXME ("Unhandled byte array tag %s",
3334 GST_STR_NULL (gst_tag_name));
3337 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3343 case ASF_DEMUX_DATA_TYPE_DWORD:{
3344 guint uint_val = GST_READ_UINT32_LE (value);
3346 /* this is the track number */
3347 g_value_init (&tag_value, G_TYPE_UINT);
3349 /* WM/Track counts from 0 */
3350 if (!strcmp (name_utf8, "WM/Track"))
3353 g_value_set_uint (&tag_value, uint_val);
3357 case ASF_DEMUX_DATA_TYPE_BOOL:{
3358 gboolean bool_val = GST_READ_UINT32_LE (value);
3360 if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3362 GST_INFO_OBJECT (demux, "This is 3D contents");
3365 GST_INFO_OBJECT (demux, "This is not 3D contenst");
3373 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3378 if (G_IS_VALUE (&tag_value)) {
3380 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3382 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3383 * is supposed to have a 0 base but is often wrongly written to start
3384 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3385 * replace the value added earlier from WM/Track or put it first in
3386 * the list, so that it will get picked up by _get_uint() */
3387 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3388 merge_mode = GST_TAG_MERGE_REPLACE;
3390 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3393 GST_DEBUG ("Setting global metadata %s", name_utf8);
3394 gst_structure_set_value (demux->global_metadata, name_utf8,
3398 g_value_unset (&tag_value);
3407 gst_asf_demux_add_global_tags (demux, taglist);
3414 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3415 gst_tag_list_unref (taglist);
3416 return GST_FLOW_OK; /* not really fatal */
3420 static GstStructure *
3421 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3426 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3428 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3431 s = gst_caps_get_structure (demux->metadata, i);
3432 if (gst_structure_has_name (s, sname))
3436 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3438 /* try lookup again; demux->metadata took ownership of the structure, so we
3439 * can't really make any assumptions about what happened to it, so we can't
3440 * just return it directly after appending it */
3441 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3444 static GstFlowReturn
3445 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3448 guint16 blockcount, i;
3450 GST_INFO_OBJECT (demux, "object is a metadata object");
3452 /* Content Descriptor Count */
3454 goto not_enough_data;
3456 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3458 for (i = 0; i < blockcount; ++i) {
3460 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3461 guint32 data_len, ival;
3464 if (size < (2 + 2 + 2 + 2 + 4))
3465 goto not_enough_data;
3467 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3468 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3469 name_len = gst_asf_demux_get_uint16 (&data, &size);
3470 data_type = gst_asf_demux_get_uint16 (&data, &size);
3471 data_len = gst_asf_demux_get_uint32 (&data, &size);
3473 if (size < name_len + data_len)
3474 goto not_enough_data;
3476 /* convert name to UTF-8 */
3477 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3479 gst_asf_demux_skip_bytes (name_len, &data, &size);
3481 if (name_utf8 == NULL) {
3482 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3483 gst_asf_demux_skip_bytes (data_len, &data, &size);
3487 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3488 gst_asf_demux_skip_bytes (data_len, &data, &size);
3496 goto not_enough_data;
3499 ival = gst_asf_demux_get_uint32 (&data, &size);
3501 /* skip anything else there may be, just in case */
3502 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3504 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3505 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3509 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3515 GST_WARNING ("Unexpected end of data parsing metadata object");
3516 return GST_FLOW_OK; /* not really fatal */
3520 static GstFlowReturn
3521 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3523 GstFlowReturn ret = GST_FLOW_OK;
3524 guint32 i, num_objects;
3525 guint8 unknown G_GNUC_UNUSED;
3527 /* Get the rest of the header's header */
3528 if (size < (4 + 1 + 1))
3529 goto not_enough_data;
3531 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3532 unknown = gst_asf_demux_get_uint8 (&data, &size);
3533 unknown = gst_asf_demux_get_uint8 (&data, &size);
3535 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3537 /* Loop through the header's objects, processing those */
3538 for (i = 0; i < num_objects; ++i) {
3539 GST_INFO_OBJECT (demux, "reading header part %u", i);
3540 ret = gst_asf_demux_process_object (demux, &data, &size);
3541 if (ret != GST_FLOW_OK) {
3542 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3551 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3552 ("short read parsing HEADER object"));
3553 return GST_FLOW_ERROR;
3557 static GstFlowReturn
3558 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3560 guint64 creation_time G_GNUC_UNUSED;
3561 guint64 file_size G_GNUC_UNUSED;
3562 guint64 send_time G_GNUC_UNUSED;
3563 guint64 packets_count, play_time, preroll;
3564 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3566 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3567 goto not_enough_data;
3569 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3570 file_size = gst_asf_demux_get_uint64 (&data, &size);
3571 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3572 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3573 play_time = gst_asf_demux_get_uint64 (&data, &size);
3574 send_time = gst_asf_demux_get_uint64 (&data, &size);
3575 preroll = gst_asf_demux_get_uint64 (&data, &size);
3576 flags = gst_asf_demux_get_uint32 (&data, &size);
3577 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3578 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3579 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3581 demux->broadcast = ! !(flags & 0x01);
3582 demux->seekable = ! !(flags & 0x02);
3584 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3585 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3586 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3588 if (demux->broadcast) {
3589 /* these fields are invalid if the broadcast flag is set */
3594 if (min_pktsize != max_pktsize)
3595 goto non_fixed_packet_size;
3597 demux->packet_size = max_pktsize;
3599 /* FIXME: do we need send_time as well? what is it? */
3600 if ((play_time * 100) >= (preroll * GST_MSECOND))
3601 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3603 demux->play_time = 0;
3605 demux->preroll = preroll * GST_MSECOND;
3607 /* initial latency */
3608 demux->latency = demux->preroll;
3610 if (demux->play_time == 0)
3611 demux->seekable = FALSE;
3613 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3614 GST_TIME_ARGS (demux->play_time));
3615 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3616 GST_TIME_ARGS (demux->preroll));
3618 if (demux->play_time > 0) {
3619 demux->segment.duration = demux->play_time;
3622 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3624 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3629 non_fixed_packet_size:
3631 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3632 ("packet size must be fixed"));
3633 return GST_FLOW_ERROR;
3637 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3638 ("short read parsing FILE object"));
3639 return GST_FLOW_ERROR;
3643 /* Content Description Object */
3644 static GstFlowReturn
3645 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3649 const gchar *gst_tag;
3654 GST_TAG_TITLE, 0, NULL}, {
3655 GST_TAG_ARTIST, 0, NULL}, {
3656 GST_TAG_COPYRIGHT, 0, NULL}, {
3657 GST_TAG_DESCRIPTION, 0, NULL}, {
3658 GST_TAG_COMMENT, 0, NULL}
3660 GstTagList *taglist;
3661 GValue value = { 0 };
3665 GST_INFO_OBJECT (demux, "object is a comment");
3667 if (size < (2 + 2 + 2 + 2 + 2))
3668 goto not_enough_data;
3670 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3671 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3672 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3673 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3674 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3676 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3677 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3678 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3680 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3681 if (size < tags[i].val_length)
3682 goto not_enough_data;
3684 /* might be just '/0', '/0'... */
3685 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3686 /* convert to UTF-8 */
3687 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3688 "UTF-8", "UTF-16LE", &in, &out, NULL);
3690 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3693 /* parse metadata into taglist */
3694 taglist = gst_tag_list_new_empty ();
3695 g_value_init (&value, G_TYPE_STRING);
3696 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3697 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3698 g_value_set_string (&value, tags[i].val_utf8);
3699 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3700 tags[i].gst_tag, &value, NULL);
3703 g_value_unset (&value);
3705 gst_asf_demux_add_global_tags (demux, taglist);
3707 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3708 g_free (tags[i].val_utf8);
3714 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3715 "comment tag section %d, skipping comment object", i);
3716 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3717 g_free (tags[i].val_utf8);
3718 return GST_FLOW_OK; /* not really fatal */
3722 static GstFlowReturn
3723 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3726 guint16 num_streams, i;
3730 goto not_enough_data;
3732 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3734 GST_INFO ("object is a bitrate properties object with %u streams",
3737 if (size < (num_streams * (2 + 4)))
3738 goto not_enough_data;
3740 for (i = 0; i < num_streams; ++i) {
3744 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3745 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3747 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3748 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3749 stream = gst_asf_demux_get_stream (demux, stream_id);
3751 if (stream->pending_tags == NULL)
3752 stream->pending_tags = gst_tag_list_new_empty ();
3753 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3754 GST_TAG_BITRATE, bitrate, NULL);
3756 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3759 GST_WARNING ("stream id %u is too large", stream_id);
3767 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3768 return GST_FLOW_OK; /* not really fatal */
3772 static GstFlowReturn
3773 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3776 GstFlowReturn ret = GST_FLOW_OK;
3779 /* Get the rest of the header's header */
3780 if (size < (16 + 2 + 4))
3781 goto not_enough_data;
3783 /* skip GUID and two other bytes */
3784 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3785 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3787 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3789 /* FIXME: does data_size include the rest of the header that we have read? */
3790 if (hdr_size > size)
3791 goto not_enough_data;
3793 while (hdr_size > 0) {
3794 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3795 if (ret != GST_FLOW_OK)
3803 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3804 ("short read parsing extended header object"));
3805 return GST_FLOW_ERROR;
3809 static GstFlowReturn
3810 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3816 goto not_enough_data;
3818 if (demux->languages) {
3819 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3820 g_strfreev (demux->languages);
3821 demux->languages = NULL;
3822 demux->num_languages = 0;
3825 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3826 GST_LOG ("%u languages:", demux->num_languages);
3828 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3829 for (i = 0; i < demux->num_languages; ++i) {
3830 guint8 len, *lang_data = NULL;
3833 goto not_enough_data;
3834 len = gst_asf_demux_get_uint8 (&data, &size);
3835 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3838 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3841 /* truncate "en-us" etc. to just "en" */
3842 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3845 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3846 demux->languages[i] = utf8;
3849 goto not_enough_data;
3857 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3858 g_free (demux->languages);
3859 demux->languages = NULL;
3860 return GST_FLOW_OK; /* not fatal */
3864 static GstFlowReturn
3865 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3868 GstClockTime interval;
3871 if (size < (16 + 8 + 4 + 4))
3872 goto not_enough_data;
3875 gst_asf_demux_skip_bytes (16, &data, &size);
3876 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3877 gst_asf_demux_skip_bytes (4, &data, &size);
3878 count = gst_asf_demux_get_uint32 (&data, &size);
3880 demux->sidx_interval = interval;
3881 demux->sidx_num_entries = count;
3882 g_free (demux->sidx_entries);
3883 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3885 for (i = 0; i < count; ++i) {
3886 if (G_UNLIKELY (size < 6)) {
3887 /* adjust for broken files, to avoid having entries at the end
3888 * of the parsed index that point to time=0. Resulting in seeking to
3889 * the end of the file leading back to the beginning */
3890 demux->sidx_num_entries -= (count - i);
3893 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3894 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3895 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3896 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3897 demux->sidx_entries[i].count);
3900 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3907 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3908 return GST_FLOW_OK; /* not fatal */
3912 static GstFlowReturn
3913 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3914 guint8 * data, guint64 size)
3919 if (size < 16 + 2 + (2 * 2))
3920 goto not_enough_data;
3922 gst_asf_demux_get_guid (&guid, &data, &size);
3923 num = gst_asf_demux_get_uint16 (&data, &size);
3926 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3930 if (size < (num * sizeof (guint16)))
3931 goto not_enough_data;
3933 /* read mutually exclusive stream numbers */
3934 for (i = 0; i < num; ++i) {
3936 mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3937 GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3939 demux->mut_ex_streams =
3940 g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
3949 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3950 return GST_FLOW_OK; /* not absolutely fatal */
3955 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3957 return g_slist_find (demux->other_streams,
3958 GINT_TO_POINTER (stream_num)) == NULL;
3961 static GstFlowReturn
3962 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3965 AsfStreamExtProps esp;
3966 AsfStream *stream = NULL;
3967 AsfObject stream_obj;
3968 guint16 stream_name_count;
3969 guint16 num_payload_ext;
3971 guint8 *stream_obj_data = NULL;
3974 guint i, stream_num;
3977 obj_size = (guint) size;
3980 goto not_enough_data;
3983 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3984 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3985 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3986 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3987 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3988 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3989 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3990 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3991 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3992 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3993 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3994 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3995 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3996 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3997 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3999 GST_INFO ("start_time = %" GST_TIME_FORMAT,
4000 GST_TIME_ARGS (esp.start_time));
4001 GST_INFO ("end_time = %" GST_TIME_FORMAT,
4002 GST_TIME_ARGS (esp.end_time));
4003 GST_INFO ("flags = %08x", esp.flags);
4004 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4005 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4006 GST_INFO ("stream number = %u", stream_num);
4007 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4008 (esp.lang_idx < demux->num_languages) ?
4009 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4010 GST_INFO ("stream name count = %u", stream_name_count);
4012 /* read stream names */
4013 for (i = 0; i < stream_name_count; ++i) {
4014 guint16 stream_lang_idx G_GNUC_UNUSED;
4015 gchar *stream_name = NULL;
4018 goto not_enough_data;
4019 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4020 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4021 goto not_enough_data;
4022 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4023 g_free (stream_name); /* TODO: store names in struct */
4026 /* read payload extension systems stuff */
4027 GST_LOG ("payload extension systems count = %u", num_payload_ext);
4029 if (num_payload_ext > 0)
4030 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4032 esp.payload_extensions = NULL;
4034 for (i = 0; i < num_payload_ext; ++i) {
4035 AsfPayloadExtension ext;
4037 guint32 sys_info_len;
4039 if (size < 16 + 2 + 4)
4040 goto not_enough_data;
4042 gst_asf_demux_get_guid (&ext_guid, &data, &size);
4043 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4044 ext.len = gst_asf_demux_get_uint16 (&data, &size);
4046 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4047 GST_LOG ("payload systems info len = %u", sys_info_len);
4048 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4049 goto not_enough_data;
4051 esp.payload_extensions[i] = ext;
4054 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4056 /* there might be an optional STREAM_INFO object here now; if not, we
4057 * should have parsed the corresponding stream info object already (since
4058 * we are parsing the extended stream properties objects delayed) */
4060 stream = gst_asf_demux_get_stream (demux, stream_num);
4064 /* get size of the stream object */
4065 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4066 goto not_enough_data;
4068 if (stream_obj.id != ASF_OBJ_STREAM)
4069 goto expected_stream_object;
4071 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4072 stream_obj.size > (10 * 1024 * 1024))
4073 goto not_enough_data;
4075 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4077 /* process this stream object later after all the other 'normal' ones
4078 * have been processed (since the others are more important/non-hidden) */
4079 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4080 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4081 goto not_enough_data;
4083 /* parse stream object */
4084 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4085 g_free (stream_obj_data);
4090 stream->ext_props = esp;
4092 /* try to set the framerate */
4093 if (stream->is_video && stream->caps) {
4094 GValue framerate = { 0 };
4098 g_value_init (&framerate, GST_TYPE_FRACTION);
4100 num = GST_SECOND / 100;
4101 denom = esp.avg_time_per_frame;
4103 /* avoid division by 0, assume 25/1 framerate */
4104 denom = GST_SECOND / 2500;
4107 gst_value_set_fraction (&framerate, num, denom);
4109 stream->caps = gst_caps_make_writable (stream->caps);
4110 s = gst_caps_get_structure (stream->caps, 0);
4111 gst_structure_set_value (s, "framerate", &framerate);
4112 g_value_unset (&framerate);
4113 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4114 num, denom, ((gdouble) num) / denom);
4117 /* add language info now if we have it */
4118 if (stream->ext_props.lang_idx < demux->num_languages) {
4119 if (stream->pending_tags == NULL)
4120 stream->pending_tags = gst_tag_list_new_empty ();
4121 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4122 demux->languages[stream->ext_props.lang_idx]);
4123 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4124 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4127 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4128 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4136 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4137 return GST_FLOW_OK; /* not absolutely fatal */
4139 expected_stream_object:
4141 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4142 "object: expected embedded stream object, but got %s object instead!",
4143 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4144 return GST_FLOW_OK; /* not absolutely fatal */
4148 static const gchar *
4149 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4153 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4154 if (g_str_has_prefix (nick, "ASF_OBJ_"))
4155 nick += strlen ("ASF_OBJ_");
4157 if (demux->objpath == NULL) {
4158 demux->objpath = g_strdup (nick);
4162 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4163 g_free (demux->objpath);
4164 demux->objpath = newpath;
4167 return (const gchar *) demux->objpath;
4171 gst_asf_demux_pop_obj (GstASFDemux * demux)
4175 if ((s = g_strrstr (demux->objpath, "/"))) {
4178 g_free (demux->objpath);
4179 demux->objpath = NULL;
4184 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4189 /* Parse the queued extended stream property objects and add the info
4190 * to the existing streams or add the new embedded streams, but without
4191 * activating them yet */
4192 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4193 g_slist_length (demux->ext_stream_props));
4195 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4196 GstBuffer *buf = GST_BUFFER (l->data);
4199 gst_buffer_map (buf, &map, GST_MAP_READ);
4201 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4202 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4203 gst_buffer_unmap (buf, &map);
4204 gst_buffer_unref (buf);
4206 g_slist_free (demux->ext_stream_props);
4207 demux->ext_stream_props = NULL;
4212 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4216 for (i = 0; i < demux->num_streams; ++i) {
4221 stream = &demux->stream[i];
4223 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
4225 if (stream->active) {
4226 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4231 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4234 /* check for each mutual exclusion whether it affects this stream */
4235 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4236 if (*mes == stream->id) {
4237 /* if yes, check if we've already added streams that are mutually
4238 * exclusive with the stream we're about to add */
4239 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4240 for (j = 0; j < demux->num_streams; ++j) {
4241 /* if the broadcast flag is set, assume the hidden streams aren't
4242 * actually streamed and hide them (or playbin won't work right),
4243 * otherwise assume their data is available */
4244 if (demux->stream[j].id == *mes && demux->broadcast) {
4246 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4247 "mutually exclusive with already existing stream ID %d, "
4248 "hiding stream", stream->id, demux->stream[j].id);
4260 /* FIXME: we should do stream activation based on preroll data in
4261 * streaming mode too */
4262 if (demux->streaming && !is_hidden)
4263 gst_asf_demux_activate_stream (demux, stream);
4268 static GstFlowReturn
4269 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4272 GstFlowReturn ret = GST_FLOW_OK;
4274 guint64 obj_data_size;
4276 if (*p_size < ASF_OBJECT_HEADER_SIZE)
4277 return ASF_FLOW_NEED_MORE_DATA;
4279 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4280 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4282 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4284 if (*p_size < obj_data_size)
4285 return ASF_FLOW_NEED_MORE_DATA;
4287 gst_asf_demux_push_obj (demux, obj.id);
4289 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4292 case ASF_OBJ_STREAM:
4293 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4297 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4299 case ASF_OBJ_HEADER:
4300 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4302 case ASF_OBJ_COMMENT:
4303 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4306 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4308 case ASF_OBJ_BITRATE_PROPS:
4310 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4313 case ASF_OBJ_EXT_CONTENT_DESC:
4315 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4318 case ASF_OBJ_METADATA_OBJECT:
4319 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4321 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4324 /* process these later, we might not have parsed the corresponding
4325 * stream object yet */
4326 GST_LOG ("%s: queued for later parsing", demux->objpath);
4327 buf = gst_buffer_new_and_alloc (obj_data_size);
4328 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4329 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4333 case ASF_OBJ_LANGUAGE_LIST:
4334 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4336 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4337 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4340 case ASF_OBJ_SIMPLE_INDEX:
4341 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4343 case ASF_OBJ_CONTENT_ENCRYPTION:
4344 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4345 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4346 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4347 goto error_encrypted;
4348 case ASF_OBJ_CONCEAL_NONE:
4350 case ASF_OBJ_UNDEFINED:
4351 case ASF_OBJ_CODEC_COMMENT:
4353 case ASF_OBJ_PADDING:
4354 case ASF_OBJ_BITRATE_MUTEX:
4355 case ASF_OBJ_COMPATIBILITY:
4356 case ASF_OBJ_INDEX_PLACEHOLDER:
4357 case ASF_OBJ_INDEX_PARAMETERS:
4358 case ASF_OBJ_STREAM_PRIORITIZATION:
4359 case ASF_OBJ_SCRIPT_COMMAND:
4360 case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4362 /* Unknown/unhandled object, skip it and hope for the best */
4363 GST_INFO ("%s: skipping object", demux->objpath);
4368 /* this can't fail, we checked the number of bytes available before */
4369 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4371 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4373 gst_asf_demux_pop_obj (demux);
4380 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4381 return GST_FLOW_ERROR;
4386 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4387 GstBuffer ** p_buffer)
4389 GstBuffer *descrambled_buffer;
4390 GstBuffer *scrambled_buffer;
4391 GstBuffer *sub_buffer;
4398 /* descrambled_buffer is initialised in the first iteration */
4399 descrambled_buffer = NULL;
4400 scrambled_buffer = *p_buffer;
4402 if (gst_buffer_get_size (scrambled_buffer) <
4403 stream->ds_packet_size * stream->span)
4406 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4407 offset += stream->ds_chunk_size) {
4408 off = offset / stream->ds_chunk_size;
4409 row = off / stream->span;
4410 col = off % stream->span;
4411 idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4412 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4413 col, off, stream->ds_chunk_size);
4414 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4415 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4416 stream->span, stream->ds_packet_size);
4417 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4418 gst_buffer_get_size (scrambled_buffer));
4420 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4421 idx * stream->ds_chunk_size, stream->ds_chunk_size);
4423 descrambled_buffer = sub_buffer;
4425 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4429 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4430 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4431 GST_BUFFER_DURATION (descrambled_buffer) =
4432 GST_BUFFER_DURATION (scrambled_buffer);
4433 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4434 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4435 GST_BUFFER_OFFSET_END (scrambled_buffer);
4437 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4439 gst_buffer_unref (scrambled_buffer);
4440 *p_buffer = descrambled_buffer;
4444 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4446 GstASFDemux *demux = GST_ASF_DEMUX (element);
4449 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4451 for (i = 0; i < demux->num_streams; ++i) {
4452 gst_event_ref (event);
4453 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4454 GST_OBJECT_CAST (element), event)) {
4455 gst_event_unref (event);
4460 gst_event_unref (event);
4464 /* takes ownership of the passed event */
4466 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4468 gboolean ret = TRUE;
4471 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4472 GST_EVENT_TYPE_NAME (event));
4474 for (i = 0; i < demux->num_streams; ++i) {
4475 gst_event_ref (event);
4476 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4478 gst_event_unref (event);
4483 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4487 gboolean res = FALSE;
4489 demux = GST_ASF_DEMUX (parent);
4491 GST_DEBUG ("handling %s query",
4492 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4494 switch (GST_QUERY_TYPE (query)) {
4495 case GST_QUERY_DURATION:
4499 gst_query_parse_duration (query, &format, NULL);
4501 if (format != GST_FORMAT_TIME) {
4502 GST_LOG ("only support duration queries in TIME format");
4506 res = gst_pad_query_default (pad, parent, query);
4508 GST_OBJECT_LOCK (demux);
4510 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4511 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4512 GST_TIME_ARGS (demux->segment.duration));
4514 gst_query_set_duration (query, GST_FORMAT_TIME,
4515 demux->segment.duration);
4519 GST_LOG ("duration not known yet");
4522 GST_OBJECT_UNLOCK (demux);
4527 case GST_QUERY_POSITION:{
4530 gst_query_parse_position (query, &format, NULL);
4532 if (format != GST_FORMAT_TIME) {
4533 GST_LOG ("only support position queries in TIME format");
4537 GST_OBJECT_LOCK (demux);
4539 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4540 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4541 GST_TIME_ARGS (demux->segment.position));
4543 gst_query_set_position (query, GST_FORMAT_TIME,
4544 demux->segment.position);
4548 GST_LOG ("position not known yet");
4551 GST_OBJECT_UNLOCK (demux);
4555 case GST_QUERY_SEEKING:{
4558 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4559 if (format == GST_FORMAT_TIME) {
4562 GST_OBJECT_LOCK (demux);
4563 duration = demux->segment.duration;
4564 GST_OBJECT_UNLOCK (demux);
4566 if (!demux->streaming || !demux->seekable) {
4567 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4574 /* try upstream first in TIME */
4575 res = gst_pad_query_default (pad, parent, query);
4577 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4578 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4579 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4580 /* if no luck, maybe in BYTES */
4581 if (!seekable || fmt != GST_FORMAT_TIME) {
4584 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4585 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4586 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4587 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4588 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4589 if (fmt != GST_FORMAT_BYTES)
4592 gst_query_unref (q);
4593 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4599 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4603 case GST_QUERY_LATENCY:
4606 GstClockTime min, max;
4608 /* preroll delay does not matter in non-live pipeline,
4609 * but we might end up in a live (rtsp) one ... */
4612 res = gst_pad_query_default (pad, parent, query);
4616 gst_query_parse_latency (query, &live, &min, &max);
4618 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4619 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4620 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4622 GST_OBJECT_LOCK (demux);
4623 min += demux->latency;
4625 max += demux->latency;
4626 GST_OBJECT_UNLOCK (demux);
4628 gst_query_set_latency (query, live, min, max);
4631 case GST_QUERY_SEGMENT:
4636 format = demux->segment.format;
4639 gst_segment_to_stream_time (&demux->segment, format,
4640 demux->segment.start);
4641 if ((stop = demux->segment.stop) == -1)
4642 stop = demux->segment.duration;
4644 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4646 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4651 res = gst_pad_query_default (pad, parent, query);
4658 static GstStateChangeReturn
4659 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4661 GstASFDemux *demux = GST_ASF_DEMUX (element);
4662 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4664 switch (transition) {
4665 case GST_STATE_CHANGE_NULL_TO_READY:{
4666 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4667 demux->need_newsegment = TRUE;
4668 demux->segment_running = FALSE;
4669 demux->keyunit_sync = FALSE;
4670 demux->adapter = gst_adapter_new ();
4671 demux->metadata = gst_caps_new_empty ();
4672 demux->global_metadata = gst_structure_new_empty ("metadata");
4673 demux->data_size = 0;
4674 demux->data_offset = 0;
4675 demux->index_offset = 0;
4676 demux->base_offset = 0;
4677 demux->flowcombiner = gst_flow_combiner_new ();
4685 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4686 if (ret == GST_STATE_CHANGE_FAILURE)
4689 switch (transition) {
4690 case GST_STATE_CHANGE_PAUSED_TO_READY:
4691 gst_asf_demux_reset (demux, FALSE);
4694 case GST_STATE_CHANGE_READY_TO_NULL:
4695 gst_asf_demux_reset (demux, FALSE);
4696 gst_flow_combiner_free (demux->flowcombiner);
4697 demux->flowcombiner = NULL;