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>
45 #include "gstasfdemux.h"
46 #include "asfheaders.h"
47 #include "asfpacket.h"
49 static GstStaticPadTemplate gst_asf_demux_sink_template =
50 GST_STATIC_PAD_TEMPLATE ("sink",
53 GST_STATIC_CAPS ("video/x-ms-asf")
56 static GstStaticPadTemplate audio_src_template =
57 GST_STATIC_PAD_TEMPLATE ("audio_%u",
62 static GstStaticPadTemplate video_src_template =
63 GST_STATIC_PAD_TEMPLATE ("video_%u",
68 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
69 #define ASF_OBJECT_HEADER_SIZE (16+8)
71 /* FIXME: get rid of this */
72 /* abuse this GstFlowReturn enum for internal usage */
73 #define ASF_FLOW_NEED_MORE_DATA 99
75 #define gst_asf_get_flow_name(flow) \
76 (flow == ASF_FLOW_NEED_MORE_DATA) ? \
77 "need-more-data" : gst_flow_get_name (flow)
79 GST_DEBUG_CATEGORY (asfdemux_dbg);
81 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
82 GstStateChange transition);
83 static gboolean gst_asf_demux_element_send_event (GstElement * element,
85 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
87 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
88 GstObject * parent, GstQuery * query);
89 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
91 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
93 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
94 guint8 ** p_data, guint64 * p_size);
95 static gboolean gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent);
96 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
97 GstObject * parent, GstPadMode mode, gboolean active);
98 static void gst_asf_demux_loop (GstASFDemux * demux);
100 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
101 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
102 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
103 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
105 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
106 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
107 AsfStream * stream, GstBuffer ** p_buffer);
108 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
110 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
112 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
115 #define gst_asf_demux_parent_class parent_class
116 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
119 gst_asf_demux_class_init (GstASFDemuxClass * klass)
121 GstElementClass *gstelement_class;
123 gstelement_class = (GstElementClass *) klass;
125 gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
127 "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
129 gst_element_class_add_pad_template (gstelement_class,
130 gst_static_pad_template_get (&audio_src_template));
131 gst_element_class_add_pad_template (gstelement_class,
132 gst_static_pad_template_get (&video_src_template));
133 gst_element_class_add_pad_template (gstelement_class,
134 gst_static_pad_template_get (&gst_asf_demux_sink_template));
136 gstelement_class->change_state =
137 GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
138 gstelement_class->send_event =
139 GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
143 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
145 gst_caps_replace (&stream->caps, NULL);
146 if (stream->pending_tags) {
147 gst_tag_list_unref (stream->pending_tags);
148 stream->pending_tags = NULL;
152 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
154 gst_object_unref (stream->pad);
158 while (stream->payloads->len > 0) {
162 last = stream->payloads->len - 1;
163 payload = &g_array_index (stream->payloads, AsfPayload, last);
164 gst_buffer_replace (&payload->buf, NULL);
165 g_array_remove_index (stream->payloads, last);
167 if (stream->payloads) {
168 g_array_free (stream->payloads, TRUE);
169 stream->payloads = NULL;
171 if (stream->ext_props.valid) {
172 g_free (stream->ext_props.payload_extensions);
173 stream->ext_props.payload_extensions = NULL;
178 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
180 GST_LOG_OBJECT (demux, "resetting");
182 gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
183 demux->segment_running = FALSE;
184 if (demux->adapter && !chain_reset) {
185 gst_adapter_clear (demux->adapter);
186 g_object_unref (demux->adapter);
187 demux->adapter = NULL;
189 if (demux->taglist) {
190 gst_tag_list_unref (demux->taglist);
191 demux->taglist = NULL;
193 if (demux->metadata) {
194 gst_caps_unref (demux->metadata);
195 demux->metadata = NULL;
197 if (demux->global_metadata) {
198 gst_structure_free (demux->global_metadata);
199 demux->global_metadata = NULL;
202 demux->state = GST_ASF_DEMUX_STATE_HEADER;
203 g_free (demux->objpath);
204 demux->objpath = NULL;
205 g_strfreev (demux->languages);
206 demux->languages = NULL;
207 demux->num_languages = 0;
208 g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
210 g_slist_free (demux->ext_stream_props);
211 demux->ext_stream_props = NULL;
213 while (demux->old_num_streams > 0) {
214 gst_asf_demux_free_stream (demux,
215 &demux->old_stream[demux->old_num_streams - 1]);
216 --demux->old_num_streams;
218 memset (demux->old_stream, 0, sizeof (demux->old_stream));
219 demux->old_num_streams = 0;
221 /* when resetting for a new chained asf, we don't want to remove the pads
222 * before adding the new ones */
224 memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
225 demux->old_num_streams = demux->num_streams;
226 demux->num_streams = 0;
229 while (demux->num_streams > 0) {
230 gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
231 --demux->num_streams;
233 memset (demux->stream, 0, sizeof (demux->stream));
235 /* do not remove those for not adding pads with same name */
236 demux->num_audio_streams = 0;
237 demux->num_video_streams = 0;
238 demux->have_group_id = FALSE;
239 demux->group_id = G_MAXUINT;
241 demux->num_streams = 0;
242 demux->activated_streams = FALSE;
243 demux->first_ts = GST_CLOCK_TIME_NONE;
244 demux->segment_ts = GST_CLOCK_TIME_NONE;
247 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
248 demux->state = GST_ASF_DEMUX_STATE_HEADER;
249 demux->seekable = FALSE;
250 demux->broadcast = FALSE;
251 demux->sidx_interval = 0;
252 demux->sidx_num_entries = 0;
253 g_free (demux->sidx_entries);
254 demux->sidx_entries = NULL;
256 demux->speed_packets = 1;
259 GST_LOG_OBJECT (demux, "Restarting");
260 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
261 demux->need_newsegment = TRUE;
262 demux->segment_seqnum = 0;
263 demux->segment_running = FALSE;
264 demux->accurate = FALSE;
265 demux->metadata = gst_caps_new_empty ();
266 demux->global_metadata = gst_structure_new_empty ("metadata");
267 demux->data_size = 0;
268 demux->data_offset = 0;
269 demux->index_offset = 0;
271 demux->base_offset = 0;
274 g_slist_free (demux->other_streams);
275 demux->other_streams = NULL;
279 gst_asf_demux_init (GstASFDemux * demux)
282 gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
283 gst_pad_set_chain_function (demux->sinkpad,
284 GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
285 gst_pad_set_event_function (demux->sinkpad,
286 GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
287 gst_pad_set_activate_function (demux->sinkpad,
288 GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
289 gst_pad_set_activatemode_function (demux->sinkpad,
290 GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
291 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
293 /* set initial state */
294 gst_asf_demux_reset (demux, FALSE);
298 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
303 query = gst_query_new_scheduling ();
305 if (!gst_pad_peer_query (sinkpad, query)) {
306 gst_query_unref (query);
310 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
311 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
312 gst_query_unref (query);
317 GST_DEBUG_OBJECT (sinkpad, "activating pull");
318 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
322 GST_DEBUG_OBJECT (sinkpad, "activating push");
323 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
328 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
329 GstPadMode mode, gboolean active)
334 demux = GST_ASF_DEMUX (parent);
337 case GST_PAD_MODE_PUSH:
338 demux->state = GST_ASF_DEMUX_STATE_HEADER;
339 demux->streaming = TRUE;
342 case GST_PAD_MODE_PULL:
344 demux->state = GST_ASF_DEMUX_STATE_HEADER;
345 demux->streaming = FALSE;
347 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
350 res = gst_pad_stop_task (sinkpad);
361 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
366 demux = GST_ASF_DEMUX (parent);
368 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
369 switch (GST_EVENT_TYPE (event)) {
370 case GST_EVENT_SEGMENT:{
371 const GstSegment *segment;
373 gst_event_parse_segment (event, &segment);
375 if (segment->format == GST_FORMAT_BYTES) {
376 if (demux->packet_size && segment->start > demux->data_offset)
377 demux->packet = (segment->start - demux->data_offset) /
381 } else if (segment->format == GST_FORMAT_TIME) {
382 /* do not know packet position, not really a problem */
385 GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
386 gst_event_unref (event);
390 /* record upstream segment for interpolation */
391 if (segment->format != demux->in_segment.format)
392 gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
393 gst_segment_copy_into (segment, &demux->in_segment);
395 /* in either case, clear some state and generate newsegment later on */
396 GST_OBJECT_LOCK (demux);
397 demux->segment_ts = GST_CLOCK_TIME_NONE;
398 demux->in_gap = GST_CLOCK_TIME_NONE;
399 demux->need_newsegment = TRUE;
400 demux->segment_seqnum = gst_event_get_seqnum (event);
401 gst_asf_demux_reset_stream_state_after_discont (demux);
402 GST_OBJECT_UNLOCK (demux);
404 gst_event_unref (event);
410 if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
411 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
412 (_("This stream contains no data.")),
413 ("got eos and didn't receive a complete header object"));
416 flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
417 if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
418 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
419 (_("Internal data stream error.")),
420 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
424 GST_OBJECT_LOCK (demux);
425 gst_adapter_clear (demux->adapter);
426 GST_OBJECT_UNLOCK (demux);
427 gst_asf_demux_send_event_unlocked (demux, event);
431 case GST_EVENT_FLUSH_STOP:
432 GST_OBJECT_LOCK (demux);
433 gst_asf_demux_reset_stream_state_after_discont (demux);
434 GST_OBJECT_UNLOCK (demux);
435 gst_asf_demux_send_event_unlocked (demux, event);
436 /* upon activation, latency is no longer introduced, e.g. after seek */
437 if (demux->activated_streams)
442 ret = gst_pad_event_default (pad, parent, event);
450 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
451 GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
452 gboolean next, gboolean * eos)
454 GstClockTime idx_time;
460 if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
463 idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
466 /* if we want the next keyframe, we have to go forward till we find
467 a different packet number */
469 if (idx >= demux->sidx_num_entries - 1) {
470 /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
475 for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
476 if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
483 if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
489 *packet = demux->sidx_entries[idx].packet;
491 *speed = demux->sidx_entries[idx].count;
493 /* so we get closer to the actual time of the packet ... actually, let's not
494 * do this, since we throw away superfluous payloads before the seek position
495 * anyway; this way, our key unit seek 'snap resolution' is a bit better
496 * (ie. same as index resolution) */
498 while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
502 idx_time = demux->sidx_interval * idx;
503 if (G_LIKELY (idx_time >= demux->preroll))
504 idx_time -= demux->preroll;
506 GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
507 GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
508 GST_TIME_ARGS (idx_time));
510 if (G_LIKELY (p_idx_time))
511 *p_idx_time = idx_time;
517 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
521 gst_adapter_clear (demux->adapter);
523 GST_DEBUG_OBJECT (demux, "reset stream state");
525 for (n = 0; n < demux->num_streams; n++) {
526 demux->stream[n].discont = TRUE;
527 demux->stream[n].last_flow = GST_FLOW_OK;
529 while (demux->stream[n].payloads->len > 0) {
533 last = demux->stream[n].payloads->len - 1;
534 payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
535 gst_buffer_replace (&payload->buf, NULL);
536 g_array_remove_index (demux->stream[n].payloads, last);
542 gst_asf_demux_mark_discont (GstASFDemux * demux)
546 GST_DEBUG_OBJECT (demux, "Mark stream discont");
548 for (n = 0; n < demux->num_streams; n++)
549 demux->stream[n].discont = TRUE;
552 /* do a seek in push based mode */
554 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
559 GstSeekType cur_type, stop_type;
563 GstEvent *byte_event;
565 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
568 stop_type = GST_SEEK_TYPE_NONE;
571 GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
573 /* determine packet, by index or by estimation */
574 if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
577 (guint) gst_util_uint64_scale (demux->num_packets, cur,
581 if (packet > demux->num_packets) {
582 GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
587 GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
589 cur = demux->data_offset + (packet * demux->packet_size);
591 GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
592 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
593 /* BYTE seek event */
594 byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
595 cur, stop_type, stop);
596 gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
597 res = gst_pad_push_event (demux->sinkpad, byte_event);
603 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
605 GstClockTime idx_time;
608 GstSeekType cur_type, stop_type;
610 gboolean only_need_update;
611 gboolean keyunit_sync, after, before, next;
616 guint packet, speed_count = 1;
621 if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
622 demux->num_packets == 0 || demux->play_time == 0)) {
623 GST_LOG_OBJECT (demux, "stream is not seekable");
627 if (G_UNLIKELY (!demux->activated_streams)) {
628 GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
632 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
634 seqnum = gst_event_get_seqnum (event);
636 if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
637 GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
641 if (G_UNLIKELY (rate <= 0.0)) {
642 GST_LOG_OBJECT (demux, "backward playback is not supported yet");
646 flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
648 ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
649 keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
650 after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
651 before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
652 next = after && !before;
654 if (G_UNLIKELY (demux->streaming)) {
655 /* support it safely needs more segment handling, e.g. closing etc */
657 GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
660 /* we can (re)construct the start later on, but not the end */
661 if (stop_type != GST_SEEK_TYPE_NONE &&
662 (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
663 GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
666 gst_event_ref (event);
667 /* upstream might handle TIME seek, e.g. mms or rtsp,
668 * or not, e.g. http, then we give it a hand */
669 if (!gst_pad_push_event (demux->sinkpad, event))
670 return gst_asf_demux_handle_seek_push (demux, event);
675 /* unlock the streaming thread */
676 if (G_LIKELY (flush)) {
677 fevent = gst_event_new_flush_start ();
679 gst_event_set_seqnum (fevent, seqnum);
680 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
681 gst_asf_demux_send_event_unlocked (demux, fevent);
683 gst_pad_pause_task (demux->sinkpad);
686 /* grab the stream lock so that streaming cannot continue, for
687 * non flushing seeks when the element is in PAUSED this could block
689 GST_PAD_STREAM_LOCK (demux->sinkpad);
691 /* we now can stop flushing, since we have the stream lock now */
692 fevent = gst_event_new_flush_stop (TRUE);
693 gst_event_set_seqnum (fevent, seqnum);
694 gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
696 if (G_LIKELY (flush))
697 gst_asf_demux_send_event_unlocked (demux, fevent);
699 gst_event_unref (fevent);
701 /* operating on copy of segment until we know the seek worked */
702 segment = demux->segment;
704 if (G_UNLIKELY (demux->segment_running && !flush)) {
705 GstSegment newsegment;
708 /* create the segment event to close the current segment */
709 gst_segment_copy_into (&segment, &newsegment);
710 newseg = gst_event_new_segment (&newsegment);
711 gst_event_set_seqnum (newseg, seqnum);
713 gst_asf_demux_send_event_unlocked (demux, newseg);
716 gst_segment_do_seek (&segment, rate, format, flags, cur_type,
717 cur, stop_type, stop, &only_need_update);
719 GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
720 "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
722 seek_time = segment.start;
724 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
725 * real start of data and segment_start to indexed time for key unit seek*/
726 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
727 &idx_time, &speed_count, next, &eos))) {
731 demux->packet = demux->num_packets;
735 /* First try to query our source to see if it can convert for us. This is
736 the case when our source is an mms stream, notice that in this case
737 gstmms will do a time based seek to get the byte offset, this is not a
738 problem as the seek to this offset needs to happen anway. */
739 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
740 GST_FORMAT_BYTES, &offset)) {
741 packet = (offset - demux->data_offset) / demux->packet_size;
742 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
743 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
744 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
745 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
746 demux->packet_size, packet);
748 /* FIXME: For streams containing video, seek to an earlier position in
749 * the hope of hitting a keyframe and let the sinks throw away the stuff
750 * before the segment start. For audio-only this is unnecessary as every
752 if (flush && (demux->accurate || (keyunit_sync && !next))
753 && demux->num_video_streams > 0) {
754 seek_time -= 5 * GST_SECOND;
759 packet = (guint) gst_util_uint64_scale (demux->num_packets,
760 seek_time, demux->play_time);
762 if (packet > demux->num_packets)
763 packet = demux->num_packets;
766 if (G_LIKELY (keyunit_sync)) {
767 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
768 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
769 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
770 segment.start = idx_time;
771 segment.position = idx_time;
772 segment.time = idx_time;
776 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
778 GST_OBJECT_LOCK (demux);
779 demux->segment = segment;
780 demux->packet = packet;
781 demux->need_newsegment = TRUE;
782 demux->segment_seqnum = seqnum;
783 demux->speed_packets = speed_count;
784 gst_asf_demux_reset_stream_state_after_discont (demux);
785 GST_OBJECT_UNLOCK (demux);
788 /* restart our task since it might have been stopped when we did the flush */
789 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
792 /* streaming can continue now */
793 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
799 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
805 demux = GST_ASF_DEMUX (parent);
807 switch (GST_EVENT_TYPE (event)) {
809 GST_LOG_OBJECT (pad, "seek event");
810 ret = gst_asf_demux_handle_seek_event (demux, event);
811 gst_event_unref (event);
814 case GST_EVENT_NAVIGATION:
815 /* just drop these two silently */
816 gst_event_unref (event);
820 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
821 ret = gst_pad_event_default (pad, parent, event);
828 static inline guint32
829 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
833 ret = gst_asf_identify_guid (guids, guid);
835 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
836 gst_asf_get_guid_nick (guids, ret),
837 guid->v1, guid->v2, guid->v3, guid->v4);
849 /* expect is true when the user is expeting an object,
850 * when false, it will give no warnings if the object
854 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
855 guint data_len, AsfObject * object, gboolean expect)
859 if (data_len < ASF_OBJECT_HEADER_SIZE)
862 guid.v1 = GST_READ_UINT32_LE (data + 0);
863 guid.v2 = GST_READ_UINT32_LE (data + 4);
864 guid.v3 = GST_READ_UINT32_LE (data + 8);
865 guid.v4 = GST_READ_UINT32_LE (data + 12);
867 object->size = GST_READ_UINT64_LE (data + 16);
869 /* FIXME: make asf_demux_identify_object_guid() */
870 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
871 if (object->id == ASF_OBJ_UNDEFINED && expect) {
872 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
873 guid.v1, guid.v2, guid.v3, guid.v4);
880 gst_asf_demux_release_old_pads (GstASFDemux * demux)
882 GST_DEBUG_OBJECT (demux, "Releasing old pads");
884 while (demux->old_num_streams > 0) {
885 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
886 gst_event_new_eos ());
887 gst_asf_demux_free_stream (demux,
888 &demux->old_stream[demux->old_num_streams - 1]);
889 --demux->old_num_streams;
891 memset (demux->old_stream, 0, sizeof (demux->old_stream));
892 demux->old_num_streams = 0;
896 gst_asf_demux_chain_headers (GstASFDemux * demux)
900 guint8 *header_data, *data = NULL;
901 const guint8 *cdata = NULL;
904 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
908 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
909 if (obj.id != ASF_OBJ_HEADER)
912 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
914 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
915 if (gst_adapter_available (demux->adapter) < obj.size + 50)
918 data = gst_adapter_take (demux->adapter, obj.size + 50);
921 header_size = obj.size;
922 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
923 if (flow != GST_FLOW_OK)
926 /* calculate where the packet data starts */
927 demux->data_offset = obj.size + 50;
929 /* now parse the beginning of the ASF_OBJ_DATA object */
930 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
933 if (demux->num_streams == 0)
942 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
949 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
950 ("This doesn't seem to be an ASF file"));
952 return GST_FLOW_ERROR;
957 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
958 ("header parsing failed, or no streams found, flow = %s",
959 gst_flow_get_name (flow)));
961 return GST_FLOW_ERROR;
966 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
971 GST_DEBUG_OBJECT (demux, "Aggregating");
973 /* Store the value */
974 stream->last_flow = flow;
976 /* any other error that is not not-linked can be returned right away */
977 if (flow != GST_FLOW_NOT_LINKED)
980 for (i = 0; i < demux->num_streams; i++) {
981 if (demux->stream[i].active) {
982 flow = demux->stream[i].last_flow;
983 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
984 gst_flow_get_name (flow));
985 if (flow != GST_FLOW_NOT_LINKED)
990 /* If we got here, then all our active streams are not linked */
996 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
997 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1002 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1005 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1007 if (G_LIKELY (p_flow))
1010 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1011 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1012 "+%u", gst_flow_get_name (flow), offset, size);
1017 g_assert (*p_buf != NULL);
1019 buffer_size = gst_buffer_get_size (*p_buf);
1020 if (G_UNLIKELY (buffer_size < size)) {
1021 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1022 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1023 gst_buffer_unref (*p_buf);
1024 if (G_LIKELY (p_flow))
1025 *p_flow = GST_FLOW_EOS;
1034 gst_asf_demux_pull_indices (GstASFDemux * demux)
1036 GstBuffer *buf = NULL;
1040 offset = demux->index_offset;
1042 if (G_UNLIKELY (offset == 0)) {
1043 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1047 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1053 gst_buffer_map (buf, &map, GST_MAP_READ);
1054 g_assert (map.size >= 16 + 8);
1055 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1056 gst_buffer_unmap (buf, &map);
1057 gst_buffer_replace (&buf, NULL);
1059 /* check for sanity */
1060 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1061 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1065 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1069 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1070 ", size %u", offset, (guint) obj.size);
1072 offset += obj.size; /* increase before _process_object changes it */
1074 gst_buffer_map (buf, &map, GST_MAP_READ);
1075 g_assert (map.size >= obj.size);
1076 bufdata = (guint8 *) map.data;
1077 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1078 gst_buffer_unmap (buf, &map);
1079 gst_buffer_replace (&buf, NULL);
1081 if (G_UNLIKELY (flow != GST_FLOW_OK))
1086 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1090 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1094 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1095 if (obj.id != ASF_OBJ_DATA) {
1096 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1100 demux->state = GST_ASF_DEMUX_STATE_DATA;
1102 if (!demux->broadcast && obj.size > 50) {
1103 demux->data_size = obj.size - 50;
1104 /* CHECKME: for at least one file this is off by +158 bytes?! */
1105 demux->index_offset = demux->data_offset + demux->data_size;
1107 demux->data_size = 0;
1108 demux->index_offset = 0;
1113 if (!demux->broadcast) {
1114 /* skip object header (24 bytes) and file GUID (16 bytes) */
1115 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1117 demux->num_packets = 0;
1120 if (demux->num_packets == 0)
1121 demux->seekable = FALSE;
1123 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1124 if (demux->data_size == 0 && demux->num_packets > 0) {
1125 demux->data_size = demux->num_packets * demux->packet_size;
1126 demux->index_offset = demux->data_offset + demux->data_size;
1129 /* process pending stream objects and create pads for those */
1130 gst_asf_demux_process_queued_extended_stream_objects (demux);
1132 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1133 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1134 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1135 demux->data_offset, demux->data_size, demux->index_offset);
1141 gst_asf_demux_pull_headers (GstASFDemux * demux)
1145 GstBuffer *buf = NULL;
1150 GST_LOG_OBJECT (demux, "reading headers");
1152 /* pull HEADER object header, so we know its size */
1153 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1156 gst_buffer_map (buf, &map, GST_MAP_READ);
1157 g_assert (map.size >= 16 + 8);
1158 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1159 gst_buffer_unmap (buf, &map);
1160 gst_buffer_replace (&buf, NULL);
1162 if (obj.id != ASF_OBJ_HEADER)
1165 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1167 /* pull HEADER object */
1168 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1172 size = obj.size; /* don't want obj.size changed */
1173 gst_buffer_map (buf, &map, GST_MAP_READ);
1174 g_assert (map.size >= size);
1175 bufdata = (guint8 *) map.data;
1176 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1177 gst_buffer_unmap (buf, &map);
1178 gst_buffer_replace (&buf, NULL);
1180 if (flow != GST_FLOW_OK) {
1181 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1185 /* calculate where the packet data starts */
1186 demux->data_offset = demux->base_offset + obj.size + 50;
1188 /* now pull beginning of DATA object before packet data */
1189 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1193 gst_buffer_map (buf, &map, GST_MAP_READ);
1194 g_assert (map.size >= size);
1195 bufdata = (guint8 *) map.data;
1196 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1199 if (demux->num_streams == 0)
1202 gst_buffer_unmap (buf, &map);
1203 gst_buffer_replace (&buf, NULL);
1211 gst_buffer_unmap (buf, &map);
1212 gst_buffer_replace (&buf, NULL);
1214 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1215 ("This doesn't seem to be an ASF file"));
1224 gst_buffer_unmap (buf, &map);
1225 gst_buffer_replace (&buf, NULL);
1226 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1232 all_streams_prerolled (GstASFDemux * demux)
1234 GstClockTime preroll_time;
1235 guint i, num_no_data = 0;
1237 /* Allow at least 500ms of preroll_time */
1238 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1240 /* returns TRUE as long as there isn't a stream which (a) has data queued
1241 * and (b) the timestamp of last piece of data queued is < demux->preroll
1242 * AND there is at least one other stream with data queued */
1243 for (i = 0; i < demux->num_streams; ++i) {
1244 AsfPayload *last_payload = NULL;
1248 stream = &demux->stream[i];
1249 if (G_UNLIKELY (stream->payloads->len == 0)) {
1251 GST_LOG_OBJECT (stream->pad, "no data queued");
1255 /* find last payload with timestamp */
1256 for (last_idx = stream->payloads->len - 1;
1257 last_idx >= 0 && (last_payload == NULL
1258 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1259 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1262 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1263 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1264 GST_TIME_ARGS (preroll_time));
1265 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1266 || last_payload->ts <= preroll_time)) {
1267 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1272 if (G_UNLIKELY (num_no_data > 0))
1280 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1285 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1288 /* check for each mutual exclusion group whether it affects this stream */
1289 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1290 if (*mes == stream->id) {
1291 /* we are in this group; let's check if we've already activated streams
1292 * that are in the same group (and hence mutually exclusive to this
1294 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1297 for (i = 0; i < demux->num_streams; ++i) {
1298 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1299 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1300 "to already active stream with ID %d", stream->id,
1301 demux->stream[i].id);
1306 /* we can only be in this group once, let's break out and move on to
1307 * the next mutual exclusion group */
1318 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1320 /* remember the first queued timestamp for the segment */
1321 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1322 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1323 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1324 GST_TIME_ARGS (demux->first_ts));
1325 demux->segment_ts = payload_ts;
1326 /* always note, but only determines segment when streaming */
1327 if (demux->streaming)
1328 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1329 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1330 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1335 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1337 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1338 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1341 /* go trhough each stream, find smallest timestamp */
1342 for (i = 0; i < demux->num_streams; ++i) {
1345 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1346 stream = &demux->stream[i];
1348 for (j = 0; j < stream->payloads->len; ++j) {
1349 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1350 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1351 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1352 || stream_min_ts > payload->ts))
1353 stream_min_ts = payload->ts;
1356 /* if we don't have timestamp for this stream, wait for more data */
1357 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1360 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1361 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1362 first_ts = stream_min_ts;
1365 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1368 demux->first_ts = first_ts;
1370 /* update packets queued before we knew first timestamp */
1371 for (i = 0; i < demux->num_streams; ++i) {
1374 stream = &demux->stream[i];
1376 for (j = 0; j < stream->payloads->len; ++j) {
1377 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1378 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1379 if (payload->ts > first_ts)
1380 payload->ts -= first_ts;
1388 gst_asf_demux_check_segment_ts (demux, 0);
1394 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1396 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1397 and often set wrong, inspecting the data is the only way that seem to be working */
1398 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1399 GstCaps *caps = NULL;
1401 GstAdapter *adapter = gst_adapter_new ();
1403 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1405 AsfPayload *payload;
1408 payload = &g_array_index (stream->payloads, AsfPayload, i);
1409 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1410 len = gst_adapter_available (adapter);
1411 data = gst_adapter_map (adapter, len);
1415 #define MIN_LENGTH 128
1417 /* look for the sync points */
1419 if (len < MIN_LENGTH || /* give typefind something to work on */
1420 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1421 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1427 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1430 if (prob < GST_TYPE_FIND_LIKELY) {
1433 if (len > MIN_LENGTH)
1434 /* this wasn't it, look for another sync point */
1438 gst_adapter_unmap (adapter);
1441 gst_object_unref (adapter);
1444 gst_caps_take (&stream->caps, caps);
1452 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1456 if (demux->activated_streams)
1459 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1462 if (!all_streams_prerolled (demux) && !force) {
1463 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1467 for (i = 0; i < demux->num_streams; ++i) {
1468 AsfStream *stream = &demux->stream[i];
1470 if (stream->payloads->len > 0) {
1472 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1473 !stream->active && /* do not inspect active streams (caps were already set) */
1474 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1475 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1476 /* try to gather some more data */
1479 /* we don't check mutual exclusion stuff here; either we have data for
1480 * a stream, then we active it, or we don't, then we'll ignore it */
1481 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1482 gst_asf_demux_activate_stream (demux, stream);
1484 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1488 gst_asf_demux_release_old_pads (demux);
1490 demux->activated_streams = TRUE;
1491 GST_LOG_OBJECT (demux, "signalling no more pads");
1492 gst_element_no_more_pads (GST_ELEMENT (demux));
1496 /* returns the stream that has a complete payload with the lowest timestamp
1497 * queued, or NULL (we push things by timestamp because during the internal
1498 * prerolling we might accumulate more data then the external queues can take,
1499 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1501 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1503 AsfPayload *best_payload = NULL;
1504 AsfStream *best_stream = NULL;
1507 for (i = 0; i < demux->num_streams; ++i) {
1511 stream = &demux->stream[i];
1513 /* Don't push any data until we have at least one payload that falls within
1514 * the current segment. This way we can remove out-of-segment payloads that
1515 * don't need to be decoded after a seek, sending only data from the
1516 * keyframe directly before our segment start */
1517 if (stream->payloads->len > 0) {
1518 AsfPayload *payload = NULL;
1521 /* find last payload with timestamp */
1522 for (last_idx = stream->payloads->len - 1;
1523 last_idx >= 0 && (payload == NULL
1524 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1525 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1528 /* if this is first payload after seek we might need to update the segment */
1529 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1530 gst_asf_demux_check_segment_ts (demux, payload->ts);
1532 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1533 (payload->ts < demux->segment.start))) {
1534 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1535 GST_DEBUG_OBJECT (stream->pad,
1536 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1537 GST_TIME_ARGS (payload->ts));
1538 demux->segment.start = payload->ts;
1539 demux->segment.time = payload->ts;
1541 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1542 GST_TIME_FORMAT " which is before our segment start %"
1543 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1544 GST_TIME_ARGS (demux->segment.start));
1549 /* Now see if there's a complete payload queued for this stream */
1552 /* find first complete payload with timestamp */
1554 j < stream->payloads->len && (payload == NULL
1555 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1556 payload = &g_array_index (stream->payloads, AsfPayload, j);
1559 if (!gst_asf_payload_is_complete (payload))
1562 /* ... and whether its timestamp is lower than the current best */
1563 if (best_stream == NULL || best_payload->ts > payload->ts) {
1564 best_stream = stream;
1565 best_payload = payload;
1573 static GstFlowReturn
1574 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1577 GstFlowReturn ret = GST_FLOW_OK;
1579 if (G_UNLIKELY (!demux->activated_streams)) {
1580 if (!gst_asf_demux_check_activate_streams (demux, force))
1582 /* streams are now activated */
1585 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1586 AsfPayload *payload;
1588 /* wait until we had a chance to "lock on" some payload's timestamp */
1589 if (G_UNLIKELY (demux->need_newsegment
1590 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1593 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1595 /* do we need to send a newsegment event */
1596 if ((G_UNLIKELY (demux->need_newsegment))) {
1597 GstEvent *segment_event;
1599 /* safe default if insufficient upstream info */
1600 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1603 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1604 demux->segment.duration > 0) {
1605 /* slight HACK; prevent clipping of last bit */
1606 demux->segment.stop = demux->segment.duration + demux->in_gap;
1609 /* FIXME : only if ACCURATE ! */
1610 if (G_LIKELY (!demux->accurate
1611 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1612 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1613 GST_TIME_ARGS (payload->ts));
1614 demux->segment.start = payload->ts;
1615 demux->segment.time = payload->ts;
1618 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1621 /* note: we fix up all timestamps to start from 0, so this should be ok */
1622 segment_event = gst_event_new_segment (&demux->segment);
1623 if (demux->segment_seqnum)
1624 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1625 gst_asf_demux_send_event_unlocked (demux, segment_event);
1627 /* now post any global tags we may have found */
1628 if (demux->taglist == NULL) {
1629 demux->taglist = gst_tag_list_new_empty ();
1630 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1633 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1634 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1636 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1637 gst_asf_demux_send_event_unlocked (demux,
1638 gst_event_new_tag (demux->taglist));
1639 demux->taglist = NULL;
1641 demux->need_newsegment = FALSE;
1642 demux->segment_seqnum = 0;
1643 demux->segment_running = TRUE;
1646 /* Do we have tags pending for this stream? */
1647 if (G_UNLIKELY (stream->pending_tags)) {
1648 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1649 gst_pad_push_event (stream->pad,
1650 gst_event_new_tag (stream->pending_tags));
1651 stream->pending_tags = NULL;
1654 /* We have the whole packet now so we should push the packet to
1655 * the src pad now. First though we should check if we need to do
1657 if (G_UNLIKELY (demux->span > 1)) {
1658 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1661 payload->buf = gst_buffer_make_writable (payload->buf);
1663 if (G_LIKELY (!payload->keyframe)) {
1664 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1667 if (G_UNLIKELY (stream->discont)) {
1668 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1669 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1670 stream->discont = FALSE;
1673 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1674 (payload->par_x != stream->par_x) &&
1675 (payload->par_y != stream->par_y))) {
1676 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1677 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1678 stream->par_x = payload->par_x;
1679 stream->par_y = payload->par_y;
1680 stream->caps = gst_caps_make_writable (stream->caps);
1681 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1682 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1683 gst_pad_set_caps (stream->pad, stream->caps);
1686 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1687 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1688 payload->interlaced);
1689 stream->interlaced = payload->interlaced;
1690 stream->caps = gst_caps_make_writable (stream->caps);
1691 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1692 (stream->interlaced ? "mixed" : "progressive"), NULL);
1693 gst_pad_set_caps (stream->pad, stream->caps);
1696 /* (sort of) interpolate timestamps using upstream "frame of reference",
1697 * typically useful for live src, but might (unavoidably) mess with
1698 * position reporting if a live src is playing not so live content
1699 * (e.g. rtspsrc taking some time to fall back to tcp) */
1700 GST_BUFFER_PTS (payload->buf) = payload->ts;
1701 if (GST_BUFFER_PTS_IS_VALID (payload->buf)) {
1702 GST_BUFFER_PTS (payload->buf) += demux->in_gap;
1704 if (payload->duration == GST_CLOCK_TIME_NONE
1705 && stream->ext_props.avg_time_per_frame != 0)
1706 GST_BUFFER_DURATION (payload->buf) =
1707 stream->ext_props.avg_time_per_frame * 100;
1709 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1711 /* FIXME: we should really set durations on buffers if we can */
1713 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1714 ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
1715 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1716 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1717 gst_buffer_get_size (payload->buf));
1719 if (stream->active) {
1720 ret = gst_pad_push (stream->pad, payload->buf);
1721 ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1723 gst_buffer_unref (payload->buf);
1726 payload->buf = NULL;
1727 g_array_remove_index (stream->payloads, 0);
1729 /* Break out as soon as we have an issue */
1730 if (G_UNLIKELY (ret != GST_FLOW_OK))
1738 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1742 g_assert (buf != NULL);
1744 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1746 gst_buffer_map (buf, &map, GST_MAP_READ);
1748 /* we return false on buffer too small */
1749 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1750 gst_buffer_unmap (buf, &map);
1754 /* check if it is a header */
1755 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1756 gst_buffer_unmap (buf, &map);
1757 if (obj.id == ASF_OBJ_HEADER) {
1764 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1766 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1767 GstFlowReturn ret = GST_FLOW_OK;
1768 GstBuffer *buf = NULL;
1769 gboolean header = FALSE;
1771 /* TODO maybe we should skip index objects after the data and look
1772 * further for a new header */
1773 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1774 g_assert (buf != NULL);
1775 /* check if it is a header */
1776 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1777 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1778 demux->base_offset = off;
1782 gst_buffer_unref (buf);
1789 gst_asf_demux_loop (GstASFDemux * demux)
1791 GstFlowReturn flow = GST_FLOW_OK;
1792 GstBuffer *buf = NULL;
1794 gboolean sent_eos = FALSE;
1796 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1797 if (!gst_asf_demux_pull_headers (demux)) {
1798 flow = GST_FLOW_ERROR;
1802 gst_asf_demux_pull_indices (demux);
1805 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1807 if (G_UNLIKELY (demux->num_packets != 0
1808 && demux->packet >= demux->num_packets))
1811 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1812 (guint) demux->num_packets);
1814 off = demux->data_offset + (demux->packet * demux->packet_size);
1816 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1817 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1818 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1819 if (flow == GST_FLOW_EOS)
1821 else if (flow == GST_FLOW_FLUSHING) {
1822 GST_DEBUG_OBJECT (demux, "Not fatal");
1828 if (G_LIKELY (demux->speed_packets == 1)) {
1829 GstAsfDemuxParsePacketError err;
1830 err = gst_asf_demux_parse_packet (demux, buf);
1831 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1832 /* when we don't know when the data object ends, we should check
1833 * for a chained asf */
1834 if (demux->num_packets == 0) {
1835 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1836 GST_INFO_OBJECT (demux, "Chained asf found");
1837 demux->base_offset = off;
1838 gst_asf_demux_reset (demux, TRUE);
1839 gst_buffer_unref (buf);
1843 /* FIXME: We should tally up fatal errors and error out only
1844 * after a few broken packets in a row? */
1846 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1847 gst_buffer_unref (buf);
1852 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1858 for (n = 0; n < demux->speed_packets; n++) {
1860 GstAsfDemuxParsePacketError err;
1863 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1864 n * demux->packet_size, demux->packet_size);
1865 err = gst_asf_demux_parse_packet (demux, sub);
1866 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1867 /* when we don't know when the data object ends, we should check
1868 * for a chained asf */
1869 if (demux->num_packets == 0) {
1870 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1871 GST_INFO_OBJECT (demux, "Chained asf found");
1872 demux->base_offset = off + n * demux->packet_size;
1873 gst_asf_demux_reset (demux, TRUE);
1874 gst_buffer_unref (sub);
1875 gst_buffer_unref (buf);
1879 /* FIXME: We should tally up fatal errors and error out only
1880 * after a few broken packets in a row? */
1882 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1886 gst_buffer_unref (sub);
1888 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1889 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1895 /* reset speed pull */
1896 demux->speed_packets = 1;
1899 gst_buffer_unref (buf);
1901 if (G_UNLIKELY (demux->num_packets > 0
1902 && demux->packet >= demux->num_packets)) {
1903 GST_LOG_OBJECT (demux, "reached EOS");
1907 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1908 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1912 /* check if we're at the end of the configured segment */
1913 /* FIXME: check if segment end reached etc. */
1919 /* if we haven't activated our streams yet, this might be because we have
1920 * less data queued than required for preroll; force stream activation and
1921 * send any pending payloads before sending EOS */
1922 if (!demux->activated_streams)
1923 gst_asf_demux_push_complete_payloads (demux, TRUE);
1925 /* we want to push an eos or post a segment-done in any case */
1926 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1929 /* for segment playback we need to post when (in stream time)
1930 * we stopped, this is either stop (when set) or the duration. */
1931 if ((stop = demux->segment.stop) == -1)
1932 stop = demux->segment.duration;
1934 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1935 gst_element_post_message (GST_ELEMENT_CAST (demux),
1936 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1938 gst_asf_demux_send_event_unlocked (demux,
1939 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1940 } else if (flow != GST_FLOW_EOS) {
1941 /* check if we have a chained asf, in case, we don't eos yet */
1942 if (gst_asf_demux_check_chained_asf (demux)) {
1943 GST_INFO_OBJECT (demux, "Chained ASF starting");
1944 gst_asf_demux_reset (demux, TRUE);
1948 /* normal playback, send EOS to all linked pads */
1949 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1950 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1952 /* ... and fall through to pause */
1956 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1957 gst_flow_get_name (flow));
1958 demux->segment_running = FALSE;
1959 gst_pad_pause_task (demux->sinkpad);
1961 /* For the error cases (not EOS) */
1963 if (flow == GST_FLOW_EOS)
1964 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1965 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1966 /* Post an error. Hopefully something else already has, but if not... */
1967 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1968 (_("Internal data stream error.")),
1969 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1978 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1979 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1980 flow = GST_FLOW_EOS;
1984 /* See FIXMEs above */
1987 gst_buffer_unref (buf);
1988 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1989 ("Error parsing ASF packet %u", (guint) demux->packet));
1990 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1991 flow = GST_FLOW_ERROR;
1997 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1998 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1999 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2002 gst_asf_demux_check_header (GstASFDemux * demux)
2005 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2006 ASF_OBJECT_HEADER_SIZE);
2007 if (cdata == NULL) /* need more data */
2008 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2010 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2011 if (obj.id != ASF_OBJ_HEADER) {
2012 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2014 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2018 static GstFlowReturn
2019 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2021 GstFlowReturn ret = GST_FLOW_OK;
2024 demux = GST_ASF_DEMUX (parent);
2026 GST_LOG_OBJECT (demux,
2027 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2028 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2029 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2031 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2032 GST_DEBUG_OBJECT (demux, "received DISCONT");
2033 gst_asf_demux_mark_discont (demux);
2036 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2037 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2038 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2039 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2040 ", interpolation gap: %" GST_TIME_FORMAT,
2041 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2044 gst_adapter_push (demux->adapter, buf);
2046 switch (demux->state) {
2047 case GST_ASF_DEMUX_STATE_INDEX:{
2048 gint result = gst_asf_demux_check_header (demux);
2049 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2052 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2053 /* we don't care about this, probably an index */
2054 /* TODO maybe would be smarter to skip all the indices
2055 * until we got a new header or EOS to decide */
2056 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2059 GST_INFO_OBJECT (demux, "Chained asf starting");
2060 /* cleanup and get ready for a chained asf */
2061 gst_asf_demux_reset (demux, TRUE);
2065 case GST_ASF_DEMUX_STATE_HEADER:{
2066 ret = gst_asf_demux_chain_headers (demux);
2067 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2069 /* otherwise fall through */
2071 case GST_ASF_DEMUX_STATE_DATA:
2075 data_size = demux->packet_size;
2077 while (gst_adapter_available (demux->adapter) >= data_size) {
2079 GstAsfDemuxParsePacketError err;
2081 /* we don't know the length of the stream
2082 * check for a chained asf everytime */
2083 if (demux->num_packets == 0) {
2084 gint result = gst_asf_demux_check_header (demux);
2086 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2087 GST_INFO_OBJECT (demux, "Chained asf starting");
2088 /* cleanup and get ready for a chained asf */
2089 gst_asf_demux_reset (demux, TRUE);
2092 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2093 && demux->packet >= demux->num_packets)) {
2094 /* do not overshoot data section when streaming */
2098 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2100 /* FIXME: We should tally up fatal errors and error out only
2101 * after a few broken packets in a row? */
2102 err = gst_asf_demux_parse_packet (demux, buf);
2104 gst_buffer_unref (buf);
2106 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2107 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2109 GST_WARNING_OBJECT (demux, "Parse error");
2111 if (demux->packet >= 0)
2114 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2115 && demux->packet >= demux->num_packets)) {
2116 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2121 g_assert_not_reached ();
2125 if (ret != GST_FLOW_OK)
2126 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2132 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2138 static inline gboolean
2139 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2141 if (*p_size < num_bytes)
2144 *p_data += num_bytes;
2145 *p_size -= num_bytes;
2149 static inline guint8
2150 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2154 g_assert (*p_size >= 1);
2155 ret = GST_READ_UINT8 (*p_data);
2156 *p_data += sizeof (guint8);
2157 *p_size -= sizeof (guint8);
2161 static inline guint16
2162 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2166 g_assert (*p_size >= 2);
2167 ret = GST_READ_UINT16_LE (*p_data);
2168 *p_data += sizeof (guint16);
2169 *p_size -= sizeof (guint16);
2173 static inline guint32
2174 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2178 g_assert (*p_size >= 4);
2179 ret = GST_READ_UINT32_LE (*p_data);
2180 *p_data += sizeof (guint32);
2181 *p_size -= sizeof (guint32);
2185 static inline guint64
2186 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2190 g_assert (*p_size >= 8);
2191 ret = GST_READ_UINT64_LE (*p_data);
2192 *p_data += sizeof (guint64);
2193 *p_size -= sizeof (guint64);
2197 static inline guint32
2198 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
2205 g_assert (*p_size >= 1);
2206 return gst_asf_demux_get_uint8 (p_data, p_size);
2209 g_assert (*p_size >= 2);
2210 return gst_asf_demux_get_uint16 (p_data, p_size);
2213 g_assert (*p_size >= 4);
2214 return gst_asf_demux_get_uint32 (p_data, p_size);
2217 g_assert_not_reached ();
2224 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2225 guint8 ** p_data, guint64 * p_size)
2229 if (*p_size < num_bytes_to_read)
2232 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2233 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2235 *p_data += num_bytes_to_read;
2236 *p_size -= num_bytes_to_read;
2242 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2243 guint8 ** p_data, guint64 * p_size)
2247 if (*p_size < num_bytes_to_read)
2250 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2251 *p_data += num_bytes_to_read;
2252 *p_size -= num_bytes_to_read;
2257 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2258 guint8 ** p_data, guint64 * p_size)
2268 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2271 *p_strlen = s_length;
2273 if (s_length == 0) {
2274 GST_WARNING ("zero-length string");
2275 *p_str = g_strdup ("");
2279 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2282 g_assert (s != NULL);
2284 /* just because They don't exist doesn't
2285 * mean They are not out to get you ... */
2286 if (s[s_length - 1] != '\0') {
2287 s = g_realloc (s, s_length + 1);
2291 *p_str = (gchar *) s;
2297 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2299 g_assert (*p_size >= 4 * sizeof (guint32));
2301 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2302 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2303 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2304 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2308 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2311 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2314 /* WAVEFORMATEX Structure */
2315 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2316 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2317 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2318 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2319 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2320 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2321 /* Codec specific data size */
2322 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2327 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2330 if (*p_size < (4 + 4 + 1 + 2))
2333 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2334 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2335 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2336 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2341 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2342 guint8 ** p_data, guint64 * p_size)
2344 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2347 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2348 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2349 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2350 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2351 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2352 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2353 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2354 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2355 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2356 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2357 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2362 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2366 for (i = 0; i < demux->num_streams; i++) {
2367 if (demux->stream[i].id == id)
2368 return &demux->stream[i];
2371 if (gst_asf_demux_is_unknown_stream (demux, id))
2372 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2377 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2378 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2382 gst_pad_use_fixed_caps (src_pad);
2383 gst_pad_set_caps (src_pad, caps);
2385 gst_pad_set_event_function (src_pad,
2386 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2387 gst_pad_set_query_function (src_pad,
2388 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2390 stream = &demux->stream[demux->num_streams];
2391 stream->caps = caps;
2392 stream->pad = src_pad;
2394 stream->fps_known = !is_video; /* bit hacky for audio */
2395 stream->is_video = is_video;
2396 stream->pending_tags = tags;
2397 stream->discont = TRUE;
2401 st = gst_caps_get_structure (caps, 0);
2402 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2403 par_x > 0 && par_y > 0) {
2404 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2405 stream->par_x = par_x;
2406 stream->par_y = par_y;
2410 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2412 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2413 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2415 ++demux->num_streams;
2417 stream->active = FALSE;
2421 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2422 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2424 GstTagList *tags = NULL;
2425 GstBuffer *extradata = NULL;
2428 guint16 size_left = 0;
2429 gchar *codec_name = NULL;
2432 size_left = audio->size;
2434 /* Create the audio pad */
2435 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2437 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2440 /* Swallow up any left over data and set up the
2441 * standard properties from the header info */
2443 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2444 "codec specific data", size_left);
2446 g_assert (size_left <= *p_size);
2447 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2450 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2451 * additional two bytes indicating extradata. */
2452 /* FIXME: Handle the channel reorder map here */
2453 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2454 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2457 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2458 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2461 /* Informing about that audio format we just added */
2463 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2464 g_free (codec_name);
2468 gst_buffer_unref (extradata);
2470 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2471 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2472 audio->codec_tag, tags);
2474 ++demux->num_audio_streams;
2476 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2480 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2481 asf_stream_video_format * video, guint16 id,
2482 guint8 ** p_data, guint64 * p_size)
2484 GstTagList *tags = NULL;
2485 GstBuffer *extradata = NULL;
2490 gchar *codec_name = NULL;
2491 gint size_left = video->size - 40;
2493 /* Create the video pad */
2494 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2495 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2498 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2500 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2501 g_assert (size_left <= *p_size);
2502 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2505 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2507 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2508 caps = gst_riff_create_video_caps (video->tag, NULL,
2509 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2512 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2513 G_TYPE_UINT, video->tag, NULL);
2518 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2519 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2520 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2521 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2526 /* retry with the global metadata */
2527 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2528 demux->global_metadata);
2529 s = demux->global_metadata;
2530 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2531 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2532 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2533 if (ax > 0 && ay > 0)
2534 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2538 s = gst_caps_get_structure (caps, 0);
2539 gst_structure_remove_field (s, "framerate");
2542 /* add fourcc format to caps, some proprietary decoders seem to need it */
2543 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2544 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2548 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2549 g_free (codec_name);
2553 gst_buffer_unref (extradata);
2555 GST_INFO ("Adding video stream #%u, id %u, codec %"
2556 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2557 GST_FOURCC_ARGS (video->tag), video->tag);
2559 ++demux->num_video_streams;
2561 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2565 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2567 if (!stream->active) {
2571 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2572 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2573 gst_pad_set_active (stream->pad, TRUE);
2576 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2577 "%03u", stream->id);
2580 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2582 if (gst_event_parse_group_id (event, &demux->group_id))
2583 demux->have_group_id = TRUE;
2585 demux->have_group_id = FALSE;
2586 gst_event_unref (event);
2587 } else if (!demux->have_group_id) {
2588 demux->have_group_id = TRUE;
2589 demux->group_id = gst_util_group_id_next ();
2592 event = gst_event_new_stream_start (stream_id);
2593 if (demux->have_group_id)
2594 gst_event_set_group_id (event, demux->group_id);
2596 gst_pad_push_event (stream->pad, event);
2598 gst_pad_set_caps (stream->pad, stream->caps);
2600 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2601 stream->active = TRUE;
2606 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2609 AsfCorrectionType correction_type;
2610 AsfStreamType stream_type;
2611 GstClockTime time_offset;
2612 gboolean is_encrypted G_GNUC_UNUSED;
2616 guint stream_specific_size;
2617 guint type_specific_size G_GNUC_UNUSED;
2618 guint unknown G_GNUC_UNUSED;
2619 gboolean inspect_payload = FALSE;
2622 /* Get the rest of the header's header */
2623 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2624 goto not_enough_data;
2626 gst_asf_demux_get_guid (&guid, &data, &size);
2627 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2629 gst_asf_demux_get_guid (&guid, &data, &size);
2630 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2632 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2634 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2635 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2637 flags = gst_asf_demux_get_uint16 (&data, &size);
2638 stream_id = flags & 0x7f;
2639 is_encrypted = ! !((flags & 0x8000) << 15);
2640 unknown = gst_asf_demux_get_uint32 (&data, &size);
2642 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2643 stream_id, GST_TIME_ARGS (time_offset));
2645 /* dvr-ms has audio stream declared in stream specific data */
2646 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2647 AsfExtStreamType ext_stream_type;
2648 gst_asf_demux_get_guid (&guid, &data, &size);
2649 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2651 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2652 inspect_payload = TRUE;
2654 gst_asf_demux_get_guid (&guid, &data, &size);
2655 gst_asf_demux_get_uint32 (&data, &size);
2656 gst_asf_demux_get_uint32 (&data, &size);
2657 gst_asf_demux_get_uint32 (&data, &size);
2658 gst_asf_demux_get_guid (&guid, &data, &size);
2659 gst_asf_demux_get_uint32 (&data, &size);
2660 stream_type = ASF_STREAM_AUDIO;
2664 switch (stream_type) {
2665 case ASF_STREAM_AUDIO:{
2666 asf_stream_audio audio_object;
2668 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2669 goto not_enough_data;
2671 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2674 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2677 switch (correction_type) {
2678 case ASF_CORRECTION_ON:{
2679 guint span, packet_size, chunk_size, data_size, silence_data;
2681 GST_INFO ("Using error correction");
2683 if (size < (1 + 2 + 2 + 2 + 1))
2684 goto not_enough_data;
2686 span = gst_asf_demux_get_uint8 (&data, &size);
2687 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2688 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2689 data_size = gst_asf_demux_get_uint16 (&data, &size);
2690 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2692 /* FIXME: shouldn't this be per-stream? */
2695 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2696 packet_size, chunk_size, data_size, span, silence_data);
2698 if (demux->span > 1) {
2699 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2700 /* Disable descrambling */
2703 /* FIXME: this else branch was added for
2704 * weird_al_yankovic - the saga begins.asf */
2705 demux->ds_packet_size = packet_size;
2706 demux->ds_chunk_size = chunk_size;
2709 /* Descambling is enabled */
2710 demux->ds_packet_size = packet_size;
2711 demux->ds_chunk_size = chunk_size;
2714 /* Now skip the rest of the silence data */
2716 gst_bytestream_flush (demux->bs, data_size - 1);
2718 /* FIXME: CHECKME. And why -1? */
2719 if (data_size > 1) {
2720 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2721 goto not_enough_data;
2727 case ASF_CORRECTION_OFF:{
2728 GST_INFO ("Error correction off");
2729 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2730 goto not_enough_data;
2734 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2735 ("Audio stream using unknown error correction"));
2742 case ASF_STREAM_VIDEO:{
2743 asf_stream_video_format video_format_object;
2744 asf_stream_video video_object;
2747 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2748 goto not_enough_data;
2750 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2752 GST_INFO ("object is a video stream with %u bytes of "
2753 "additional data", vsize);
2755 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2757 goto not_enough_data;
2760 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2767 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2769 demux->other_streams =
2770 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
2774 stream = gst_asf_demux_get_stream (demux, stream_id);
2776 stream->inspect_payload = inspect_payload;
2781 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2782 /* we'll error out later if we found no streams */
2787 static const gchar *
2788 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2792 const gchar *asf_name;
2793 const gchar *gst_name;
2796 "WM/Genre", GST_TAG_GENRE}, {
2797 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2798 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2799 "WM/Picture", GST_TAG_IMAGE}, {
2800 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2801 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2802 "WM/Year", GST_TAG_DATE_TIME}
2803 /* { "WM/Composer", GST_TAG_COMPOSER } */
2808 if (name_utf8 == NULL) {
2809 GST_WARNING ("Failed to convert name to UTF8, skipping");
2813 out = strlen (name_utf8);
2815 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2816 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2817 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2818 return tags[i].gst_name;
2825 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2827 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2831 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2833 if (taglist == NULL)
2836 if (gst_tag_list_is_empty (taglist)) {
2837 gst_tag_list_unref (taglist);
2841 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2842 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
2844 gst_tag_list_unref (demux->taglist);
2845 gst_tag_list_unref (taglist);
2847 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2850 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2851 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2852 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2855 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2859 const guint8 *img_data = NULL;
2860 guint32 img_data_len = 0;
2861 guint8 pic_type = 0;
2863 gst_byte_reader_init (&r, tag_data, tag_data_len);
2865 /* skip mime type string (we don't trust it and do our own typefinding),
2866 * and also skip the description string, since we don't use it */
2867 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2868 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2869 !gst_byte_reader_skip_string_utf16 (&r) ||
2870 !gst_byte_reader_skip_string_utf16 (&r) ||
2871 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2872 goto not_enough_data;
2876 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2877 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2883 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2884 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2889 /* Extended Content Description Object */
2890 static GstFlowReturn
2891 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2894 /* Other known (and unused) 'text/unicode' metadata available :
2897 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2898 * WMFSDKVersion = 9.00.00.2980
2899 * WMFSDKNeeded = 0.0.0.0000
2900 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2901 * WM/Publisher = 4AD
2903 * WM/ProviderRating = 8
2904 * WM/ProviderStyle = Rock (similar to WM/Genre)
2905 * WM/GenreID (similar to WM/Genre)
2906 * WM/TrackNumber (same as WM/Track but as a string)
2908 * Other known (and unused) 'non-text' metadata available :
2914 * We might want to read WM/TrackNumber and use atoi() if we don't have
2918 GstTagList *taglist;
2919 guint16 blockcount, i;
2921 GST_INFO_OBJECT (demux, "object is an extended content description");
2923 taglist = gst_tag_list_new_empty ();
2925 /* Content Descriptor Count */
2927 goto not_enough_data;
2929 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2931 for (i = 1; i <= blockcount; ++i) {
2932 const gchar *gst_tag_name;
2936 GValue tag_value = { 0, };
2939 gchar *name_utf8 = NULL;
2943 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2944 goto not_enough_data;
2948 goto not_enough_data;
2950 /* Descriptor Value Data Type */
2951 datatype = gst_asf_demux_get_uint16 (&data, &size);
2953 /* Descriptor Value (not really a string, but same thing reading-wise) */
2954 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2956 goto not_enough_data;
2960 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2962 if (name_utf8 != NULL) {
2963 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2965 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2966 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2969 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2972 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2975 /* get rid of tags with empty value */
2976 if (value_utf8 != NULL && *value_utf8 != '\0') {
2977 GST_DEBUG ("string value %s", value_utf8);
2979 value_utf8[out] = '\0';
2981 if (gst_tag_name != NULL) {
2982 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
2983 guint year = atoi (value_utf8);
2986 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
2987 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
2989 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2990 guint id3v1_genre_id;
2991 const gchar *genre_str;
2993 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2994 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2995 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2996 g_free (value_utf8);
2997 value_utf8 = g_strdup (genre_str);
3002 /* convert tag from string to other type if required */
3003 tag_type = gst_tag_get_type (gst_tag_name);
3004 g_value_init (&tag_value, tag_type);
3005 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3006 GValue from_val = { 0, };
3008 g_value_init (&from_val, G_TYPE_STRING);
3009 g_value_set_string (&from_val, value_utf8);
3010 if (!g_value_transform (&from_val, &tag_value)) {
3011 GST_WARNING_OBJECT (demux,
3012 "Could not transform string tag to " "%s tag type %s",
3013 gst_tag_name, g_type_name (tag_type));
3014 g_value_unset (&tag_value);
3016 g_value_unset (&from_val);
3021 GST_DEBUG ("Setting metadata");
3022 g_value_init (&tag_value, G_TYPE_STRING);
3023 g_value_set_string (&tag_value, value_utf8);
3025 } else if (value_utf8 == NULL) {
3026 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3028 GST_DEBUG ("Skipping empty string value for %s",
3029 GST_STR_NULL (gst_tag_name));
3031 g_free (value_utf8);
3034 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3036 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3037 GST_FIXME ("Unhandled byte array tag %s",
3038 GST_STR_NULL (gst_tag_name));
3041 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3047 case ASF_DEMUX_DATA_TYPE_DWORD:{
3048 guint uint_val = GST_READ_UINT32_LE (value);
3050 /* this is the track number */
3051 g_value_init (&tag_value, G_TYPE_UINT);
3053 /* WM/Track counts from 0 */
3054 if (!strcmp (name_utf8, "WM/Track"))
3057 g_value_set_uint (&tag_value, uint_val);
3061 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3066 if (G_IS_VALUE (&tag_value)) {
3068 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3070 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3071 * is supposed to have a 0 base but is often wrongly written to start
3072 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3073 * replace the value added earlier from WM/Track or put it first in
3074 * the list, so that it will get picked up by _get_uint() */
3075 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3076 merge_mode = GST_TAG_MERGE_REPLACE;
3078 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3081 GST_DEBUG ("Setting global metadata %s", name_utf8);
3082 gst_structure_set_value (demux->global_metadata, name_utf8,
3086 g_value_unset (&tag_value);
3095 gst_asf_demux_add_global_tags (demux, taglist);
3102 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3103 gst_tag_list_unref (taglist);
3104 return GST_FLOW_OK; /* not really fatal */
3108 static GstStructure *
3109 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3114 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3116 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3119 s = gst_caps_get_structure (demux->metadata, i);
3120 if (gst_structure_has_name (s, sname))
3124 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3126 /* try lookup again; demux->metadata took ownership of the structure, so we
3127 * can't really make any assumptions about what happened to it, so we can't
3128 * just return it directly after appending it */
3129 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3132 static GstFlowReturn
3133 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3136 guint16 blockcount, i;
3138 GST_INFO_OBJECT (demux, "object is a metadata object");
3140 /* Content Descriptor Count */
3142 goto not_enough_data;
3144 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3146 for (i = 0; i < blockcount; ++i) {
3148 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3149 guint32 data_len, ival;
3152 if (size < (2 + 2 + 2 + 2 + 4))
3153 goto not_enough_data;
3155 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3156 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3157 name_len = gst_asf_demux_get_uint16 (&data, &size);
3158 data_type = gst_asf_demux_get_uint16 (&data, &size);
3159 data_len = gst_asf_demux_get_uint32 (&data, &size);
3161 if (size < name_len + data_len)
3162 goto not_enough_data;
3164 /* convert name to UTF-8 */
3165 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3167 gst_asf_demux_skip_bytes (name_len, &data, &size);
3169 if (name_utf8 == NULL) {
3170 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3171 gst_asf_demux_skip_bytes (data_len, &data, &size);
3175 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3176 gst_asf_demux_skip_bytes (data_len, &data, &size);
3184 goto not_enough_data;
3187 ival = gst_asf_demux_get_uint32 (&data, &size);
3189 /* skip anything else there may be, just in case */
3190 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3192 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3193 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3197 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3203 GST_WARNING ("Unexpected end of data parsing metadata object");
3204 return GST_FLOW_OK; /* not really fatal */
3208 static GstFlowReturn
3209 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3211 GstFlowReturn ret = GST_FLOW_OK;
3212 guint32 i, num_objects;
3213 guint8 unknown G_GNUC_UNUSED;
3215 /* Get the rest of the header's header */
3216 if (size < (4 + 1 + 1))
3217 goto not_enough_data;
3219 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3220 unknown = gst_asf_demux_get_uint8 (&data, &size);
3221 unknown = gst_asf_demux_get_uint8 (&data, &size);
3223 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3225 /* Loop through the header's objects, processing those */
3226 for (i = 0; i < num_objects; ++i) {
3227 GST_INFO_OBJECT (demux, "reading header part %u", i);
3228 ret = gst_asf_demux_process_object (demux, &data, &size);
3229 if (ret != GST_FLOW_OK) {
3230 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3239 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3240 ("short read parsing HEADER object"));
3241 return GST_FLOW_ERROR;
3245 static GstFlowReturn
3246 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3248 guint64 creation_time G_GNUC_UNUSED;
3249 guint64 file_size G_GNUC_UNUSED;
3250 guint64 send_time G_GNUC_UNUSED;
3251 guint64 packets_count, play_time, preroll;
3252 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3254 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3255 goto not_enough_data;
3257 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3258 file_size = gst_asf_demux_get_uint64 (&data, &size);
3259 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3260 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3261 play_time = gst_asf_demux_get_uint64 (&data, &size);
3262 send_time = gst_asf_demux_get_uint64 (&data, &size);
3263 preroll = gst_asf_demux_get_uint64 (&data, &size);
3264 flags = gst_asf_demux_get_uint32 (&data, &size);
3265 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3266 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3267 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3269 demux->broadcast = ! !(flags & 0x01);
3270 demux->seekable = ! !(flags & 0x02);
3272 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3273 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3274 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3276 if (demux->broadcast) {
3277 /* these fields are invalid if the broadcast flag is set */
3282 if (min_pktsize != max_pktsize)
3283 goto non_fixed_packet_size;
3285 demux->packet_size = max_pktsize;
3287 /* FIXME: do we need send_time as well? what is it? */
3288 if ((play_time * 100) >= (preroll * GST_MSECOND))
3289 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3291 demux->play_time = 0;
3293 demux->preroll = preroll * GST_MSECOND;
3295 /* initial latency */
3296 demux->latency = demux->preroll;
3298 if (demux->play_time == 0)
3299 demux->seekable = FALSE;
3301 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3302 GST_TIME_ARGS (demux->play_time));
3303 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3304 GST_TIME_ARGS (demux->preroll));
3306 if (demux->play_time > 0) {
3307 demux->segment.duration = demux->play_time;
3310 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3312 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3317 non_fixed_packet_size:
3319 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3320 ("packet size must be fixed"));
3321 return GST_FLOW_ERROR;
3325 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3326 ("short read parsing FILE object"));
3327 return GST_FLOW_ERROR;
3331 /* Content Description Object */
3332 static GstFlowReturn
3333 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3337 const gchar *gst_tag;
3342 GST_TAG_TITLE, 0, NULL}, {
3343 GST_TAG_ARTIST, 0, NULL}, {
3344 GST_TAG_COPYRIGHT, 0, NULL}, {
3345 GST_TAG_DESCRIPTION, 0, NULL}, {
3346 GST_TAG_COMMENT, 0, NULL}
3348 GstTagList *taglist;
3349 GValue value = { 0 };
3353 GST_INFO_OBJECT (demux, "object is a comment");
3355 if (size < (2 + 2 + 2 + 2 + 2))
3356 goto not_enough_data;
3358 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3359 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3360 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3361 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3362 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3364 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3365 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3366 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3368 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3369 if (size < tags[i].val_length)
3370 goto not_enough_data;
3372 /* might be just '/0', '/0'... */
3373 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3374 /* convert to UTF-8 */
3375 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3376 "UTF-8", "UTF-16LE", &in, &out, NULL);
3378 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3381 /* parse metadata into taglist */
3382 taglist = gst_tag_list_new_empty ();
3383 g_value_init (&value, G_TYPE_STRING);
3384 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3385 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3386 g_value_set_string (&value, tags[i].val_utf8);
3387 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3388 tags[i].gst_tag, &value, NULL);
3391 g_value_unset (&value);
3393 gst_asf_demux_add_global_tags (demux, taglist);
3395 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3396 g_free (tags[i].val_utf8);
3402 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3403 "comment tag section %d, skipping comment object", i);
3404 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3405 g_free (tags[i].val_utf8);
3406 return GST_FLOW_OK; /* not really fatal */
3410 static GstFlowReturn
3411 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3414 guint16 num_streams, i;
3418 goto not_enough_data;
3420 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3422 GST_INFO ("object is a bitrate properties object with %u streams",
3425 if (size < (num_streams * (2 + 4)))
3426 goto not_enough_data;
3428 for (i = 0; i < num_streams; ++i) {
3432 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3433 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3435 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3436 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3437 stream = gst_asf_demux_get_stream (demux, stream_id);
3439 if (stream->pending_tags == NULL) {
3440 stream->pending_tags =
3441 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3444 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3447 GST_WARNING ("stream id %u is too large", stream_id);
3455 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3456 return GST_FLOW_OK; /* not really fatal */
3460 static GstFlowReturn
3461 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3464 GstFlowReturn ret = GST_FLOW_OK;
3467 /* Get the rest of the header's header */
3468 if (size < (16 + 2 + 4))
3469 goto not_enough_data;
3471 /* skip GUID and two other bytes */
3472 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3473 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3475 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3477 /* FIXME: does data_size include the rest of the header that we have read? */
3478 if (hdr_size > size)
3479 goto not_enough_data;
3481 while (hdr_size > 0) {
3482 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3483 if (ret != GST_FLOW_OK)
3491 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3492 ("short read parsing extended header object"));
3493 return GST_FLOW_ERROR;
3497 static GstFlowReturn
3498 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3504 goto not_enough_data;
3506 if (demux->languages) {
3507 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3508 g_strfreev (demux->languages);
3509 demux->languages = NULL;
3510 demux->num_languages = 0;
3513 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3514 GST_LOG ("%u languages:", demux->num_languages);
3516 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3517 for (i = 0; i < demux->num_languages; ++i) {
3518 guint8 len, *lang_data = NULL;
3521 goto not_enough_data;
3522 len = gst_asf_demux_get_uint8 (&data, &size);
3523 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3526 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3529 /* truncate "en-us" etc. to just "en" */
3530 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3533 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3534 demux->languages[i] = utf8;
3537 goto not_enough_data;
3545 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3546 g_free (demux->languages);
3547 demux->languages = NULL;
3548 return GST_FLOW_OK; /* not fatal */
3552 static GstFlowReturn
3553 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3556 GstClockTime interval;
3559 if (size < (16 + 8 + 4 + 4))
3560 goto not_enough_data;
3563 gst_asf_demux_skip_bytes (16, &data, &size);
3564 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3565 gst_asf_demux_skip_bytes (4, &data, &size);
3566 count = gst_asf_demux_get_uint32 (&data, &size);
3568 demux->sidx_interval = interval;
3569 demux->sidx_num_entries = count;
3570 g_free (demux->sidx_entries);
3571 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3573 for (i = 0; i < count; ++i) {
3574 if (G_UNLIKELY (size <= 6))
3576 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3577 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3578 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3579 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3580 demux->sidx_entries[i].count);
3583 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3590 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3591 return GST_FLOW_OK; /* not fatal */
3595 static GstFlowReturn
3596 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3597 guint8 * data, guint64 size)
3603 if (size < 16 + 2 + (2 * 2))
3604 goto not_enough_data;
3606 gst_asf_demux_get_guid (&guid, &data, &size);
3607 num = gst_asf_demux_get_uint16 (&data, &size);
3610 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3614 if (size < (num * sizeof (guint16)))
3615 goto not_enough_data;
3617 /* read mutually exclusive stream numbers */
3618 mes = g_new (guint8, num + 1);
3619 for (i = 0; i < num; ++i) {
3620 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3621 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3624 /* add terminator so we can easily get the count or know when to stop */
3625 mes[i] = (guint8) - 1;
3627 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3634 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3635 return GST_FLOW_OK; /* not absolutely fatal */
3640 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3642 return g_slist_find (demux->other_streams,
3643 GINT_TO_POINTER (stream_num)) == NULL;
3646 static GstFlowReturn
3647 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3650 AsfStreamExtProps esp;
3651 AsfStream *stream = NULL;
3652 AsfObject stream_obj;
3653 guint16 stream_name_count;
3654 guint16 num_payload_ext;
3656 guint8 *stream_obj_data = NULL;
3659 guint i, stream_num;
3662 obj_size = (guint) size;
3665 goto not_enough_data;
3668 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3669 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3670 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3671 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3672 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3673 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3674 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3675 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3676 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3677 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3678 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3679 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3680 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3681 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3682 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3684 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3685 GST_TIME_ARGS (esp.start_time));
3686 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3687 GST_TIME_ARGS (esp.end_time));
3688 GST_INFO ("flags = %08x", esp.flags);
3689 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3690 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3691 GST_INFO ("stream number = %u", stream_num);
3692 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3693 (esp.lang_idx < demux->num_languages) ?
3694 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3695 GST_INFO ("stream name count = %u", stream_name_count);
3697 /* read stream names */
3698 for (i = 0; i < stream_name_count; ++i) {
3699 guint16 stream_lang_idx G_GNUC_UNUSED;
3700 gchar *stream_name = NULL;
3703 goto not_enough_data;
3704 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3705 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3706 goto not_enough_data;
3707 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3708 g_free (stream_name); /* TODO: store names in struct */
3711 /* read payload extension systems stuff */
3712 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3714 if (num_payload_ext > 0)
3715 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3717 esp.payload_extensions = NULL;
3719 for (i = 0; i < num_payload_ext; ++i) {
3720 AsfPayloadExtension ext;
3722 guint32 sys_info_len;
3724 if (size < 16 + 2 + 4)
3725 goto not_enough_data;
3727 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3728 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3729 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3731 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3732 GST_LOG ("payload systems info len = %u", sys_info_len);
3733 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3734 goto not_enough_data;
3736 esp.payload_extensions[i] = ext;
3739 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3741 /* there might be an optional STREAM_INFO object here now; if not, we
3742 * should have parsed the corresponding stream info object already (since
3743 * we are parsing the extended stream properties objects delayed) */
3745 stream = gst_asf_demux_get_stream (demux, stream_num);
3749 /* get size of the stream object */
3750 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3751 goto not_enough_data;
3753 if (stream_obj.id != ASF_OBJ_STREAM)
3754 goto expected_stream_object;
3756 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3757 stream_obj.size > (10 * 1024 * 1024))
3758 goto not_enough_data;
3760 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3762 /* process this stream object later after all the other 'normal' ones
3763 * have been processed (since the others are more important/non-hidden) */
3764 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3765 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3766 goto not_enough_data;
3768 /* parse stream object */
3769 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3770 g_free (stream_obj_data);
3775 stream->ext_props = esp;
3777 /* try to set the framerate */
3778 if (stream->is_video && stream->caps) {
3779 GValue framerate = { 0 };
3783 g_value_init (&framerate, GST_TYPE_FRACTION);
3785 num = GST_SECOND / 100;
3786 denom = esp.avg_time_per_frame;
3788 /* avoid division by 0, assume 25/1 framerate */
3789 denom = GST_SECOND / 2500;
3792 gst_value_set_fraction (&framerate, num, denom);
3794 stream->caps = gst_caps_make_writable (stream->caps);
3795 s = gst_caps_get_structure (stream->caps, 0);
3796 gst_structure_set_value (s, "framerate", &framerate);
3797 g_value_unset (&framerate);
3798 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3799 num, denom, ((gdouble) num) / denom);
3802 /* add language info now if we have it */
3803 if (stream->ext_props.lang_idx < demux->num_languages) {
3804 if (stream->pending_tags == NULL)
3805 stream->pending_tags = gst_tag_list_new_empty ();
3806 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3807 demux->languages[stream->ext_props.lang_idx]);
3808 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3809 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3812 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
3813 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3821 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3822 return GST_FLOW_OK; /* not absolutely fatal */
3824 expected_stream_object:
3826 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3827 "object: expected embedded stream object, but got %s object instead!",
3828 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3829 return GST_FLOW_OK; /* not absolutely fatal */
3833 static const gchar *
3834 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3838 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3839 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3840 nick += strlen ("ASF_OBJ_");
3842 if (demux->objpath == NULL) {
3843 demux->objpath = g_strdup (nick);
3847 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3848 g_free (demux->objpath);
3849 demux->objpath = newpath;
3852 return (const gchar *) demux->objpath;
3856 gst_asf_demux_pop_obj (GstASFDemux * demux)
3860 if ((s = g_strrstr (demux->objpath, "/"))) {
3863 g_free (demux->objpath);
3864 demux->objpath = NULL;
3869 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3874 /* Parse the queued extended stream property objects and add the info
3875 * to the existing streams or add the new embedded streams, but without
3876 * activating them yet */
3877 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3878 g_slist_length (demux->ext_stream_props));
3880 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3881 GstBuffer *buf = GST_BUFFER (l->data);
3884 gst_buffer_map (buf, &map, GST_MAP_READ);
3886 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3887 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
3888 gst_buffer_unmap (buf, &map);
3889 gst_buffer_unref (buf);
3891 g_slist_free (demux->ext_stream_props);
3892 demux->ext_stream_props = NULL;
3897 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3901 for (i = 0; i < demux->num_streams; ++i) {
3906 stream = &demux->stream[i];
3908 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3910 if (stream->active) {
3911 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3916 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3919 /* check for each mutual exclusion whether it affects this stream */
3920 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3921 if (*mes == stream->id) {
3922 /* if yes, check if we've already added streams that are mutually
3923 * exclusive with the stream we're about to add */
3924 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3925 for (j = 0; j < demux->num_streams; ++j) {
3926 /* if the broadcast flag is set, assume the hidden streams aren't
3927 * actually streamed and hide them (or playbin won't work right),
3928 * otherwise assume their data is available */
3929 if (demux->stream[j].id == *mes && demux->broadcast) {
3931 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3932 "mutually exclusive with already existing stream ID %d, "
3933 "hiding stream", stream->id, demux->stream[j].id);
3945 /* FIXME: we should do stream activation based on preroll data in
3946 * streaming mode too */
3947 if (demux->streaming && !is_hidden)
3948 gst_asf_demux_activate_stream (demux, stream);
3953 static GstFlowReturn
3954 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3957 GstFlowReturn ret = GST_FLOW_OK;
3959 guint64 obj_data_size;
3961 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3962 return ASF_FLOW_NEED_MORE_DATA;
3964 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3965 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3967 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3969 if (*p_size < obj_data_size)
3970 return ASF_FLOW_NEED_MORE_DATA;
3972 gst_asf_demux_push_obj (demux, obj.id);
3974 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3977 case ASF_OBJ_STREAM:
3978 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3982 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3984 case ASF_OBJ_HEADER:
3985 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3987 case ASF_OBJ_COMMENT:
3988 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3991 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3993 case ASF_OBJ_BITRATE_PROPS:
3995 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3998 case ASF_OBJ_EXT_CONTENT_DESC:
4000 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4003 case ASF_OBJ_METADATA_OBJECT:
4004 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4006 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4009 /* process these later, we might not have parsed the corresponding
4010 * stream object yet */
4011 GST_LOG ("%s: queued for later parsing", demux->objpath);
4012 buf = gst_buffer_new_and_alloc (obj_data_size);
4013 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4014 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4018 case ASF_OBJ_LANGUAGE_LIST:
4019 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4021 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4022 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4025 case ASF_OBJ_SIMPLE_INDEX:
4026 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4028 case ASF_OBJ_CONTENT_ENCRYPTION:
4029 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4030 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4031 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4032 goto error_encrypted;
4033 case ASF_OBJ_CONCEAL_NONE:
4035 case ASF_OBJ_UNDEFINED:
4036 case ASF_OBJ_CODEC_COMMENT:
4038 case ASF_OBJ_PADDING:
4039 case ASF_OBJ_BITRATE_MUTEX:
4040 case ASF_OBJ_COMPATIBILITY:
4041 case ASF_OBJ_INDEX_PLACEHOLDER:
4042 case ASF_OBJ_INDEX_PARAMETERS:
4043 case ASF_OBJ_STREAM_PRIORITIZATION:
4044 case ASF_OBJ_SCRIPT_COMMAND:
4046 /* Unknown/unhandled object, skip it and hope for the best */
4047 GST_INFO ("%s: skipping object", demux->objpath);
4052 /* this can't fail, we checked the number of bytes available before */
4053 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4055 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4057 gst_asf_demux_pop_obj (demux);
4064 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4065 return GST_FLOW_ERROR;
4070 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4071 GstBuffer ** p_buffer)
4073 GstBuffer *descrambled_buffer;
4074 GstBuffer *scrambled_buffer;
4075 GstBuffer *sub_buffer;
4082 /* descrambled_buffer is initialised in the first iteration */
4083 descrambled_buffer = NULL;
4084 scrambled_buffer = *p_buffer;
4086 if (gst_buffer_get_size (scrambled_buffer) <
4087 demux->ds_packet_size * demux->span)
4090 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4091 offset += demux->ds_chunk_size) {
4092 off = offset / demux->ds_chunk_size;
4093 row = off / demux->span;
4094 col = off % demux->span;
4095 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
4096 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4097 col, off, demux->ds_chunk_size);
4098 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4099 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4100 demux->span, demux->ds_packet_size);
4101 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4102 gst_buffer_get_size (scrambled_buffer));
4104 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_NONE,
4105 idx * demux->ds_chunk_size, demux->ds_chunk_size);
4107 descrambled_buffer = sub_buffer;
4109 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4113 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4114 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4115 GST_BUFFER_DURATION (descrambled_buffer) =
4116 GST_BUFFER_DURATION (scrambled_buffer);
4117 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4118 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4119 GST_BUFFER_OFFSET_END (scrambled_buffer);
4121 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4123 gst_buffer_unref (scrambled_buffer);
4124 *p_buffer = descrambled_buffer;
4128 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4130 GstASFDemux *demux = GST_ASF_DEMUX (element);
4133 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4135 for (i = 0; i < demux->num_streams; ++i) {
4136 gst_event_ref (event);
4137 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4138 GST_OBJECT_CAST (element), event)) {
4139 gst_event_unref (event);
4144 gst_event_unref (event);
4148 /* takes ownership of the passed event */
4150 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4152 gboolean ret = TRUE;
4155 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4156 GST_EVENT_TYPE_NAME (event));
4158 for (i = 0; i < demux->num_streams; ++i) {
4159 gst_event_ref (event);
4160 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4162 gst_event_unref (event);
4167 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4171 gboolean res = FALSE;
4173 demux = GST_ASF_DEMUX (parent);
4175 GST_DEBUG ("handling %s query",
4176 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4178 switch (GST_QUERY_TYPE (query)) {
4179 case GST_QUERY_DURATION:
4183 gst_query_parse_duration (query, &format, NULL);
4185 if (format != GST_FORMAT_TIME) {
4186 GST_LOG ("only support duration queries in TIME format");
4190 GST_OBJECT_LOCK (demux);
4192 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4193 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4194 GST_TIME_ARGS (demux->segment.duration));
4196 gst_query_set_duration (query, GST_FORMAT_TIME,
4197 demux->segment.duration);
4201 GST_LOG ("duration not known yet");
4204 GST_OBJECT_UNLOCK (demux);
4208 case GST_QUERY_POSITION:{
4211 gst_query_parse_position (query, &format, NULL);
4213 if (format != GST_FORMAT_TIME) {
4214 GST_LOG ("only support position queries in TIME format");
4218 GST_OBJECT_LOCK (demux);
4220 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4221 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4222 GST_TIME_ARGS (demux->segment.position));
4224 gst_query_set_position (query, GST_FORMAT_TIME,
4225 demux->segment.position);
4229 GST_LOG ("position not known yet");
4232 GST_OBJECT_UNLOCK (demux);
4236 case GST_QUERY_SEEKING:{
4239 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4240 if (format == GST_FORMAT_TIME) {
4243 GST_OBJECT_LOCK (demux);
4244 duration = demux->segment.duration;
4245 GST_OBJECT_UNLOCK (demux);
4247 if (!demux->streaming || !demux->seekable) {
4248 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4255 /* try downstream first in TIME */
4256 res = gst_pad_query_default (pad, parent, query);
4258 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4259 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4260 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4261 /* if no luck, maybe in BYTES */
4262 if (!seekable || fmt != GST_FORMAT_TIME) {
4265 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4266 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4267 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4268 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4269 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4270 if (fmt != GST_FORMAT_BYTES)
4273 gst_query_unref (q);
4274 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4280 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4284 case GST_QUERY_LATENCY:
4287 GstClockTime min, max;
4289 /* preroll delay does not matter in non-live pipeline,
4290 * but we might end up in a live (rtsp) one ... */
4293 res = gst_pad_query_default (pad, parent, query);
4297 gst_query_parse_latency (query, &live, &min, &max);
4299 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4300 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4301 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4303 GST_OBJECT_LOCK (demux);
4305 min += demux->latency;
4307 max += demux->latency;
4308 GST_OBJECT_UNLOCK (demux);
4310 gst_query_set_latency (query, live, min, max);
4313 case GST_QUERY_SEGMENT:
4318 format = demux->segment.format;
4321 gst_segment_to_stream_time (&demux->segment, format,
4322 demux->segment.start);
4323 if ((stop = demux->segment.stop) == -1)
4324 stop = demux->segment.duration;
4326 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4328 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4333 res = gst_pad_query_default (pad, parent, query);
4340 static GstStateChangeReturn
4341 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4343 GstASFDemux *demux = GST_ASF_DEMUX (element);
4344 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4346 switch (transition) {
4347 case GST_STATE_CHANGE_NULL_TO_READY:{
4348 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4349 demux->need_newsegment = TRUE;
4350 demux->segment_running = FALSE;
4351 demux->accurate = FALSE;
4352 demux->adapter = gst_adapter_new ();
4353 demux->metadata = gst_caps_new_empty ();
4354 demux->global_metadata = gst_structure_new_empty ("metadata");
4355 demux->data_size = 0;
4356 demux->data_offset = 0;
4357 demux->index_offset = 0;
4358 demux->base_offset = 0;
4365 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4366 if (ret == GST_STATE_CHANGE_FAILURE)
4369 switch (transition) {
4370 case GST_STATE_CHANGE_PAUSED_TO_READY:
4371 case GST_STATE_CHANGE_READY_TO_NULL:
4372 gst_asf_demux_reset (demux, FALSE);