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_first_ts (GstASFDemux * demux, gboolean force)
1320 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1321 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1324 /* go trhough each stream, find smallest timestamp */
1325 for (i = 0; i < demux->num_streams; ++i) {
1328 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1329 stream = &demux->stream[i];
1331 for (j = 0; j < stream->payloads->len; ++j) {
1332 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1333 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1334 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1335 || stream_min_ts > payload->ts))
1336 stream_min_ts = payload->ts;
1339 /* if we don't have timestamp for this stream, wait for more data */
1340 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1343 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1344 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1345 first_ts = stream_min_ts;
1348 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1351 demux->first_ts = first_ts;
1353 /* update packets queued before we knew first timestamp */
1354 for (i = 0; i < demux->num_streams; ++i) {
1357 stream = &demux->stream[i];
1359 for (j = 0; j < stream->payloads->len; ++j) {
1360 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1361 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1362 if (payload->ts > first_ts)
1363 payload->ts -= first_ts;
1370 /* remember the first queued timestamp for the segment */
1371 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts))) {
1372 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1373 GST_TIME_ARGS (first_ts));
1374 demux->segment_ts = first_ts;
1375 /* always note, but only determines segment when streaming */
1376 if (demux->streaming)
1377 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1378 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1379 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1387 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1389 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1390 and often set wrong, inspecting the data is the only way that seem to be working */
1391 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1392 GstCaps *caps = NULL;
1393 GstAdapter *adapter = gst_adapter_new ();
1395 for (int i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1397 AsfPayload *payload;
1400 payload = &g_array_index (stream->payloads, AsfPayload, i);
1401 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1402 len = gst_adapter_available (adapter);
1403 data = gst_adapter_map (adapter, len);
1407 #define MIN_LENGTH 128
1409 /* look for the sync points */
1411 if (len < MIN_LENGTH || /* give typefind something to work on */
1412 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1413 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1419 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1422 if (prob < GST_TYPE_FIND_LIKELY) {
1425 if (len > MIN_LENGTH)
1426 /* this wasn't it, look for another sync point */
1430 gst_adapter_unmap (adapter);
1433 gst_object_unref (adapter);
1436 gst_caps_take (&stream->caps, caps);
1444 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1448 if (demux->activated_streams)
1451 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1454 if (!all_streams_prerolled (demux) && !force) {
1455 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1459 for (i = 0; i < demux->num_streams; ++i) {
1460 AsfStream *stream = &demux->stream[i];
1462 if (stream->payloads->len > 0) {
1464 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1465 !stream->active && /* do not inspect active streams (caps were already set) */
1466 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1467 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1468 /* try to gather some more data */
1471 /* we don't check mutual exclusion stuff here; either we have data for
1472 * a stream, then we active it, or we don't, then we'll ignore it */
1473 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1474 gst_asf_demux_activate_stream (demux, stream);
1476 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1480 gst_asf_demux_release_old_pads (demux);
1482 demux->activated_streams = TRUE;
1483 GST_LOG_OBJECT (demux, "signalling no more pads");
1484 gst_element_no_more_pads (GST_ELEMENT (demux));
1488 /* returns the stream that has a complete payload with the lowest timestamp
1489 * queued, or NULL (we push things by timestamp because during the internal
1490 * prerolling we might accumulate more data then the external queues can take,
1491 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1493 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1495 AsfPayload *best_payload = NULL;
1496 AsfStream *best_stream = NULL;
1499 for (i = 0; i < demux->num_streams; ++i) {
1503 stream = &demux->stream[i];
1505 /* Don't push any data until we have at least one payload that falls within
1506 * the current segment. This way we can remove out-of-segment payloads that
1507 * don't need to be decoded after a seek, sending only data from the
1508 * keyframe directly before our segment start */
1509 if (stream->payloads->len > 0) {
1510 AsfPayload *payload = NULL;
1513 /* find last payload with timestamp */
1514 for (last_idx = stream->payloads->len - 1;
1515 last_idx >= 0 && (payload == NULL
1516 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1517 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1519 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1520 (payload->ts < demux->segment.start))) {
1521 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1522 GST_DEBUG_OBJECT (stream->pad,
1523 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1524 GST_TIME_ARGS (payload->ts));
1525 demux->segment.start = payload->ts;
1526 demux->segment.time = payload->ts;
1528 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1529 GST_TIME_FORMAT " which is before our segment start %"
1530 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1531 GST_TIME_ARGS (demux->segment.start));
1536 /* Now see if there's a complete payload queued for this stream */
1539 /* find first complete payload with timestamp */
1541 j < stream->payloads->len && (payload == NULL
1542 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1543 payload = &g_array_index (stream->payloads, AsfPayload, j);
1546 if (!gst_asf_payload_is_complete (payload))
1549 /* ... and whether its timestamp is lower than the current best */
1550 if (best_stream == NULL || best_payload->ts > payload->ts) {
1551 best_stream = stream;
1552 best_payload = payload;
1560 static GstFlowReturn
1561 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1564 GstFlowReturn ret = GST_FLOW_OK;
1566 if (G_UNLIKELY (!demux->activated_streams)) {
1567 if (!gst_asf_demux_check_activate_streams (demux, force))
1569 /* streams are now activated */
1572 /* wait until we had a chance to "lock on" some payload's timestamp */
1573 if (G_UNLIKELY (demux->need_newsegment
1574 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1577 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1578 AsfPayload *payload;
1580 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1582 /* do we need to send a newsegment event */
1583 if ((G_UNLIKELY (demux->need_newsegment))) {
1584 GstEvent *segment_event;
1586 /* safe default if insufficient upstream info */
1587 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1590 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1591 demux->segment.duration > 0) {
1592 /* slight HACK; prevent clipping of last bit */
1593 demux->segment.stop = demux->segment.duration + demux->in_gap;
1596 /* FIXME : only if ACCURATE ! */
1597 if (G_LIKELY (!demux->accurate
1598 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1599 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1600 GST_TIME_ARGS (payload->ts));
1601 demux->segment.start = payload->ts;
1602 demux->segment.time = payload->ts;
1605 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1608 /* note: we fix up all timestamps to start from 0, so this should be ok */
1609 segment_event = gst_event_new_segment (&demux->segment);
1610 if (demux->segment_seqnum)
1611 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1612 gst_asf_demux_send_event_unlocked (demux, segment_event);
1614 /* now post any global tags we may have found */
1615 if (demux->taglist == NULL) {
1616 demux->taglist = gst_tag_list_new_empty ();
1617 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1620 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1621 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1623 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1624 gst_asf_demux_send_event_unlocked (demux,
1625 gst_event_new_tag (demux->taglist));
1626 demux->taglist = NULL;
1628 demux->need_newsegment = FALSE;
1629 demux->segment_seqnum = 0;
1630 demux->segment_running = TRUE;
1633 /* Do we have tags pending for this stream? */
1634 if (G_UNLIKELY (stream->pending_tags)) {
1635 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1636 gst_pad_push_event (stream->pad,
1637 gst_event_new_tag (stream->pending_tags));
1638 stream->pending_tags = NULL;
1641 /* We have the whole packet now so we should push the packet to
1642 * the src pad now. First though we should check if we need to do
1644 if (G_UNLIKELY (demux->span > 1)) {
1645 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1648 payload->buf = gst_buffer_make_writable (payload->buf);
1650 if (G_LIKELY (!payload->keyframe)) {
1651 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1654 if (G_UNLIKELY (stream->discont)) {
1655 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1656 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1657 stream->discont = FALSE;
1660 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1661 (payload->par_x != stream->par_x) &&
1662 (payload->par_y != stream->par_y))) {
1663 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1664 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1665 stream->par_x = payload->par_x;
1666 stream->par_y = payload->par_y;
1667 stream->caps = gst_caps_make_writable (stream->caps);
1668 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1669 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1670 gst_pad_set_caps (stream->pad, stream->caps);
1673 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1674 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1675 payload->interlaced);
1676 stream->interlaced = payload->interlaced;
1677 stream->caps = gst_caps_make_writable (stream->caps);
1678 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1679 (stream->interlaced ? "mixed" : "progressive"), NULL);
1680 gst_pad_set_caps (stream->pad, stream->caps);
1683 /* (sort of) interpolate timestamps using upstream "frame of reference",
1684 * typically useful for live src, but might (unavoidably) mess with
1685 * position reporting if a live src is playing not so live content
1686 * (e.g. rtspsrc taking some time to fall back to tcp) */
1687 GST_BUFFER_PTS (payload->buf) = payload->ts;
1688 if (GST_BUFFER_PTS_IS_VALID (payload->buf)) {
1689 GST_BUFFER_PTS (payload->buf) += demux->in_gap;
1691 if (payload->duration == GST_CLOCK_TIME_NONE
1692 && stream->ext_props.avg_time_per_frame != 0)
1693 GST_BUFFER_DURATION (payload->buf) =
1694 stream->ext_props.avg_time_per_frame * 100;
1696 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1698 /* FIXME: we should really set durations on buffers if we can */
1700 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1701 ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
1702 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1703 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1704 gst_buffer_get_size (payload->buf));
1706 if (stream->active) {
1707 ret = gst_pad_push (stream->pad, payload->buf);
1708 ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1710 gst_buffer_unref (payload->buf);
1713 payload->buf = NULL;
1714 g_array_remove_index (stream->payloads, 0);
1716 /* Break out as soon as we have an issue */
1717 if (G_UNLIKELY (ret != GST_FLOW_OK))
1725 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1729 g_assert (buf != NULL);
1731 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1733 gst_buffer_map (buf, &map, GST_MAP_READ);
1735 /* we return false on buffer too small */
1736 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1737 gst_buffer_unmap (buf, &map);
1741 /* check if it is a header */
1742 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1743 gst_buffer_unmap (buf, &map);
1744 if (obj.id == ASF_OBJ_HEADER) {
1751 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1753 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1754 GstFlowReturn ret = GST_FLOW_OK;
1755 GstBuffer *buf = NULL;
1756 gboolean header = FALSE;
1758 /* TODO maybe we should skip index objects after the data and look
1759 * further for a new header */
1760 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1761 g_assert (buf != NULL);
1762 /* check if it is a header */
1763 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1764 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1765 demux->base_offset = off;
1769 gst_buffer_unref (buf);
1776 gst_asf_demux_loop (GstASFDemux * demux)
1778 GstFlowReturn flow = GST_FLOW_OK;
1779 GstBuffer *buf = NULL;
1781 gboolean sent_eos = FALSE;
1783 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1784 if (!gst_asf_demux_pull_headers (demux)) {
1785 flow = GST_FLOW_ERROR;
1789 gst_asf_demux_pull_indices (demux);
1792 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1794 if (G_UNLIKELY (demux->num_packets != 0
1795 && demux->packet >= demux->num_packets))
1798 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1799 (guint) demux->num_packets);
1801 off = demux->data_offset + (demux->packet * demux->packet_size);
1803 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1804 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1805 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1806 if (flow == GST_FLOW_EOS)
1808 else if (flow == GST_FLOW_FLUSHING) {
1809 GST_DEBUG_OBJECT (demux, "Not fatal");
1815 if (G_LIKELY (demux->speed_packets == 1)) {
1816 GstAsfDemuxParsePacketError err;
1817 err = gst_asf_demux_parse_packet (demux, buf);
1818 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1819 /* when we don't know when the data object ends, we should check
1820 * for a chained asf */
1821 if (demux->num_packets == 0) {
1822 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1823 GST_INFO_OBJECT (demux, "Chained asf found");
1824 demux->base_offset = off;
1825 gst_asf_demux_reset (demux, TRUE);
1826 gst_buffer_unref (buf);
1830 /* FIXME: We should tally up fatal errors and error out only
1831 * after a few broken packets in a row? */
1833 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1834 gst_buffer_unref (buf);
1839 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1845 for (n = 0; n < demux->speed_packets; n++) {
1847 GstAsfDemuxParsePacketError err;
1850 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1851 n * demux->packet_size, demux->packet_size);
1852 err = gst_asf_demux_parse_packet (demux, sub);
1853 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1854 /* when we don't know when the data object ends, we should check
1855 * for a chained asf */
1856 if (demux->num_packets == 0) {
1857 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1858 GST_INFO_OBJECT (demux, "Chained asf found");
1859 demux->base_offset = off + n * demux->packet_size;
1860 gst_asf_demux_reset (demux, TRUE);
1861 gst_buffer_unref (sub);
1862 gst_buffer_unref (buf);
1866 /* FIXME: We should tally up fatal errors and error out only
1867 * after a few broken packets in a row? */
1869 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1873 gst_buffer_unref (sub);
1875 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1876 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1882 /* reset speed pull */
1883 demux->speed_packets = 1;
1886 gst_buffer_unref (buf);
1888 if (G_UNLIKELY (demux->num_packets > 0
1889 && demux->packet >= demux->num_packets)) {
1890 GST_LOG_OBJECT (demux, "reached EOS");
1894 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1895 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1899 /* check if we're at the end of the configured segment */
1900 /* FIXME: check if segment end reached etc. */
1906 /* if we haven't activated our streams yet, this might be because we have
1907 * less data queued than required for preroll; force stream activation and
1908 * send any pending payloads before sending EOS */
1909 if (!demux->activated_streams)
1910 gst_asf_demux_push_complete_payloads (demux, TRUE);
1912 /* we want to push an eos or post a segment-done in any case */
1913 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1916 /* for segment playback we need to post when (in stream time)
1917 * we stopped, this is either stop (when set) or the duration. */
1918 if ((stop = demux->segment.stop) == -1)
1919 stop = demux->segment.duration;
1921 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1922 gst_element_post_message (GST_ELEMENT_CAST (demux),
1923 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1925 gst_asf_demux_send_event_unlocked (demux,
1926 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1927 } else if (flow != GST_FLOW_EOS) {
1928 /* check if we have a chained asf, in case, we don't eos yet */
1929 if (gst_asf_demux_check_chained_asf (demux)) {
1930 GST_INFO_OBJECT (demux, "Chained ASF starting");
1931 gst_asf_demux_reset (demux, TRUE);
1935 /* normal playback, send EOS to all linked pads */
1936 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1937 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1939 /* ... and fall through to pause */
1943 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1944 gst_flow_get_name (flow));
1945 demux->segment_running = FALSE;
1946 gst_pad_pause_task (demux->sinkpad);
1948 /* For the error cases (not EOS) */
1950 if (flow == GST_FLOW_EOS)
1951 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1952 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1953 /* Post an error. Hopefully something else already has, but if not... */
1954 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1955 (_("Internal data stream error.")),
1956 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1965 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1966 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1967 flow = GST_FLOW_EOS;
1971 /* See FIXMEs above */
1974 gst_buffer_unref (buf);
1975 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1976 ("Error parsing ASF packet %u", (guint) demux->packet));
1977 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1978 flow = GST_FLOW_ERROR;
1984 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
1985 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
1986 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1989 gst_asf_demux_check_header (GstASFDemux * demux)
1992 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
1993 ASF_OBJECT_HEADER_SIZE);
1994 if (cdata == NULL) /* need more data */
1995 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1997 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1998 if (obj.id != ASF_OBJ_HEADER) {
1999 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2001 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2005 static GstFlowReturn
2006 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2008 GstFlowReturn ret = GST_FLOW_OK;
2011 demux = GST_ASF_DEMUX (parent);
2013 GST_LOG_OBJECT (demux,
2014 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2015 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2016 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2018 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2019 GST_DEBUG_OBJECT (demux, "received DISCONT");
2020 gst_asf_demux_mark_discont (demux);
2023 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2024 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2025 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2026 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2027 ", interpolation gap: %" GST_TIME_FORMAT,
2028 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2031 gst_adapter_push (demux->adapter, buf);
2033 switch (demux->state) {
2034 case GST_ASF_DEMUX_STATE_INDEX:{
2035 gint result = gst_asf_demux_check_header (demux);
2036 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2039 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2040 /* we don't care about this, probably an index */
2041 /* TODO maybe would be smarter to skip all the indices
2042 * until we got a new header or EOS to decide */
2043 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2046 GST_INFO_OBJECT (demux, "Chained asf starting");
2047 /* cleanup and get ready for a chained asf */
2048 gst_asf_demux_reset (demux, TRUE);
2052 case GST_ASF_DEMUX_STATE_HEADER:{
2053 ret = gst_asf_demux_chain_headers (demux);
2054 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2056 /* otherwise fall through */
2058 case GST_ASF_DEMUX_STATE_DATA:
2062 data_size = demux->packet_size;
2064 while (gst_adapter_available (demux->adapter) >= data_size) {
2066 GstAsfDemuxParsePacketError err;
2068 /* we don't know the length of the stream
2069 * check for a chained asf everytime */
2070 if (demux->num_packets == 0) {
2071 gint result = gst_asf_demux_check_header (demux);
2073 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2074 GST_INFO_OBJECT (demux, "Chained asf starting");
2075 /* cleanup and get ready for a chained asf */
2076 gst_asf_demux_reset (demux, TRUE);
2079 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2080 && demux->packet >= demux->num_packets)) {
2081 /* do not overshoot data section when streaming */
2085 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2087 /* FIXME: We should tally up fatal errors and error out only
2088 * after a few broken packets in a row? */
2089 err = gst_asf_demux_parse_packet (demux, buf);
2091 gst_buffer_unref (buf);
2093 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2094 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2096 GST_WARNING_OBJECT (demux, "Parse error");
2098 if (demux->packet >= 0)
2101 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2102 && demux->packet >= demux->num_packets)) {
2103 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2108 g_assert_not_reached ();
2112 if (ret != GST_FLOW_OK)
2113 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2119 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2125 static inline gboolean
2126 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2128 if (*p_size < num_bytes)
2131 *p_data += num_bytes;
2132 *p_size -= num_bytes;
2136 static inline guint8
2137 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2141 g_assert (*p_size >= 1);
2142 ret = GST_READ_UINT8 (*p_data);
2143 *p_data += sizeof (guint8);
2144 *p_size -= sizeof (guint8);
2148 static inline guint16
2149 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2153 g_assert (*p_size >= 2);
2154 ret = GST_READ_UINT16_LE (*p_data);
2155 *p_data += sizeof (guint16);
2156 *p_size -= sizeof (guint16);
2160 static inline guint32
2161 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2165 g_assert (*p_size >= 4);
2166 ret = GST_READ_UINT32_LE (*p_data);
2167 *p_data += sizeof (guint32);
2168 *p_size -= sizeof (guint32);
2172 static inline guint64
2173 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2177 g_assert (*p_size >= 8);
2178 ret = GST_READ_UINT64_LE (*p_data);
2179 *p_data += sizeof (guint64);
2180 *p_size -= sizeof (guint64);
2184 static inline guint32
2185 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
2192 g_assert (*p_size >= 1);
2193 return gst_asf_demux_get_uint8 (p_data, p_size);
2196 g_assert (*p_size >= 2);
2197 return gst_asf_demux_get_uint16 (p_data, p_size);
2200 g_assert (*p_size >= 4);
2201 return gst_asf_demux_get_uint32 (p_data, p_size);
2204 g_assert_not_reached ();
2211 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2212 guint8 ** p_data, guint64 * p_size)
2216 if (*p_size < num_bytes_to_read)
2219 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2220 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2222 *p_data += num_bytes_to_read;
2223 *p_size -= num_bytes_to_read;
2229 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2230 guint8 ** p_data, guint64 * p_size)
2234 if (*p_size < num_bytes_to_read)
2237 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2238 *p_data += num_bytes_to_read;
2239 *p_size -= num_bytes_to_read;
2244 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2245 guint8 ** p_data, guint64 * p_size)
2255 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2258 *p_strlen = s_length;
2260 if (s_length == 0) {
2261 GST_WARNING ("zero-length string");
2262 *p_str = g_strdup ("");
2266 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2269 g_assert (s != NULL);
2271 /* just because They don't exist doesn't
2272 * mean They are not out to get you ... */
2273 if (s[s_length - 1] != '\0') {
2274 s = g_realloc (s, s_length + 1);
2278 *p_str = (gchar *) s;
2284 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2286 g_assert (*p_size >= 4 * sizeof (guint32));
2288 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2289 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2290 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2291 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2295 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2298 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2301 /* WAVEFORMATEX Structure */
2302 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2303 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2304 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2305 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2306 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2307 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2308 /* Codec specific data size */
2309 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2314 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2317 if (*p_size < (4 + 4 + 1 + 2))
2320 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2321 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2322 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2323 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2328 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2329 guint8 ** p_data, guint64 * p_size)
2331 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2334 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2335 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2336 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2337 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2338 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2339 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2340 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2341 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2342 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2343 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2344 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2349 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2353 for (i = 0; i < demux->num_streams; i++) {
2354 if (demux->stream[i].id == id)
2355 return &demux->stream[i];
2358 if (gst_asf_demux_is_unknown_stream (demux, id))
2359 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2364 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2365 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2369 gst_pad_use_fixed_caps (src_pad);
2370 gst_pad_set_caps (src_pad, caps);
2372 gst_pad_set_event_function (src_pad,
2373 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2374 gst_pad_set_query_function (src_pad,
2375 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2377 stream = &demux->stream[demux->num_streams];
2378 stream->caps = caps;
2379 stream->pad = src_pad;
2381 stream->fps_known = !is_video; /* bit hacky for audio */
2382 stream->is_video = is_video;
2383 stream->pending_tags = tags;
2384 stream->discont = TRUE;
2388 st = gst_caps_get_structure (caps, 0);
2389 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2390 par_x > 0 && par_y > 0) {
2391 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2392 stream->par_x = par_x;
2393 stream->par_y = par_y;
2397 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2399 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2400 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2402 ++demux->num_streams;
2404 stream->active = FALSE;
2408 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2409 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2411 GstTagList *tags = NULL;
2412 GstBuffer *extradata = NULL;
2415 guint16 size_left = 0;
2416 gchar *codec_name = NULL;
2419 size_left = audio->size;
2421 /* Create the audio pad */
2422 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2424 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2427 /* Swallow up any left over data and set up the
2428 * standard properties from the header info */
2430 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2431 "codec specific data", size_left);
2433 g_assert (size_left <= *p_size);
2434 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2437 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2438 * additional two bytes indicating extradata. */
2439 /* FIXME: Handle the channel reorder map here */
2440 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2441 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2444 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2445 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2448 /* Informing about that audio format we just added */
2450 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2451 g_free (codec_name);
2455 gst_buffer_unref (extradata);
2457 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2458 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2459 audio->codec_tag, tags);
2461 ++demux->num_audio_streams;
2463 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2467 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2468 asf_stream_video_format * video, guint16 id,
2469 guint8 ** p_data, guint64 * p_size)
2471 GstTagList *tags = NULL;
2472 GstBuffer *extradata = NULL;
2477 gchar *codec_name = NULL;
2478 gint size_left = video->size - 40;
2480 /* Create the video pad */
2481 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2482 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2485 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2487 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2488 g_assert (size_left <= *p_size);
2489 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2492 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2494 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2495 caps = gst_riff_create_video_caps (video->tag, NULL,
2496 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2499 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2500 G_TYPE_UINT, video->tag, NULL);
2505 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2506 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2507 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2508 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2513 /* retry with the global metadata */
2514 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2515 demux->global_metadata);
2516 s = demux->global_metadata;
2517 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2518 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2519 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2520 if (ax > 0 && ay > 0)
2521 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2525 s = gst_caps_get_structure (caps, 0);
2526 gst_structure_remove_field (s, "framerate");
2529 /* add fourcc format to caps, some proprietary decoders seem to need it */
2530 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2531 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2535 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2536 g_free (codec_name);
2540 gst_buffer_unref (extradata);
2542 GST_INFO ("Adding video stream #%u, id %u, codec %"
2543 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2544 GST_FOURCC_ARGS (video->tag), video->tag);
2546 ++demux->num_video_streams;
2548 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2552 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2554 if (!stream->active) {
2558 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2559 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2560 gst_pad_set_active (stream->pad, TRUE);
2563 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2564 "%03u", stream->id);
2567 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2569 if (gst_event_parse_group_id (event, &demux->group_id))
2570 demux->have_group_id = TRUE;
2572 demux->have_group_id = FALSE;
2573 gst_event_unref (event);
2574 } else if (!demux->have_group_id) {
2575 demux->have_group_id = TRUE;
2576 demux->group_id = gst_util_group_id_next ();
2579 event = gst_event_new_stream_start (stream_id);
2580 if (demux->have_group_id)
2581 gst_event_set_group_id (event, demux->group_id);
2583 gst_pad_push_event (stream->pad, event);
2585 gst_pad_set_caps (stream->pad, stream->caps);
2587 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2588 stream->active = TRUE;
2593 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2596 AsfCorrectionType correction_type;
2597 AsfStreamType stream_type;
2598 GstClockTime time_offset;
2599 gboolean is_encrypted G_GNUC_UNUSED;
2603 guint stream_specific_size;
2604 guint type_specific_size G_GNUC_UNUSED;
2605 guint unknown G_GNUC_UNUSED;
2606 gboolean inspect_payload = FALSE;
2609 /* Get the rest of the header's header */
2610 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2611 goto not_enough_data;
2613 gst_asf_demux_get_guid (&guid, &data, &size);
2614 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2616 gst_asf_demux_get_guid (&guid, &data, &size);
2617 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2619 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2621 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2622 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2624 flags = gst_asf_demux_get_uint16 (&data, &size);
2625 stream_id = flags & 0x7f;
2626 is_encrypted = ! !((flags & 0x8000) << 15);
2627 unknown = gst_asf_demux_get_uint32 (&data, &size);
2629 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2630 stream_id, GST_TIME_ARGS (time_offset));
2632 /* dvr-ms has audio stream declared in stream specific data */
2633 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2634 AsfExtStreamType ext_stream_type;
2635 gst_asf_demux_get_guid (&guid, &data, &size);
2636 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2638 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2639 inspect_payload = TRUE;
2641 gst_asf_demux_get_guid (&guid, &data, &size);
2642 gst_asf_demux_get_uint32 (&data, &size);
2643 gst_asf_demux_get_uint32 (&data, &size);
2644 gst_asf_demux_get_uint32 (&data, &size);
2645 gst_asf_demux_get_guid (&guid, &data, &size);
2646 gst_asf_demux_get_uint32 (&data, &size);
2647 stream_type = ASF_STREAM_AUDIO;
2651 switch (stream_type) {
2652 case ASF_STREAM_AUDIO:{
2653 asf_stream_audio audio_object;
2655 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2656 goto not_enough_data;
2658 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2661 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2664 switch (correction_type) {
2665 case ASF_CORRECTION_ON:{
2666 guint span, packet_size, chunk_size, data_size, silence_data;
2668 GST_INFO ("Using error correction");
2670 if (size < (1 + 2 + 2 + 2 + 1))
2671 goto not_enough_data;
2673 span = gst_asf_demux_get_uint8 (&data, &size);
2674 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2675 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2676 data_size = gst_asf_demux_get_uint16 (&data, &size);
2677 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2679 /* FIXME: shouldn't this be per-stream? */
2682 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2683 packet_size, chunk_size, data_size, span, silence_data);
2685 if (demux->span > 1) {
2686 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2687 /* Disable descrambling */
2690 /* FIXME: this else branch was added for
2691 * weird_al_yankovic - the saga begins.asf */
2692 demux->ds_packet_size = packet_size;
2693 demux->ds_chunk_size = chunk_size;
2696 /* Descambling is enabled */
2697 demux->ds_packet_size = packet_size;
2698 demux->ds_chunk_size = chunk_size;
2701 /* Now skip the rest of the silence data */
2703 gst_bytestream_flush (demux->bs, data_size - 1);
2705 /* FIXME: CHECKME. And why -1? */
2706 if (data_size > 1) {
2707 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2708 goto not_enough_data;
2714 case ASF_CORRECTION_OFF:{
2715 GST_INFO ("Error correction off");
2716 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2717 goto not_enough_data;
2721 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2722 ("Audio stream using unknown error correction"));
2729 case ASF_STREAM_VIDEO:{
2730 asf_stream_video_format video_format_object;
2731 asf_stream_video video_object;
2734 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2735 goto not_enough_data;
2737 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2739 GST_INFO ("object is a video stream with %u bytes of "
2740 "additional data", vsize);
2742 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2744 goto not_enough_data;
2747 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2754 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2756 demux->other_streams =
2757 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
2761 stream = gst_asf_demux_get_stream (demux, stream_id);
2763 stream->inspect_payload = inspect_payload;
2768 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2769 /* we'll error out later if we found no streams */
2774 static const gchar *
2775 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2779 const gchar *asf_name;
2780 const gchar *gst_name;
2783 "WM/Genre", GST_TAG_GENRE}, {
2784 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2785 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2786 "WM/Picture", GST_TAG_IMAGE}, {
2787 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2788 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2789 "WM/Year", GST_TAG_DATE_TIME}
2790 /* { "WM/Composer", GST_TAG_COMPOSER } */
2795 if (name_utf8 == NULL) {
2796 GST_WARNING ("Failed to convert name to UTF8, skipping");
2800 out = strlen (name_utf8);
2802 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2803 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2804 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2805 return tags[i].gst_name;
2812 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2814 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2818 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2820 if (taglist == NULL)
2823 if (gst_tag_list_is_empty (taglist)) {
2824 gst_tag_list_unref (taglist);
2828 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2829 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
2831 gst_tag_list_unref (demux->taglist);
2832 gst_tag_list_unref (taglist);
2834 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2837 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2838 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2839 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2842 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2846 const guint8 *img_data = NULL;
2847 guint32 img_data_len = 0;
2848 guint8 pic_type = 0;
2850 gst_byte_reader_init (&r, tag_data, tag_data_len);
2852 /* skip mime type string (we don't trust it and do our own typefinding),
2853 * and also skip the description string, since we don't use it */
2854 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2855 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2856 !gst_byte_reader_skip_string_utf16 (&r) ||
2857 !gst_byte_reader_skip_string_utf16 (&r) ||
2858 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2859 goto not_enough_data;
2863 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2864 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2870 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2871 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2876 /* Extended Content Description Object */
2877 static GstFlowReturn
2878 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2881 /* Other known (and unused) 'text/unicode' metadata available :
2884 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2885 * WMFSDKVersion = 9.00.00.2980
2886 * WMFSDKNeeded = 0.0.0.0000
2887 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2888 * WM/Publisher = 4AD
2890 * WM/ProviderRating = 8
2891 * WM/ProviderStyle = Rock (similar to WM/Genre)
2892 * WM/GenreID (similar to WM/Genre)
2893 * WM/TrackNumber (same as WM/Track but as a string)
2895 * Other known (and unused) 'non-text' metadata available :
2901 * We might want to read WM/TrackNumber and use atoi() if we don't have
2905 GstTagList *taglist;
2906 guint16 blockcount, i;
2908 GST_INFO_OBJECT (demux, "object is an extended content description");
2910 taglist = gst_tag_list_new_empty ();
2912 /* Content Descriptor Count */
2914 goto not_enough_data;
2916 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2918 for (i = 1; i <= blockcount; ++i) {
2919 const gchar *gst_tag_name;
2923 GValue tag_value = { 0, };
2926 gchar *name_utf8 = NULL;
2930 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2931 goto not_enough_data;
2935 goto not_enough_data;
2937 /* Descriptor Value Data Type */
2938 datatype = gst_asf_demux_get_uint16 (&data, &size);
2940 /* Descriptor Value (not really a string, but same thing reading-wise) */
2941 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2943 goto not_enough_data;
2947 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2949 if (name_utf8 != NULL) {
2950 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2952 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2953 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2956 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2959 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2962 /* get rid of tags with empty value */
2963 if (value_utf8 != NULL && *value_utf8 != '\0') {
2964 GST_DEBUG ("string value %s", value_utf8);
2966 value_utf8[out] = '\0';
2968 if (gst_tag_name != NULL) {
2969 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
2970 guint year = atoi (value_utf8);
2973 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
2974 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
2976 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2977 guint id3v1_genre_id;
2978 const gchar *genre_str;
2980 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2981 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2982 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2983 g_free (value_utf8);
2984 value_utf8 = g_strdup (genre_str);
2989 /* convert tag from string to other type if required */
2990 tag_type = gst_tag_get_type (gst_tag_name);
2991 g_value_init (&tag_value, tag_type);
2992 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2993 GValue from_val = { 0, };
2995 g_value_init (&from_val, G_TYPE_STRING);
2996 g_value_set_string (&from_val, value_utf8);
2997 if (!g_value_transform (&from_val, &tag_value)) {
2998 GST_WARNING_OBJECT (demux,
2999 "Could not transform string tag to " "%s tag type %s",
3000 gst_tag_name, g_type_name (tag_type));
3001 g_value_unset (&tag_value);
3003 g_value_unset (&from_val);
3008 GST_DEBUG ("Setting metadata");
3009 g_value_init (&tag_value, G_TYPE_STRING);
3010 g_value_set_string (&tag_value, value_utf8);
3012 } else if (value_utf8 == NULL) {
3013 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3015 GST_DEBUG ("Skipping empty string value for %s",
3016 GST_STR_NULL (gst_tag_name));
3018 g_free (value_utf8);
3021 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3023 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3024 GST_FIXME ("Unhandled byte array tag %s",
3025 GST_STR_NULL (gst_tag_name));
3028 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3034 case ASF_DEMUX_DATA_TYPE_DWORD:{
3035 guint uint_val = GST_READ_UINT32_LE (value);
3037 /* this is the track number */
3038 g_value_init (&tag_value, G_TYPE_UINT);
3040 /* WM/Track counts from 0 */
3041 if (!strcmp (name_utf8, "WM/Track"))
3044 g_value_set_uint (&tag_value, uint_val);
3048 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3053 if (G_IS_VALUE (&tag_value)) {
3055 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3057 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3058 * is supposed to have a 0 base but is often wrongly written to start
3059 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3060 * replace the value added earlier from WM/Track or put it first in
3061 * the list, so that it will get picked up by _get_uint() */
3062 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3063 merge_mode = GST_TAG_MERGE_REPLACE;
3065 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3068 GST_DEBUG ("Setting global metadata %s", name_utf8);
3069 gst_structure_set_value (demux->global_metadata, name_utf8,
3073 g_value_unset (&tag_value);
3082 gst_asf_demux_add_global_tags (demux, taglist);
3089 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3090 gst_tag_list_unref (taglist);
3091 return GST_FLOW_OK; /* not really fatal */
3095 static GstStructure *
3096 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3101 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3103 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3106 s = gst_caps_get_structure (demux->metadata, i);
3107 if (gst_structure_has_name (s, sname))
3111 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3113 /* try lookup again; demux->metadata took ownership of the structure, so we
3114 * can't really make any assumptions about what happened to it, so we can't
3115 * just return it directly after appending it */
3116 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3119 static GstFlowReturn
3120 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3123 guint16 blockcount, i;
3125 GST_INFO_OBJECT (demux, "object is a metadata object");
3127 /* Content Descriptor Count */
3129 goto not_enough_data;
3131 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3133 for (i = 0; i < blockcount; ++i) {
3135 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3136 guint32 data_len, ival;
3139 if (size < (2 + 2 + 2 + 2 + 4))
3140 goto not_enough_data;
3142 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3143 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3144 name_len = gst_asf_demux_get_uint16 (&data, &size);
3145 data_type = gst_asf_demux_get_uint16 (&data, &size);
3146 data_len = gst_asf_demux_get_uint32 (&data, &size);
3148 if (size < name_len + data_len)
3149 goto not_enough_data;
3151 /* convert name to UTF-8 */
3152 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3154 gst_asf_demux_skip_bytes (name_len, &data, &size);
3156 if (name_utf8 == NULL) {
3157 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3158 gst_asf_demux_skip_bytes (data_len, &data, &size);
3162 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3163 gst_asf_demux_skip_bytes (data_len, &data, &size);
3171 goto not_enough_data;
3174 ival = gst_asf_demux_get_uint32 (&data, &size);
3176 /* skip anything else there may be, just in case */
3177 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3179 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3180 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3184 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3190 GST_WARNING ("Unexpected end of data parsing metadata object");
3191 return GST_FLOW_OK; /* not really fatal */
3195 static GstFlowReturn
3196 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3198 GstFlowReturn ret = GST_FLOW_OK;
3199 guint32 i, num_objects;
3200 guint8 unknown G_GNUC_UNUSED;
3202 /* Get the rest of the header's header */
3203 if (size < (4 + 1 + 1))
3204 goto not_enough_data;
3206 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3207 unknown = gst_asf_demux_get_uint8 (&data, &size);
3208 unknown = gst_asf_demux_get_uint8 (&data, &size);
3210 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3212 /* Loop through the header's objects, processing those */
3213 for (i = 0; i < num_objects; ++i) {
3214 GST_INFO_OBJECT (demux, "reading header part %u", i);
3215 ret = gst_asf_demux_process_object (demux, &data, &size);
3216 if (ret != GST_FLOW_OK) {
3217 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3226 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3227 ("short read parsing HEADER object"));
3228 return GST_FLOW_ERROR;
3232 static GstFlowReturn
3233 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3235 guint64 creation_time G_GNUC_UNUSED;
3236 guint64 file_size G_GNUC_UNUSED;
3237 guint64 send_time G_GNUC_UNUSED;
3238 guint64 packets_count, play_time, preroll;
3239 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3241 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3242 goto not_enough_data;
3244 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3245 file_size = gst_asf_demux_get_uint64 (&data, &size);
3246 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3247 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3248 play_time = gst_asf_demux_get_uint64 (&data, &size);
3249 send_time = gst_asf_demux_get_uint64 (&data, &size);
3250 preroll = gst_asf_demux_get_uint64 (&data, &size);
3251 flags = gst_asf_demux_get_uint32 (&data, &size);
3252 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3253 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3254 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3256 demux->broadcast = ! !(flags & 0x01);
3257 demux->seekable = ! !(flags & 0x02);
3259 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3260 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3261 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3263 if (demux->broadcast) {
3264 /* these fields are invalid if the broadcast flag is set */
3269 if (min_pktsize != max_pktsize)
3270 goto non_fixed_packet_size;
3272 demux->packet_size = max_pktsize;
3274 /* FIXME: do we need send_time as well? what is it? */
3275 if ((play_time * 100) >= (preroll * GST_MSECOND))
3276 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3278 demux->play_time = 0;
3280 demux->preroll = preroll * GST_MSECOND;
3282 /* initial latency */
3283 demux->latency = demux->preroll;
3285 if (demux->play_time == 0)
3286 demux->seekable = FALSE;
3288 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3289 GST_TIME_ARGS (demux->play_time));
3290 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3291 GST_TIME_ARGS (demux->preroll));
3293 if (demux->play_time > 0) {
3294 demux->segment.duration = demux->play_time;
3297 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3299 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3304 non_fixed_packet_size:
3306 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3307 ("packet size must be fixed"));
3308 return GST_FLOW_ERROR;
3312 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3313 ("short read parsing FILE object"));
3314 return GST_FLOW_ERROR;
3318 /* Content Description Object */
3319 static GstFlowReturn
3320 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3324 const gchar *gst_tag;
3329 GST_TAG_TITLE, 0, NULL}, {
3330 GST_TAG_ARTIST, 0, NULL}, {
3331 GST_TAG_COPYRIGHT, 0, NULL}, {
3332 GST_TAG_DESCRIPTION, 0, NULL}, {
3333 GST_TAG_COMMENT, 0, NULL}
3335 GstTagList *taglist;
3336 GValue value = { 0 };
3340 GST_INFO_OBJECT (demux, "object is a comment");
3342 if (size < (2 + 2 + 2 + 2 + 2))
3343 goto not_enough_data;
3345 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3346 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3347 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3348 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3349 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3351 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3352 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3353 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3355 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3356 if (size < tags[i].val_length)
3357 goto not_enough_data;
3359 /* might be just '/0', '/0'... */
3360 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3361 /* convert to UTF-8 */
3362 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3363 "UTF-8", "UTF-16LE", &in, &out, NULL);
3365 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3368 /* parse metadata into taglist */
3369 taglist = gst_tag_list_new_empty ();
3370 g_value_init (&value, G_TYPE_STRING);
3371 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3372 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3373 g_value_set_string (&value, tags[i].val_utf8);
3374 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3375 tags[i].gst_tag, &value, NULL);
3378 g_value_unset (&value);
3380 gst_asf_demux_add_global_tags (demux, taglist);
3382 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3383 g_free (tags[i].val_utf8);
3389 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3390 "comment tag section %d, skipping comment object", i);
3391 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3392 g_free (tags[i].val_utf8);
3393 return GST_FLOW_OK; /* not really fatal */
3397 static GstFlowReturn
3398 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3401 guint16 num_streams, i;
3405 goto not_enough_data;
3407 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3409 GST_INFO ("object is a bitrate properties object with %u streams",
3412 if (size < (num_streams * (2 + 4)))
3413 goto not_enough_data;
3415 for (i = 0; i < num_streams; ++i) {
3419 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3420 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3422 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3423 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3424 stream = gst_asf_demux_get_stream (demux, stream_id);
3426 if (stream->pending_tags == NULL) {
3427 stream->pending_tags =
3428 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3431 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3434 GST_WARNING ("stream id %u is too large", stream_id);
3442 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3443 return GST_FLOW_OK; /* not really fatal */
3447 static GstFlowReturn
3448 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3451 GstFlowReturn ret = GST_FLOW_OK;
3454 /* Get the rest of the header's header */
3455 if (size < (16 + 2 + 4))
3456 goto not_enough_data;
3458 /* skip GUID and two other bytes */
3459 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3460 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3462 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3464 /* FIXME: does data_size include the rest of the header that we have read? */
3465 if (hdr_size > size)
3466 goto not_enough_data;
3468 while (hdr_size > 0) {
3469 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3470 if (ret != GST_FLOW_OK)
3478 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3479 ("short read parsing extended header object"));
3480 return GST_FLOW_ERROR;
3484 static GstFlowReturn
3485 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3491 goto not_enough_data;
3493 if (demux->languages) {
3494 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3495 g_strfreev (demux->languages);
3496 demux->languages = NULL;
3497 demux->num_languages = 0;
3500 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3501 GST_LOG ("%u languages:", demux->num_languages);
3503 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3504 for (i = 0; i < demux->num_languages; ++i) {
3505 guint8 len, *lang_data = NULL;
3508 goto not_enough_data;
3509 len = gst_asf_demux_get_uint8 (&data, &size);
3510 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3513 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3516 /* truncate "en-us" etc. to just "en" */
3517 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3520 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3521 demux->languages[i] = utf8;
3524 goto not_enough_data;
3532 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3533 g_free (demux->languages);
3534 demux->languages = NULL;
3535 return GST_FLOW_OK; /* not fatal */
3539 static GstFlowReturn
3540 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3543 GstClockTime interval;
3546 if (size < (16 + 8 + 4 + 4))
3547 goto not_enough_data;
3550 gst_asf_demux_skip_bytes (16, &data, &size);
3551 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3552 gst_asf_demux_skip_bytes (4, &data, &size);
3553 count = gst_asf_demux_get_uint32 (&data, &size);
3555 demux->sidx_interval = interval;
3556 demux->sidx_num_entries = count;
3557 g_free (demux->sidx_entries);
3558 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3560 for (i = 0; i < count; ++i) {
3561 if (G_UNLIKELY (size <= 6))
3563 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3564 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3565 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3566 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3567 demux->sidx_entries[i].count);
3570 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3577 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3578 return GST_FLOW_OK; /* not fatal */
3582 static GstFlowReturn
3583 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3584 guint8 * data, guint64 size)
3590 if (size < 16 + 2 + (2 * 2))
3591 goto not_enough_data;
3593 gst_asf_demux_get_guid (&guid, &data, &size);
3594 num = gst_asf_demux_get_uint16 (&data, &size);
3597 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3601 if (size < (num * sizeof (guint16)))
3602 goto not_enough_data;
3604 /* read mutually exclusive stream numbers */
3605 mes = g_new (guint8, num + 1);
3606 for (i = 0; i < num; ++i) {
3607 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3608 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3611 /* add terminator so we can easily get the count or know when to stop */
3612 mes[i] = (guint8) - 1;
3614 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3621 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3622 return GST_FLOW_OK; /* not absolutely fatal */
3627 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3629 return g_slist_find (demux->other_streams,
3630 GINT_TO_POINTER (stream_num)) == NULL;
3633 static GstFlowReturn
3634 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3637 AsfStreamExtProps esp;
3638 AsfStream *stream = NULL;
3639 AsfObject stream_obj;
3640 guint16 stream_name_count;
3641 guint16 num_payload_ext;
3643 guint8 *stream_obj_data = NULL;
3646 guint i, stream_num;
3649 obj_size = (guint) size;
3652 goto not_enough_data;
3655 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3656 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3657 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3658 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3659 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3660 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3661 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3662 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3663 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3664 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3665 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3666 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3667 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3668 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3669 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3671 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3672 GST_TIME_ARGS (esp.start_time));
3673 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3674 GST_TIME_ARGS (esp.end_time));
3675 GST_INFO ("flags = %08x", esp.flags);
3676 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3677 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3678 GST_INFO ("stream number = %u", stream_num);
3679 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3680 (esp.lang_idx < demux->num_languages) ?
3681 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3682 GST_INFO ("stream name count = %u", stream_name_count);
3684 /* read stream names */
3685 for (i = 0; i < stream_name_count; ++i) {
3686 guint16 stream_lang_idx G_GNUC_UNUSED;
3687 gchar *stream_name = NULL;
3690 goto not_enough_data;
3691 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3692 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3693 goto not_enough_data;
3694 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3695 g_free (stream_name); /* TODO: store names in struct */
3698 /* read payload extension systems stuff */
3699 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3701 if (num_payload_ext > 0)
3702 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3704 esp.payload_extensions = NULL;
3706 for (i = 0; i < num_payload_ext; ++i) {
3707 AsfPayloadExtension ext;
3709 guint32 sys_info_len;
3711 if (size < 16 + 2 + 4)
3712 goto not_enough_data;
3714 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3715 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3716 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3718 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3719 GST_LOG ("payload systems info len = %u", sys_info_len);
3720 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3721 goto not_enough_data;
3723 esp.payload_extensions[i] = ext;
3726 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3728 /* there might be an optional STREAM_INFO object here now; if not, we
3729 * should have parsed the corresponding stream info object already (since
3730 * we are parsing the extended stream properties objects delayed) */
3732 stream = gst_asf_demux_get_stream (demux, stream_num);
3736 /* get size of the stream object */
3737 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3738 goto not_enough_data;
3740 if (stream_obj.id != ASF_OBJ_STREAM)
3741 goto expected_stream_object;
3743 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3744 stream_obj.size > (10 * 1024 * 1024))
3745 goto not_enough_data;
3747 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3749 /* process this stream object later after all the other 'normal' ones
3750 * have been processed (since the others are more important/non-hidden) */
3751 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3752 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3753 goto not_enough_data;
3755 /* parse stream object */
3756 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3757 g_free (stream_obj_data);
3762 stream->ext_props = esp;
3764 /* try to set the framerate */
3765 if (stream->is_video && stream->caps) {
3766 GValue framerate = { 0 };
3770 g_value_init (&framerate, GST_TYPE_FRACTION);
3772 num = GST_SECOND / 100;
3773 denom = esp.avg_time_per_frame;
3775 /* avoid division by 0, assume 25/1 framerate */
3776 denom = GST_SECOND / 2500;
3779 gst_value_set_fraction (&framerate, num, denom);
3781 stream->caps = gst_caps_make_writable (stream->caps);
3782 s = gst_caps_get_structure (stream->caps, 0);
3783 gst_structure_set_value (s, "framerate", &framerate);
3784 g_value_unset (&framerate);
3785 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3786 num, denom, ((gdouble) num) / denom);
3789 /* add language info now if we have it */
3790 if (stream->ext_props.lang_idx < demux->num_languages) {
3791 if (stream->pending_tags == NULL)
3792 stream->pending_tags = gst_tag_list_new_empty ();
3793 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3794 demux->languages[stream->ext_props.lang_idx]);
3795 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3796 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3799 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
3800 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3808 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3809 return GST_FLOW_OK; /* not absolutely fatal */
3811 expected_stream_object:
3813 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3814 "object: expected embedded stream object, but got %s object instead!",
3815 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3816 return GST_FLOW_OK; /* not absolutely fatal */
3820 static const gchar *
3821 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3825 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3826 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3827 nick += strlen ("ASF_OBJ_");
3829 if (demux->objpath == NULL) {
3830 demux->objpath = g_strdup (nick);
3834 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3835 g_free (demux->objpath);
3836 demux->objpath = newpath;
3839 return (const gchar *) demux->objpath;
3843 gst_asf_demux_pop_obj (GstASFDemux * demux)
3847 if ((s = g_strrstr (demux->objpath, "/"))) {
3850 g_free (demux->objpath);
3851 demux->objpath = NULL;
3856 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3861 /* Parse the queued extended stream property objects and add the info
3862 * to the existing streams or add the new embedded streams, but without
3863 * activating them yet */
3864 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3865 g_slist_length (demux->ext_stream_props));
3867 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3868 GstBuffer *buf = GST_BUFFER (l->data);
3871 gst_buffer_map (buf, &map, GST_MAP_READ);
3873 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3874 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
3875 gst_buffer_unmap (buf, &map);
3876 gst_buffer_unref (buf);
3878 g_slist_free (demux->ext_stream_props);
3879 demux->ext_stream_props = NULL;
3884 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3888 for (i = 0; i < demux->num_streams; ++i) {
3893 stream = &demux->stream[i];
3895 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3897 if (stream->active) {
3898 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3903 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3906 /* check for each mutual exclusion whether it affects this stream */
3907 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3908 if (*mes == stream->id) {
3909 /* if yes, check if we've already added streams that are mutually
3910 * exclusive with the stream we're about to add */
3911 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3912 for (j = 0; j < demux->num_streams; ++j) {
3913 /* if the broadcast flag is set, assume the hidden streams aren't
3914 * actually streamed and hide them (or playbin won't work right),
3915 * otherwise assume their data is available */
3916 if (demux->stream[j].id == *mes && demux->broadcast) {
3918 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3919 "mutually exclusive with already existing stream ID %d, "
3920 "hiding stream", stream->id, demux->stream[j].id);
3932 /* FIXME: we should do stream activation based on preroll data in
3933 * streaming mode too */
3934 if (demux->streaming && !is_hidden)
3935 gst_asf_demux_activate_stream (demux, stream);
3940 static GstFlowReturn
3941 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3944 GstFlowReturn ret = GST_FLOW_OK;
3946 guint64 obj_data_size;
3948 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3949 return ASF_FLOW_NEED_MORE_DATA;
3951 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3952 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3954 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3956 if (*p_size < obj_data_size)
3957 return ASF_FLOW_NEED_MORE_DATA;
3959 gst_asf_demux_push_obj (demux, obj.id);
3961 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3964 case ASF_OBJ_STREAM:
3965 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3969 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3971 case ASF_OBJ_HEADER:
3972 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3974 case ASF_OBJ_COMMENT:
3975 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3978 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3980 case ASF_OBJ_BITRATE_PROPS:
3982 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3985 case ASF_OBJ_EXT_CONTENT_DESC:
3987 gst_asf_demux_process_ext_content_desc (demux, *p_data,
3990 case ASF_OBJ_METADATA_OBJECT:
3991 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3993 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3996 /* process these later, we might not have parsed the corresponding
3997 * stream object yet */
3998 GST_LOG ("%s: queued for later parsing", demux->objpath);
3999 buf = gst_buffer_new_and_alloc (obj_data_size);
4000 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4001 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4005 case ASF_OBJ_LANGUAGE_LIST:
4006 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4008 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4009 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4012 case ASF_OBJ_SIMPLE_INDEX:
4013 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4015 case ASF_OBJ_CONTENT_ENCRYPTION:
4016 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4017 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4018 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4019 goto error_encrypted;
4020 case ASF_OBJ_CONCEAL_NONE:
4022 case ASF_OBJ_UNDEFINED:
4023 case ASF_OBJ_CODEC_COMMENT:
4025 case ASF_OBJ_PADDING:
4026 case ASF_OBJ_BITRATE_MUTEX:
4027 case ASF_OBJ_COMPATIBILITY:
4028 case ASF_OBJ_INDEX_PLACEHOLDER:
4029 case ASF_OBJ_INDEX_PARAMETERS:
4030 case ASF_OBJ_STREAM_PRIORITIZATION:
4031 case ASF_OBJ_SCRIPT_COMMAND:
4033 /* Unknown/unhandled object, skip it and hope for the best */
4034 GST_INFO ("%s: skipping object", demux->objpath);
4039 /* this can't fail, we checked the number of bytes available before */
4040 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4042 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4044 gst_asf_demux_pop_obj (demux);
4051 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4052 return GST_FLOW_ERROR;
4057 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4058 GstBuffer ** p_buffer)
4060 GstBuffer *descrambled_buffer;
4061 GstBuffer *scrambled_buffer;
4062 GstBuffer *sub_buffer;
4069 /* descrambled_buffer is initialised in the first iteration */
4070 descrambled_buffer = NULL;
4071 scrambled_buffer = *p_buffer;
4073 if (gst_buffer_get_size (scrambled_buffer) <
4074 demux->ds_packet_size * demux->span)
4077 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4078 offset += demux->ds_chunk_size) {
4079 off = offset / demux->ds_chunk_size;
4080 row = off / demux->span;
4081 col = off % demux->span;
4082 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
4083 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4084 col, off, demux->ds_chunk_size);
4085 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4086 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4087 demux->span, demux->ds_packet_size);
4088 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4089 gst_buffer_get_size (scrambled_buffer));
4091 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_NONE,
4092 idx * demux->ds_chunk_size, demux->ds_chunk_size);
4094 descrambled_buffer = sub_buffer;
4096 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4100 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4101 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4102 GST_BUFFER_DURATION (descrambled_buffer) =
4103 GST_BUFFER_DURATION (scrambled_buffer);
4104 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4105 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4106 GST_BUFFER_OFFSET_END (scrambled_buffer);
4108 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4110 gst_buffer_unref (scrambled_buffer);
4111 *p_buffer = descrambled_buffer;
4115 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4117 GstASFDemux *demux = GST_ASF_DEMUX (element);
4120 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4122 for (i = 0; i < demux->num_streams; ++i) {
4123 gst_event_ref (event);
4124 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4125 GST_OBJECT_CAST (element), event)) {
4126 gst_event_unref (event);
4131 gst_event_unref (event);
4135 /* takes ownership of the passed event */
4137 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4139 gboolean ret = TRUE;
4142 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4143 GST_EVENT_TYPE_NAME (event));
4145 for (i = 0; i < demux->num_streams; ++i) {
4146 gst_event_ref (event);
4147 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4149 gst_event_unref (event);
4154 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4158 gboolean res = FALSE;
4160 demux = GST_ASF_DEMUX (parent);
4162 GST_DEBUG ("handling %s query",
4163 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4165 switch (GST_QUERY_TYPE (query)) {
4166 case GST_QUERY_DURATION:
4170 gst_query_parse_duration (query, &format, NULL);
4172 if (format != GST_FORMAT_TIME) {
4173 GST_LOG ("only support duration queries in TIME format");
4177 GST_OBJECT_LOCK (demux);
4179 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4180 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4181 GST_TIME_ARGS (demux->segment.duration));
4183 gst_query_set_duration (query, GST_FORMAT_TIME,
4184 demux->segment.duration);
4188 GST_LOG ("duration not known yet");
4191 GST_OBJECT_UNLOCK (demux);
4195 case GST_QUERY_POSITION:{
4198 gst_query_parse_position (query, &format, NULL);
4200 if (format != GST_FORMAT_TIME) {
4201 GST_LOG ("only support position queries in TIME format");
4205 GST_OBJECT_LOCK (demux);
4207 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4208 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4209 GST_TIME_ARGS (demux->segment.position));
4211 gst_query_set_position (query, GST_FORMAT_TIME,
4212 demux->segment.position);
4216 GST_LOG ("position not known yet");
4219 GST_OBJECT_UNLOCK (demux);
4223 case GST_QUERY_SEEKING:{
4226 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4227 if (format == GST_FORMAT_TIME) {
4230 GST_OBJECT_LOCK (demux);
4231 duration = demux->segment.duration;
4232 GST_OBJECT_UNLOCK (demux);
4234 if (!demux->streaming || !demux->seekable) {
4235 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4242 /* try downstream first in TIME */
4243 res = gst_pad_query_default (pad, parent, query);
4245 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4246 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4247 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4248 /* if no luck, maybe in BYTES */
4249 if (!seekable || fmt != GST_FORMAT_TIME) {
4252 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4253 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4254 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4255 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4256 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4257 if (fmt != GST_FORMAT_BYTES)
4260 gst_query_unref (q);
4261 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4267 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4271 case GST_QUERY_LATENCY:
4274 GstClockTime min, max;
4276 /* preroll delay does not matter in non-live pipeline,
4277 * but we might end up in a live (rtsp) one ... */
4280 res = gst_pad_query_default (pad, parent, query);
4284 gst_query_parse_latency (query, &live, &min, &max);
4286 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4287 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4288 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4290 GST_OBJECT_LOCK (demux);
4292 min += demux->latency;
4294 max += demux->latency;
4295 GST_OBJECT_UNLOCK (demux);
4297 gst_query_set_latency (query, live, min, max);
4300 case GST_QUERY_SEGMENT:
4305 format = demux->segment.format;
4308 gst_segment_to_stream_time (&demux->segment, format,
4309 demux->segment.start);
4310 if ((stop = demux->segment.stop) == -1)
4311 stop = demux->segment.duration;
4313 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4315 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4320 res = gst_pad_query_default (pad, parent, query);
4327 static GstStateChangeReturn
4328 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4330 GstASFDemux *demux = GST_ASF_DEMUX (element);
4331 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4333 switch (transition) {
4334 case GST_STATE_CHANGE_NULL_TO_READY:{
4335 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4336 demux->need_newsegment = TRUE;
4337 demux->segment_running = FALSE;
4338 demux->accurate = FALSE;
4339 demux->adapter = gst_adapter_new ();
4340 demux->metadata = gst_caps_new_empty ();
4341 demux->global_metadata = gst_structure_new_empty ("metadata");
4342 demux->data_size = 0;
4343 demux->data_offset = 0;
4344 demux->index_offset = 0;
4345 demux->base_offset = 0;
4352 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4353 if (ret == GST_STATE_CHANGE_FAILURE)
4356 switch (transition) {
4357 case GST_STATE_CHANGE_PAUSED_TO_READY:
4358 case GST_STATE_CHANGE_READY_TO_NULL:
4359 gst_asf_demux_reset (demux, FALSE);