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 if (cur_type != GST_SEEK_TYPE_SET)
723 seek_time = segment.start;
727 /* FIXME: should check the KEY_UNIT flag; need to adjust position to
728 * real start of data and segment_start to indexed time for key unit seek*/
729 if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
730 &idx_time, &speed_count, next, &eos))) {
734 demux->packet = demux->num_packets;
738 /* First try to query our source to see if it can convert for us. This is
739 the case when our source is an mms stream, notice that in this case
740 gstmms will do a time based seek to get the byte offset, this is not a
741 problem as the seek to this offset needs to happen anway. */
742 if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
743 GST_FORMAT_BYTES, &offset)) {
744 packet = (offset - demux->data_offset) / demux->packet_size;
745 GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
746 " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
747 G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
748 GST_TIME_ARGS (seek_time), offset, demux->data_offset,
749 demux->packet_size, packet);
751 /* FIXME: For streams containing video, seek to an earlier position in
752 * the hope of hitting a keyframe and let the sinks throw away the stuff
753 * before the segment start. For audio-only this is unnecessary as every
755 if (flush && (demux->accurate || (keyunit_sync && !next))
756 && demux->num_video_streams > 0) {
757 seek_time -= 5 * GST_SECOND;
762 packet = (guint) gst_util_uint64_scale (demux->num_packets,
763 seek_time, demux->play_time);
765 if (packet > demux->num_packets)
766 packet = demux->num_packets;
769 if (G_LIKELY (keyunit_sync)) {
770 GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
771 GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
772 GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
773 segment.start = idx_time;
774 segment.position = idx_time;
775 segment.time = idx_time;
779 GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
781 GST_OBJECT_LOCK (demux);
782 demux->segment = segment;
783 demux->packet = packet;
784 demux->need_newsegment = TRUE;
785 demux->segment_seqnum = seqnum;
786 demux->speed_packets = speed_count;
787 gst_asf_demux_reset_stream_state_after_discont (demux);
788 GST_OBJECT_UNLOCK (demux);
791 /* restart our task since it might have been stopped when we did the flush */
792 gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
795 /* streaming can continue now */
796 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
802 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
808 demux = GST_ASF_DEMUX (parent);
810 switch (GST_EVENT_TYPE (event)) {
812 GST_LOG_OBJECT (pad, "seek event");
813 ret = gst_asf_demux_handle_seek_event (demux, event);
814 gst_event_unref (event);
817 case GST_EVENT_NAVIGATION:
818 /* just drop these two silently */
819 gst_event_unref (event);
823 GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
824 ret = gst_pad_event_default (pad, parent, event);
831 static inline guint32
832 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
836 ret = gst_asf_identify_guid (guids, guid);
838 GST_LOG ("%s 0x%08x-0x%08x-0x%08x-0x%08x",
839 gst_asf_get_guid_nick (guids, ret),
840 guid->v1, guid->v2, guid->v3, guid->v4);
852 /* expect is true when the user is expeting an object,
853 * when false, it will give no warnings if the object
857 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
858 guint data_len, AsfObject * object, gboolean expect)
862 if (data_len < ASF_OBJECT_HEADER_SIZE)
865 guid.v1 = GST_READ_UINT32_LE (data + 0);
866 guid.v2 = GST_READ_UINT32_LE (data + 4);
867 guid.v3 = GST_READ_UINT32_LE (data + 8);
868 guid.v4 = GST_READ_UINT32_LE (data + 12);
870 object->size = GST_READ_UINT64_LE (data + 16);
872 /* FIXME: make asf_demux_identify_object_guid() */
873 object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
874 if (object->id == ASF_OBJ_UNDEFINED && expect) {
875 GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
876 guid.v1, guid.v2, guid.v3, guid.v4);
883 gst_asf_demux_release_old_pads (GstASFDemux * demux)
885 GST_DEBUG_OBJECT (demux, "Releasing old pads");
887 while (demux->old_num_streams > 0) {
888 gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
889 gst_event_new_eos ());
890 gst_asf_demux_free_stream (demux,
891 &demux->old_stream[demux->old_num_streams - 1]);
892 --demux->old_num_streams;
894 memset (demux->old_stream, 0, sizeof (demux->old_stream));
895 demux->old_num_streams = 0;
899 gst_asf_demux_chain_headers (GstASFDemux * demux)
903 guint8 *header_data, *data = NULL;
904 const guint8 *cdata = NULL;
907 cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
911 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
912 if (obj.id != ASF_OBJ_HEADER)
915 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
917 /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
918 if (gst_adapter_available (demux->adapter) < obj.size + 50)
921 data = gst_adapter_take (demux->adapter, obj.size + 50);
924 header_size = obj.size;
925 flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
926 if (flow != GST_FLOW_OK)
929 /* calculate where the packet data starts */
930 demux->data_offset = obj.size + 50;
932 /* now parse the beginning of the ASF_OBJ_DATA object */
933 if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
936 if (demux->num_streams == 0)
945 GST_LOG_OBJECT (demux, "not enough data in adapter yet");
952 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
953 ("This doesn't seem to be an ASF file"));
955 return GST_FLOW_ERROR;
960 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
961 ("header parsing failed, or no streams found, flow = %s",
962 gst_flow_get_name (flow)));
964 return GST_FLOW_ERROR;
969 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
974 GST_DEBUG_OBJECT (demux, "Aggregating");
976 /* Store the value */
977 stream->last_flow = flow;
979 /* any other error that is not not-linked can be returned right away */
980 if (flow != GST_FLOW_NOT_LINKED)
983 for (i = 0; i < demux->num_streams; i++) {
984 if (demux->stream[i].active) {
985 flow = demux->stream[i].last_flow;
986 GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
987 gst_flow_get_name (flow));
988 if (flow != GST_FLOW_NOT_LINKED)
993 /* If we got here, then all our active streams are not linked */
999 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1000 GstBuffer ** p_buf, GstFlowReturn * p_flow)
1005 GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1008 flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1010 if (G_LIKELY (p_flow))
1013 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1014 GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1015 "+%u", gst_flow_get_name (flow), offset, size);
1020 g_assert (*p_buf != NULL);
1022 buffer_size = gst_buffer_get_size (*p_buf);
1023 if (G_UNLIKELY (buffer_size < size)) {
1024 GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1025 "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1026 gst_buffer_unref (*p_buf);
1027 if (G_LIKELY (p_flow))
1028 *p_flow = GST_FLOW_EOS;
1037 gst_asf_demux_pull_indices (GstASFDemux * demux)
1039 GstBuffer *buf = NULL;
1043 offset = demux->index_offset;
1045 if (G_UNLIKELY (offset == 0)) {
1046 GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1050 while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1056 gst_buffer_map (buf, &map, GST_MAP_READ);
1057 g_assert (map.size >= 16 + 8);
1058 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1059 gst_buffer_unmap (buf, &map);
1060 gst_buffer_replace (&buf, NULL);
1062 /* check for sanity */
1063 if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1064 GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1068 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1072 GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1073 ", size %u", offset, (guint) obj.size);
1075 offset += obj.size; /* increase before _process_object changes it */
1077 gst_buffer_map (buf, &map, GST_MAP_READ);
1078 g_assert (map.size >= obj.size);
1079 bufdata = (guint8 *) map.data;
1080 flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1081 gst_buffer_unmap (buf, &map);
1082 gst_buffer_replace (&buf, NULL);
1084 if (G_UNLIKELY (flow != GST_FLOW_OK))
1089 GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1093 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1097 asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1098 if (obj.id != ASF_OBJ_DATA) {
1099 GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1103 demux->state = GST_ASF_DEMUX_STATE_DATA;
1105 if (!demux->broadcast && obj.size > 50) {
1106 demux->data_size = obj.size - 50;
1107 /* CHECKME: for at least one file this is off by +158 bytes?! */
1108 demux->index_offset = demux->data_offset + demux->data_size;
1110 demux->data_size = 0;
1111 demux->index_offset = 0;
1116 if (!demux->broadcast) {
1117 /* skip object header (24 bytes) and file GUID (16 bytes) */
1118 demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1120 demux->num_packets = 0;
1123 if (demux->num_packets == 0)
1124 demux->seekable = FALSE;
1126 /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1127 if (demux->data_size == 0 && demux->num_packets > 0) {
1128 demux->data_size = demux->num_packets * demux->packet_size;
1129 demux->index_offset = demux->data_offset + demux->data_size;
1132 /* process pending stream objects and create pads for those */
1133 gst_asf_demux_process_queued_extended_stream_objects (demux);
1135 GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1136 "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1137 ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1138 demux->data_offset, demux->data_size, demux->index_offset);
1144 gst_asf_demux_pull_headers (GstASFDemux * demux)
1148 GstBuffer *buf = NULL;
1153 GST_LOG_OBJECT (demux, "reading headers");
1155 /* pull HEADER object header, so we know its size */
1156 if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1159 gst_buffer_map (buf, &map, GST_MAP_READ);
1160 g_assert (map.size >= 16 + 8);
1161 asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1162 gst_buffer_unmap (buf, &map);
1163 gst_buffer_replace (&buf, NULL);
1165 if (obj.id != ASF_OBJ_HEADER)
1168 GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1170 /* pull HEADER object */
1171 if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1175 size = obj.size; /* don't want obj.size changed */
1176 gst_buffer_map (buf, &map, GST_MAP_READ);
1177 g_assert (map.size >= size);
1178 bufdata = (guint8 *) map.data;
1179 flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1180 gst_buffer_unmap (buf, &map);
1181 gst_buffer_replace (&buf, NULL);
1183 if (flow != GST_FLOW_OK) {
1184 GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1188 /* calculate where the packet data starts */
1189 demux->data_offset = demux->base_offset + obj.size + 50;
1191 /* now pull beginning of DATA object before packet data */
1192 if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1196 gst_buffer_map (buf, &map, GST_MAP_READ);
1197 g_assert (map.size >= size);
1198 bufdata = (guint8 *) map.data;
1199 if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1202 if (demux->num_streams == 0)
1205 gst_buffer_unmap (buf, &map);
1206 gst_buffer_replace (&buf, NULL);
1214 gst_buffer_unmap (buf, &map);
1215 gst_buffer_replace (&buf, NULL);
1217 GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1218 ("This doesn't seem to be an ASF file"));
1227 gst_buffer_unmap (buf, &map);
1228 gst_buffer_replace (&buf, NULL);
1229 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1235 all_streams_prerolled (GstASFDemux * demux)
1237 GstClockTime preroll_time;
1238 guint i, num_no_data = 0;
1240 /* Allow at least 500ms of preroll_time */
1241 preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1243 /* returns TRUE as long as there isn't a stream which (a) has data queued
1244 * and (b) the timestamp of last piece of data queued is < demux->preroll
1245 * AND there is at least one other stream with data queued */
1246 for (i = 0; i < demux->num_streams; ++i) {
1247 AsfPayload *last_payload = NULL;
1251 stream = &demux->stream[i];
1252 if (G_UNLIKELY (stream->payloads->len == 0)) {
1254 GST_LOG_OBJECT (stream->pad, "no data queued");
1258 /* find last payload with timestamp */
1259 for (last_idx = stream->payloads->len - 1;
1260 last_idx >= 0 && (last_payload == NULL
1261 || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1262 last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1265 GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1266 GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1267 GST_TIME_ARGS (preroll_time));
1268 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1269 || last_payload->ts <= preroll_time)) {
1270 GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1275 if (G_UNLIKELY (num_no_data > 0))
1283 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1288 for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1291 /* check for each mutual exclusion group whether it affects this stream */
1292 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1293 if (*mes == stream->id) {
1294 /* we are in this group; let's check if we've already activated streams
1295 * that are in the same group (and hence mutually exclusive to this
1297 for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1300 for (i = 0; i < demux->num_streams; ++i) {
1301 if (demux->stream[i].id == *mes && demux->stream[i].active) {
1302 GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1303 "to already active stream with ID %d", stream->id,
1304 demux->stream[i].id);
1309 /* we can only be in this group once, let's break out and move on to
1310 * the next mutual exclusion group */
1321 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1323 /* remember the first queued timestamp for the segment */
1324 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1325 GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1326 GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1327 GST_TIME_ARGS (demux->first_ts));
1328 demux->segment_ts = payload_ts;
1329 /* always note, but only determines segment when streaming */
1330 if (demux->streaming)
1331 gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1332 GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1333 GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1338 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1340 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1341 GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1344 /* go trhough each stream, find smallest timestamp */
1345 for (i = 0; i < demux->num_streams; ++i) {
1348 GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1349 stream = &demux->stream[i];
1351 for (j = 0; j < stream->payloads->len; ++j) {
1352 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1353 if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1354 (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1355 || stream_min_ts > payload->ts))
1356 stream_min_ts = payload->ts;
1359 /* if we don't have timestamp for this stream, wait for more data */
1360 if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1363 if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1364 (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1365 first_ts = stream_min_ts;
1368 if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
1371 demux->first_ts = first_ts;
1373 /* update packets queued before we knew first timestamp */
1374 for (i = 0; i < demux->num_streams; ++i) {
1377 stream = &demux->stream[i];
1379 for (j = 0; j < stream->payloads->len; ++j) {
1380 AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1381 if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1382 if (payload->ts > first_ts)
1383 payload->ts -= first_ts;
1391 gst_asf_demux_check_segment_ts (demux, 0);
1397 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1399 /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1400 and often set wrong, inspecting the data is the only way that seem to be working */
1401 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1402 GstCaps *caps = NULL;
1404 GstAdapter *adapter = gst_adapter_new ();
1406 for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1408 AsfPayload *payload;
1411 payload = &g_array_index (stream->payloads, AsfPayload, i);
1412 gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1413 len = gst_adapter_available (adapter);
1414 data = gst_adapter_map (adapter, len);
1418 #define MIN_LENGTH 128
1420 /* look for the sync points */
1422 if (len < MIN_LENGTH || /* give typefind something to work on */
1423 (data[0] == 0x0b && data[1] == 0x77) || /* AC-3 sync point */
1424 (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF)) /* MPEG sync point */
1430 gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1433 if (prob < GST_TYPE_FIND_LIKELY) {
1436 if (len > MIN_LENGTH)
1437 /* this wasn't it, look for another sync point */
1441 gst_adapter_unmap (adapter);
1444 gst_object_unref (adapter);
1447 gst_caps_take (&stream->caps, caps);
1455 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1459 if (demux->activated_streams)
1462 if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1465 if (!all_streams_prerolled (demux) && !force) {
1466 GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1470 for (i = 0; i < demux->num_streams; ++i) {
1471 AsfStream *stream = &demux->stream[i];
1473 if (stream->payloads->len > 0) {
1475 if (stream->inspect_payload && /* dvr-ms required payload inspection */
1476 !stream->active && /* do not inspect active streams (caps were already set) */
1477 !gst_asf_demux_update_caps_from_payload (demux, stream) && /* failed to determine caps */
1478 stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1479 /* try to gather some more data */
1482 /* we don't check mutual exclusion stuff here; either we have data for
1483 * a stream, then we active it, or we don't, then we'll ignore it */
1484 GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1485 gst_asf_demux_activate_stream (demux, stream);
1487 GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1491 gst_asf_demux_release_old_pads (demux);
1493 demux->activated_streams = TRUE;
1494 GST_LOG_OBJECT (demux, "signalling no more pads");
1495 gst_element_no_more_pads (GST_ELEMENT (demux));
1499 /* returns the stream that has a complete payload with the lowest timestamp
1500 * queued, or NULL (we push things by timestamp because during the internal
1501 * prerolling we might accumulate more data then the external queues can take,
1502 * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1504 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1506 AsfPayload *best_payload = NULL;
1507 AsfStream *best_stream = NULL;
1510 for (i = 0; i < demux->num_streams; ++i) {
1514 stream = &demux->stream[i];
1516 /* Don't push any data until we have at least one payload that falls within
1517 * the current segment. This way we can remove out-of-segment payloads that
1518 * don't need to be decoded after a seek, sending only data from the
1519 * keyframe directly before our segment start */
1520 if (stream->payloads->len > 0) {
1521 AsfPayload *payload = NULL;
1524 /* find last payload with timestamp */
1525 for (last_idx = stream->payloads->len - 1;
1526 last_idx >= 0 && (payload == NULL
1527 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1528 payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1531 /* if this is first payload after seek we might need to update the segment */
1532 if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1533 gst_asf_demux_check_segment_ts (demux, payload->ts);
1535 if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1536 (payload->ts < demux->segment.start))) {
1537 if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1538 GST_DEBUG_OBJECT (stream->pad,
1539 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1540 GST_TIME_ARGS (payload->ts));
1541 demux->segment.start = payload->ts;
1542 demux->segment.time = payload->ts;
1544 GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1545 GST_TIME_FORMAT " which is before our segment start %"
1546 GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1547 GST_TIME_ARGS (demux->segment.start));
1552 /* Now see if there's a complete payload queued for this stream */
1555 /* find first complete payload with timestamp */
1557 j < stream->payloads->len && (payload == NULL
1558 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1559 payload = &g_array_index (stream->payloads, AsfPayload, j);
1562 if (!gst_asf_payload_is_complete (payload))
1565 /* ... and whether its timestamp is lower than the current best */
1566 if (best_stream == NULL || best_payload->ts > payload->ts) {
1567 best_stream = stream;
1568 best_payload = payload;
1576 static GstFlowReturn
1577 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1580 GstFlowReturn ret = GST_FLOW_OK;
1582 if (G_UNLIKELY (!demux->activated_streams)) {
1583 if (!gst_asf_demux_check_activate_streams (demux, force))
1585 /* streams are now activated */
1588 while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1589 AsfPayload *payload;
1591 /* wait until we had a chance to "lock on" some payload's timestamp */
1592 if (G_UNLIKELY (demux->need_newsegment
1593 && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1596 payload = &g_array_index (stream->payloads, AsfPayload, 0);
1598 /* do we need to send a newsegment event */
1599 if ((G_UNLIKELY (demux->need_newsegment))) {
1600 GstEvent *segment_event;
1602 /* safe default if insufficient upstream info */
1603 if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1606 if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1607 demux->segment.duration > 0) {
1608 /* slight HACK; prevent clipping of last bit */
1609 demux->segment.stop = demux->segment.duration + demux->in_gap;
1612 /* FIXME : only if ACCURATE ! */
1613 if (G_LIKELY (!demux->accurate
1614 && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1615 GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1616 GST_TIME_ARGS (payload->ts));
1617 demux->segment.start = payload->ts;
1618 demux->segment.time = payload->ts;
1621 GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1624 /* note: we fix up all timestamps to start from 0, so this should be ok */
1625 segment_event = gst_event_new_segment (&demux->segment);
1626 if (demux->segment_seqnum)
1627 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1628 gst_asf_demux_send_event_unlocked (demux, segment_event);
1630 /* now post any global tags we may have found */
1631 if (demux->taglist == NULL) {
1632 demux->taglist = gst_tag_list_new_empty ();
1633 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1636 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1637 GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1639 GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1640 gst_asf_demux_send_event_unlocked (demux,
1641 gst_event_new_tag (demux->taglist));
1642 demux->taglist = NULL;
1644 demux->need_newsegment = FALSE;
1645 demux->segment_seqnum = 0;
1646 demux->segment_running = TRUE;
1649 /* Do we have tags pending for this stream? */
1650 if (G_UNLIKELY (stream->pending_tags)) {
1651 GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1652 gst_pad_push_event (stream->pad,
1653 gst_event_new_tag (stream->pending_tags));
1654 stream->pending_tags = NULL;
1657 /* We have the whole packet now so we should push the packet to
1658 * the src pad now. First though we should check if we need to do
1660 if (G_UNLIKELY (demux->span > 1)) {
1661 gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1664 payload->buf = gst_buffer_make_writable (payload->buf);
1666 if (G_LIKELY (!payload->keyframe)) {
1667 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1670 if (G_UNLIKELY (stream->discont)) {
1671 GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1672 GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1673 stream->discont = FALSE;
1676 if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1677 (payload->par_x != stream->par_x) &&
1678 (payload->par_y != stream->par_y))) {
1679 GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1680 stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1681 stream->par_x = payload->par_x;
1682 stream->par_y = payload->par_y;
1683 stream->caps = gst_caps_make_writable (stream->caps);
1684 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1685 GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1686 gst_pad_set_caps (stream->pad, stream->caps);
1689 if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1690 GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1691 payload->interlaced);
1692 stream->interlaced = payload->interlaced;
1693 stream->caps = gst_caps_make_writable (stream->caps);
1694 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1695 (stream->interlaced ? "mixed" : "progressive"), NULL);
1696 gst_pad_set_caps (stream->pad, stream->caps);
1699 /* (sort of) interpolate timestamps using upstream "frame of reference",
1700 * typically useful for live src, but might (unavoidably) mess with
1701 * position reporting if a live src is playing not so live content
1702 * (e.g. rtspsrc taking some time to fall back to tcp) */
1703 GST_BUFFER_PTS (payload->buf) = payload->ts;
1704 if (GST_BUFFER_PTS_IS_VALID (payload->buf)) {
1705 GST_BUFFER_PTS (payload->buf) += demux->in_gap;
1707 if (payload->duration == GST_CLOCK_TIME_NONE
1708 && stream->ext_props.avg_time_per_frame != 0)
1709 GST_BUFFER_DURATION (payload->buf) =
1710 stream->ext_props.avg_time_per_frame * 100;
1712 GST_BUFFER_DURATION (payload->buf) = payload->duration;
1714 /* FIXME: we should really set durations on buffers if we can */
1716 GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1717 ", dur=%" GST_TIME_FORMAT " size=%" G_GSIZE_FORMAT,
1718 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1719 GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1720 gst_buffer_get_size (payload->buf));
1722 if (stream->active) {
1723 ret = gst_pad_push (stream->pad, payload->buf);
1724 ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1726 gst_buffer_unref (payload->buf);
1729 payload->buf = NULL;
1730 g_array_remove_index (stream->payloads, 0);
1732 /* Break out as soon as we have an issue */
1733 if (G_UNLIKELY (ret != GST_FLOW_OK))
1741 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1745 g_assert (buf != NULL);
1747 GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1749 gst_buffer_map (buf, &map, GST_MAP_READ);
1751 /* we return false on buffer too small */
1752 if (map.size < ASF_OBJECT_HEADER_SIZE) {
1753 gst_buffer_unmap (buf, &map);
1757 /* check if it is a header */
1758 asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1759 gst_buffer_unmap (buf, &map);
1760 if (obj.id == ASF_OBJ_HEADER) {
1767 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1769 guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1770 GstFlowReturn ret = GST_FLOW_OK;
1771 GstBuffer *buf = NULL;
1772 gboolean header = FALSE;
1774 /* TODO maybe we should skip index objects after the data and look
1775 * further for a new header */
1776 if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1777 g_assert (buf != NULL);
1778 /* check if it is a header */
1779 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1780 GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1781 demux->base_offset = off;
1785 gst_buffer_unref (buf);
1792 gst_asf_demux_loop (GstASFDemux * demux)
1794 GstFlowReturn flow = GST_FLOW_OK;
1795 GstBuffer *buf = NULL;
1797 gboolean sent_eos = FALSE;
1799 if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1800 if (!gst_asf_demux_pull_headers (demux)) {
1801 flow = GST_FLOW_ERROR;
1805 gst_asf_demux_pull_indices (demux);
1808 g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1810 if (G_UNLIKELY (demux->num_packets != 0
1811 && demux->packet >= demux->num_packets))
1814 GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1815 (guint) demux->num_packets);
1817 off = demux->data_offset + (demux->packet * demux->packet_size);
1819 if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1820 demux->packet_size * demux->speed_packets, &buf, &flow))) {
1821 GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1822 if (flow == GST_FLOW_EOS)
1824 else if (flow == GST_FLOW_FLUSHING) {
1825 GST_DEBUG_OBJECT (demux, "Not fatal");
1831 if (G_LIKELY (demux->speed_packets == 1)) {
1832 GstAsfDemuxParsePacketError err;
1833 err = gst_asf_demux_parse_packet (demux, buf);
1834 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1835 /* when we don't know when the data object ends, we should check
1836 * for a chained asf */
1837 if (demux->num_packets == 0) {
1838 if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1839 GST_INFO_OBJECT (demux, "Chained asf found");
1840 demux->base_offset = off;
1841 gst_asf_demux_reset (demux, TRUE);
1842 gst_buffer_unref (buf);
1846 /* FIXME: We should tally up fatal errors and error out only
1847 * after a few broken packets in a row? */
1849 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1850 gst_buffer_unref (buf);
1855 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1861 for (n = 0; n < demux->speed_packets; n++) {
1863 GstAsfDemuxParsePacketError err;
1866 gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
1867 n * demux->packet_size, demux->packet_size);
1868 err = gst_asf_demux_parse_packet (demux, sub);
1869 if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1870 /* when we don't know when the data object ends, we should check
1871 * for a chained asf */
1872 if (demux->num_packets == 0) {
1873 if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1874 GST_INFO_OBJECT (demux, "Chained asf found");
1875 demux->base_offset = off + n * demux->packet_size;
1876 gst_asf_demux_reset (demux, TRUE);
1877 gst_buffer_unref (sub);
1878 gst_buffer_unref (buf);
1882 /* FIXME: We should tally up fatal errors and error out only
1883 * after a few broken packets in a row? */
1885 GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1889 gst_buffer_unref (sub);
1891 if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
1892 flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1898 /* reset speed pull */
1899 demux->speed_packets = 1;
1902 gst_buffer_unref (buf);
1904 if (G_UNLIKELY (demux->num_packets > 0
1905 && demux->packet >= demux->num_packets)) {
1906 GST_LOG_OBJECT (demux, "reached EOS");
1910 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1911 GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1915 /* check if we're at the end of the configured segment */
1916 /* FIXME: check if segment end reached etc. */
1922 /* if we haven't activated our streams yet, this might be because we have
1923 * less data queued than required for preroll; force stream activation and
1924 * send any pending payloads before sending EOS */
1925 if (!demux->activated_streams)
1926 gst_asf_demux_push_complete_payloads (demux, TRUE);
1928 /* we want to push an eos or post a segment-done in any case */
1929 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1932 /* for segment playback we need to post when (in stream time)
1933 * we stopped, this is either stop (when set) or the duration. */
1934 if ((stop = demux->segment.stop) == -1)
1935 stop = demux->segment.duration;
1937 GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1938 gst_element_post_message (GST_ELEMENT_CAST (demux),
1939 gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1941 gst_asf_demux_send_event_unlocked (demux,
1942 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
1943 } else if (flow != GST_FLOW_EOS) {
1944 /* check if we have a chained asf, in case, we don't eos yet */
1945 if (gst_asf_demux_check_chained_asf (demux)) {
1946 GST_INFO_OBJECT (demux, "Chained ASF starting");
1947 gst_asf_demux_reset (demux, TRUE);
1951 /* normal playback, send EOS to all linked pads */
1952 GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1953 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1955 /* ... and fall through to pause */
1959 GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1960 gst_flow_get_name (flow));
1961 demux->segment_running = FALSE;
1962 gst_pad_pause_task (demux->sinkpad);
1964 /* For the error cases (not EOS) */
1966 if (flow == GST_FLOW_EOS)
1967 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1968 else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
1969 /* Post an error. Hopefully something else already has, but if not... */
1970 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1971 (_("Internal data stream error.")),
1972 ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1981 GST_DEBUG_OBJECT (demux, "Read failed, doh");
1982 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1983 flow = GST_FLOW_EOS;
1987 /* See FIXMEs above */
1990 gst_buffer_unref (buf);
1991 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1992 ("Error parsing ASF packet %u", (guint) demux->packet));
1993 gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1994 flow = GST_FLOW_ERROR;
2000 #define GST_ASF_DEMUX_CHECK_HEADER_YES 0
2001 #define GST_ASF_DEMUX_CHECK_HEADER_NO 1
2002 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2005 gst_asf_demux_check_header (GstASFDemux * demux)
2008 guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2009 ASF_OBJECT_HEADER_SIZE);
2010 if (cdata == NULL) /* need more data */
2011 return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2013 asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2014 if (obj.id != ASF_OBJ_HEADER) {
2015 return GST_ASF_DEMUX_CHECK_HEADER_NO;
2017 return GST_ASF_DEMUX_CHECK_HEADER_YES;
2021 static GstFlowReturn
2022 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2024 GstFlowReturn ret = GST_FLOW_OK;
2027 demux = GST_ASF_DEMUX (parent);
2029 GST_LOG_OBJECT (demux,
2030 "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2031 GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2032 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2034 if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2035 GST_DEBUG_OBJECT (demux, "received DISCONT");
2036 gst_asf_demux_mark_discont (demux);
2039 if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2040 GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2041 demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2042 GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2043 ", interpolation gap: %" GST_TIME_FORMAT,
2044 GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2047 gst_adapter_push (demux->adapter, buf);
2049 switch (demux->state) {
2050 case GST_ASF_DEMUX_STATE_INDEX:{
2051 gint result = gst_asf_demux_check_header (demux);
2052 if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */
2055 if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2056 /* we don't care about this, probably an index */
2057 /* TODO maybe would be smarter to skip all the indices
2058 * until we got a new header or EOS to decide */
2059 GST_LOG_OBJECT (demux, "Received index object, its EOS");
2062 GST_INFO_OBJECT (demux, "Chained asf starting");
2063 /* cleanup and get ready for a chained asf */
2064 gst_asf_demux_reset (demux, TRUE);
2068 case GST_ASF_DEMUX_STATE_HEADER:{
2069 ret = gst_asf_demux_chain_headers (demux);
2070 if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2072 /* otherwise fall through */
2074 case GST_ASF_DEMUX_STATE_DATA:
2078 data_size = demux->packet_size;
2080 while (gst_adapter_available (demux->adapter) >= data_size) {
2082 GstAsfDemuxParsePacketError err;
2084 /* we don't know the length of the stream
2085 * check for a chained asf everytime */
2086 if (demux->num_packets == 0) {
2087 gint result = gst_asf_demux_check_header (demux);
2089 if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2090 GST_INFO_OBJECT (demux, "Chained asf starting");
2091 /* cleanup and get ready for a chained asf */
2092 gst_asf_demux_reset (demux, TRUE);
2095 } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2096 && demux->packet >= demux->num_packets)) {
2097 /* do not overshoot data section when streaming */
2101 buf = gst_adapter_take_buffer (demux->adapter, data_size);
2103 /* FIXME: We should tally up fatal errors and error out only
2104 * after a few broken packets in a row? */
2105 err = gst_asf_demux_parse_packet (demux, buf);
2107 gst_buffer_unref (buf);
2109 if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2110 ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2112 GST_WARNING_OBJECT (demux, "Parse error");
2114 if (demux->packet >= 0)
2117 if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2118 && demux->packet >= demux->num_packets)) {
2119 demux->state = GST_ASF_DEMUX_STATE_INDEX;
2124 g_assert_not_reached ();
2128 if (ret != GST_FLOW_OK)
2129 GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2135 GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2141 static inline gboolean
2142 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2144 if (*p_size < num_bytes)
2147 *p_data += num_bytes;
2148 *p_size -= num_bytes;
2152 static inline guint8
2153 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2157 g_assert (*p_size >= 1);
2158 ret = GST_READ_UINT8 (*p_data);
2159 *p_data += sizeof (guint8);
2160 *p_size -= sizeof (guint8);
2164 static inline guint16
2165 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2169 g_assert (*p_size >= 2);
2170 ret = GST_READ_UINT16_LE (*p_data);
2171 *p_data += sizeof (guint16);
2172 *p_size -= sizeof (guint16);
2176 static inline guint32
2177 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2181 g_assert (*p_size >= 4);
2182 ret = GST_READ_UINT32_LE (*p_data);
2183 *p_data += sizeof (guint32);
2184 *p_size -= sizeof (guint32);
2188 static inline guint64
2189 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2193 g_assert (*p_size >= 8);
2194 ret = GST_READ_UINT64_LE (*p_data);
2195 *p_data += sizeof (guint64);
2196 *p_size -= sizeof (guint64);
2200 static inline guint32
2201 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
2208 g_assert (*p_size >= 1);
2209 return gst_asf_demux_get_uint8 (p_data, p_size);
2212 g_assert (*p_size >= 2);
2213 return gst_asf_demux_get_uint16 (p_data, p_size);
2216 g_assert (*p_size >= 4);
2217 return gst_asf_demux_get_uint32 (p_data, p_size);
2220 g_assert_not_reached ();
2227 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2228 guint8 ** p_data, guint64 * p_size)
2232 if (*p_size < num_bytes_to_read)
2235 *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2236 gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2238 *p_data += num_bytes_to_read;
2239 *p_size -= num_bytes_to_read;
2245 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2246 guint8 ** p_data, guint64 * p_size)
2250 if (*p_size < num_bytes_to_read)
2253 *p_buf = g_memdup (*p_data, num_bytes_to_read);
2254 *p_data += num_bytes_to_read;
2255 *p_size -= num_bytes_to_read;
2260 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2261 guint8 ** p_data, guint64 * p_size)
2271 s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2274 *p_strlen = s_length;
2276 if (s_length == 0) {
2277 GST_WARNING ("zero-length string");
2278 *p_str = g_strdup ("");
2282 if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2285 g_assert (s != NULL);
2287 /* just because They don't exist doesn't
2288 * mean They are not out to get you ... */
2289 if (s[s_length - 1] != '\0') {
2290 s = g_realloc (s, s_length + 1);
2294 *p_str = (gchar *) s;
2300 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2302 g_assert (*p_size >= 4 * sizeof (guint32));
2304 guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2305 guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2306 guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2307 guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2311 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2314 if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2317 /* WAVEFORMATEX Structure */
2318 audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2319 audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2320 audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2321 audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2322 audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2323 audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2324 /* Codec specific data size */
2325 audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2330 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2333 if (*p_size < (4 + 4 + 1 + 2))
2336 video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2337 video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2338 video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2339 video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2344 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2345 guint8 ** p_data, guint64 * p_size)
2347 if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2350 fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2351 fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2352 fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2353 fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2354 fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2355 fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2356 fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2357 fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2358 fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2359 fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2360 fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2365 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2369 for (i = 0; i < demux->num_streams; i++) {
2370 if (demux->stream[i].id == id)
2371 return &demux->stream[i];
2374 if (gst_asf_demux_is_unknown_stream (demux, id))
2375 GST_WARNING ("Segment found for undefined stream: (%d)", id);
2380 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2381 GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2385 gst_pad_use_fixed_caps (src_pad);
2386 gst_pad_set_caps (src_pad, caps);
2388 gst_pad_set_event_function (src_pad,
2389 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2390 gst_pad_set_query_function (src_pad,
2391 GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2393 stream = &demux->stream[demux->num_streams];
2394 stream->caps = caps;
2395 stream->pad = src_pad;
2397 stream->fps_known = !is_video; /* bit hacky for audio */
2398 stream->is_video = is_video;
2399 stream->pending_tags = tags;
2400 stream->discont = TRUE;
2404 st = gst_caps_get_structure (caps, 0);
2405 if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2406 par_x > 0 && par_y > 0) {
2407 GST_DEBUG ("PAR %d/%d", par_x, par_y);
2408 stream->par_x = par_x;
2409 stream->par_y = par_y;
2413 stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2415 GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2416 GST_PAD_NAME (src_pad), demux->num_streams, caps);
2418 ++demux->num_streams;
2420 stream->active = FALSE;
2424 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2425 asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2427 GstTagList *tags = NULL;
2428 GstBuffer *extradata = NULL;
2431 guint16 size_left = 0;
2432 gchar *codec_name = NULL;
2435 size_left = audio->size;
2437 /* Create the audio pad */
2438 name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2440 src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2443 /* Swallow up any left over data and set up the
2444 * standard properties from the header info */
2446 GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2447 "codec specific data", size_left);
2449 g_assert (size_left <= *p_size);
2450 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2453 /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2454 * additional two bytes indicating extradata. */
2455 /* FIXME: Handle the channel reorder map here */
2456 caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2457 (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2460 caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2461 G_TYPE_INT, (gint) audio->codec_tag, NULL);
2464 /* Informing about that audio format we just added */
2466 tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2467 g_free (codec_name);
2471 gst_buffer_unref (extradata);
2473 GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2474 GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2475 audio->codec_tag, tags);
2477 ++demux->num_audio_streams;
2479 gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2483 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2484 asf_stream_video_format * video, guint16 id,
2485 guint8 ** p_data, guint64 * p_size)
2487 GstTagList *tags = NULL;
2488 GstBuffer *extradata = NULL;
2493 gchar *codec_name = NULL;
2494 gint size_left = video->size - 40;
2496 /* Create the video pad */
2497 name = g_strdup_printf ("video_%u", demux->num_video_streams);
2498 src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2501 /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2503 GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2504 g_assert (size_left <= *p_size);
2505 gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2508 GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2510 /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2511 caps = gst_riff_create_video_caps (video->tag, NULL,
2512 (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2515 caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2516 G_TYPE_UINT, video->tag, NULL);
2521 s = gst_asf_demux_get_metadata_for_stream (demux, id);
2522 if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2523 gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2524 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2529 /* retry with the global metadata */
2530 GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2531 demux->global_metadata);
2532 s = demux->global_metadata;
2533 if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2534 gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2535 GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2536 if (ax > 0 && ay > 0)
2537 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2541 s = gst_caps_get_structure (caps, 0);
2542 gst_structure_remove_field (s, "framerate");
2545 /* add fourcc format to caps, some proprietary decoders seem to need it */
2546 str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2547 gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2551 tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2552 g_free (codec_name);
2556 gst_buffer_unref (extradata);
2558 GST_INFO ("Adding video stream #%u, id %u, codec %"
2559 GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2560 GST_FOURCC_ARGS (video->tag), video->tag);
2562 ++demux->num_video_streams;
2564 gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2568 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2570 if (!stream->active) {
2574 GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2575 GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2576 gst_pad_set_active (stream->pad, TRUE);
2579 gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2580 "%03u", stream->id);
2583 gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2585 if (gst_event_parse_group_id (event, &demux->group_id))
2586 demux->have_group_id = TRUE;
2588 demux->have_group_id = FALSE;
2589 gst_event_unref (event);
2590 } else if (!demux->have_group_id) {
2591 demux->have_group_id = TRUE;
2592 demux->group_id = gst_util_group_id_next ();
2595 event = gst_event_new_stream_start (stream_id);
2596 if (demux->have_group_id)
2597 gst_event_set_group_id (event, demux->group_id);
2599 gst_pad_push_event (stream->pad, event);
2601 gst_pad_set_caps (stream->pad, stream->caps);
2603 gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2604 stream->active = TRUE;
2609 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2612 AsfCorrectionType correction_type;
2613 AsfStreamType stream_type;
2614 GstClockTime time_offset;
2615 gboolean is_encrypted G_GNUC_UNUSED;
2619 guint stream_specific_size;
2620 guint type_specific_size G_GNUC_UNUSED;
2621 guint unknown G_GNUC_UNUSED;
2622 gboolean inspect_payload = FALSE;
2625 /* Get the rest of the header's header */
2626 if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2627 goto not_enough_data;
2629 gst_asf_demux_get_guid (&guid, &data, &size);
2630 stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2632 gst_asf_demux_get_guid (&guid, &data, &size);
2633 correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2635 time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2637 type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2638 stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2640 flags = gst_asf_demux_get_uint16 (&data, &size);
2641 stream_id = flags & 0x7f;
2642 is_encrypted = ! !((flags & 0x8000) << 15);
2643 unknown = gst_asf_demux_get_uint32 (&data, &size);
2645 GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2646 stream_id, GST_TIME_ARGS (time_offset));
2648 /* dvr-ms has audio stream declared in stream specific data */
2649 if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2650 AsfExtStreamType ext_stream_type;
2651 gst_asf_demux_get_guid (&guid, &data, &size);
2652 ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2654 if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2655 inspect_payload = TRUE;
2657 gst_asf_demux_get_guid (&guid, &data, &size);
2658 gst_asf_demux_get_uint32 (&data, &size);
2659 gst_asf_demux_get_uint32 (&data, &size);
2660 gst_asf_demux_get_uint32 (&data, &size);
2661 gst_asf_demux_get_guid (&guid, &data, &size);
2662 gst_asf_demux_get_uint32 (&data, &size);
2663 stream_type = ASF_STREAM_AUDIO;
2667 switch (stream_type) {
2668 case ASF_STREAM_AUDIO:{
2669 asf_stream_audio audio_object;
2671 if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2672 goto not_enough_data;
2674 GST_INFO ("Object is an audio stream with %u bytes of additional data",
2677 gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2680 switch (correction_type) {
2681 case ASF_CORRECTION_ON:{
2682 guint span, packet_size, chunk_size, data_size, silence_data;
2684 GST_INFO ("Using error correction");
2686 if (size < (1 + 2 + 2 + 2 + 1))
2687 goto not_enough_data;
2689 span = gst_asf_demux_get_uint8 (&data, &size);
2690 packet_size = gst_asf_demux_get_uint16 (&data, &size);
2691 chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2692 data_size = gst_asf_demux_get_uint16 (&data, &size);
2693 silence_data = gst_asf_demux_get_uint8 (&data, &size);
2695 /* FIXME: shouldn't this be per-stream? */
2698 GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2699 packet_size, chunk_size, data_size, span, silence_data);
2701 if (demux->span > 1) {
2702 if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2703 /* Disable descrambling */
2706 /* FIXME: this else branch was added for
2707 * weird_al_yankovic - the saga begins.asf */
2708 demux->ds_packet_size = packet_size;
2709 demux->ds_chunk_size = chunk_size;
2712 /* Descambling is enabled */
2713 demux->ds_packet_size = packet_size;
2714 demux->ds_chunk_size = chunk_size;
2717 /* Now skip the rest of the silence data */
2719 gst_bytestream_flush (demux->bs, data_size - 1);
2721 /* FIXME: CHECKME. And why -1? */
2722 if (data_size > 1) {
2723 if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2724 goto not_enough_data;
2730 case ASF_CORRECTION_OFF:{
2731 GST_INFO ("Error correction off");
2732 if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2733 goto not_enough_data;
2737 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2738 ("Audio stream using unknown error correction"));
2745 case ASF_STREAM_VIDEO:{
2746 asf_stream_video_format video_format_object;
2747 asf_stream_video video_object;
2750 if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2751 goto not_enough_data;
2753 vsize = video_object.size - 40; /* Byte order gets offset by single byte */
2755 GST_INFO ("object is a video stream with %u bytes of "
2756 "additional data", vsize);
2758 if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2760 goto not_enough_data;
2763 gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2770 GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2772 demux->other_streams =
2773 g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
2777 stream = gst_asf_demux_get_stream (demux, stream_id);
2779 stream->inspect_payload = inspect_payload;
2784 GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2785 /* we'll error out later if we found no streams */
2790 static const gchar *
2791 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2795 const gchar *asf_name;
2796 const gchar *gst_name;
2799 "WM/Genre", GST_TAG_GENRE}, {
2800 "WM/AlbumTitle", GST_TAG_ALBUM}, {
2801 "WM/AlbumArtist", GST_TAG_ARTIST}, {
2802 "WM/Picture", GST_TAG_IMAGE}, {
2803 "WM/Track", GST_TAG_TRACK_NUMBER}, {
2804 "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2805 "WM/Year", GST_TAG_DATE_TIME}
2806 /* { "WM/Composer", GST_TAG_COMPOSER } */
2811 if (name_utf8 == NULL) {
2812 GST_WARNING ("Failed to convert name to UTF8, skipping");
2816 out = strlen (name_utf8);
2818 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2819 if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2820 GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2821 return tags[i].gst_name;
2828 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2830 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2834 GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2836 if (taglist == NULL)
2839 if (gst_tag_list_is_empty (taglist)) {
2840 gst_tag_list_unref (taglist);
2844 t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2845 gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
2847 gst_tag_list_unref (demux->taglist);
2848 gst_tag_list_unref (taglist);
2850 GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2853 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING 0
2854 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY 1
2855 #define ASF_DEMUX_DATA_TYPE_DWORD 3
2858 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2862 const guint8 *img_data = NULL;
2863 guint32 img_data_len = 0;
2864 guint8 pic_type = 0;
2866 gst_byte_reader_init (&r, tag_data, tag_data_len);
2868 /* skip mime type string (we don't trust it and do our own typefinding),
2869 * and also skip the description string, since we don't use it */
2870 if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2871 !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2872 !gst_byte_reader_skip_string_utf16 (&r) ||
2873 !gst_byte_reader_skip_string_utf16 (&r) ||
2874 !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2875 goto not_enough_data;
2879 if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2880 GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2886 GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2887 GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2892 /* Extended Content Description Object */
2893 static GstFlowReturn
2894 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2897 /* Other known (and unused) 'text/unicode' metadata available :
2900 * WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2901 * WMFSDKVersion = 9.00.00.2980
2902 * WMFSDKNeeded = 0.0.0.0000
2903 * WM/UniqueFileIdentifier = AMGa_id=R 15334;AMGp_id=P 5149;AMGt_id=T 2324984
2904 * WM/Publisher = 4AD
2906 * WM/ProviderRating = 8
2907 * WM/ProviderStyle = Rock (similar to WM/Genre)
2908 * WM/GenreID (similar to WM/Genre)
2909 * WM/TrackNumber (same as WM/Track but as a string)
2911 * Other known (and unused) 'non-text' metadata available :
2917 * We might want to read WM/TrackNumber and use atoi() if we don't have
2921 GstTagList *taglist;
2922 guint16 blockcount, i;
2924 GST_INFO_OBJECT (demux, "object is an extended content description");
2926 taglist = gst_tag_list_new_empty ();
2928 /* Content Descriptor Count */
2930 goto not_enough_data;
2932 blockcount = gst_asf_demux_get_uint16 (&data, &size);
2934 for (i = 1; i <= blockcount; ++i) {
2935 const gchar *gst_tag_name;
2939 GValue tag_value = { 0, };
2942 gchar *name_utf8 = NULL;
2946 if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2947 goto not_enough_data;
2951 goto not_enough_data;
2953 /* Descriptor Value Data Type */
2954 datatype = gst_asf_demux_get_uint16 (&data, &size);
2956 /* Descriptor Value (not really a string, but same thing reading-wise) */
2957 if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2959 goto not_enough_data;
2963 g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2965 if (name_utf8 != NULL) {
2966 GST_DEBUG ("Found tag/metadata %s", name_utf8);
2968 gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2969 GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2972 case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2975 value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2978 /* get rid of tags with empty value */
2979 if (value_utf8 != NULL && *value_utf8 != '\0') {
2980 GST_DEBUG ("string value %s", value_utf8);
2982 value_utf8[out] = '\0';
2984 if (gst_tag_name != NULL) {
2985 if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
2986 guint year = atoi (value_utf8);
2989 g_value_init (&tag_value, GST_TYPE_DATE_TIME);
2990 g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
2992 } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2993 guint id3v1_genre_id;
2994 const gchar *genre_str;
2996 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2997 ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2998 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2999 g_free (value_utf8);
3000 value_utf8 = g_strdup (genre_str);
3005 /* convert tag from string to other type if required */
3006 tag_type = gst_tag_get_type (gst_tag_name);
3007 g_value_init (&tag_value, tag_type);
3008 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3009 GValue from_val = { 0, };
3011 g_value_init (&from_val, G_TYPE_STRING);
3012 g_value_set_string (&from_val, value_utf8);
3013 if (!g_value_transform (&from_val, &tag_value)) {
3014 GST_WARNING_OBJECT (demux,
3015 "Could not transform string tag to " "%s tag type %s",
3016 gst_tag_name, g_type_name (tag_type));
3017 g_value_unset (&tag_value);
3019 g_value_unset (&from_val);
3024 GST_DEBUG ("Setting metadata");
3025 g_value_init (&tag_value, G_TYPE_STRING);
3026 g_value_set_string (&tag_value, value_utf8);
3028 } else if (value_utf8 == NULL) {
3029 GST_WARNING ("Failed to convert string value to UTF8, skipping");
3031 GST_DEBUG ("Skipping empty string value for %s",
3032 GST_STR_NULL (gst_tag_name));
3034 g_free (value_utf8);
3037 case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3039 if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3040 GST_FIXME ("Unhandled byte array tag %s",
3041 GST_STR_NULL (gst_tag_name));
3044 asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3050 case ASF_DEMUX_DATA_TYPE_DWORD:{
3051 guint uint_val = GST_READ_UINT32_LE (value);
3053 /* this is the track number */
3054 g_value_init (&tag_value, G_TYPE_UINT);
3056 /* WM/Track counts from 0 */
3057 if (!strcmp (name_utf8, "WM/Track"))
3060 g_value_set_uint (&tag_value, uint_val);
3064 GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3069 if (G_IS_VALUE (&tag_value)) {
3071 GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3073 /* WM/TrackNumber is more reliable than WM/Track, since the latter
3074 * is supposed to have a 0 base but is often wrongly written to start
3075 * from 1 as well, so prefer WM/TrackNumber when we have it: either
3076 * replace the value added earlier from WM/Track or put it first in
3077 * the list, so that it will get picked up by _get_uint() */
3078 if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3079 merge_mode = GST_TAG_MERGE_REPLACE;
3081 gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3084 GST_DEBUG ("Setting global metadata %s", name_utf8);
3085 gst_structure_set_value (demux->global_metadata, name_utf8,
3089 g_value_unset (&tag_value);
3098 gst_asf_demux_add_global_tags (demux, taglist);
3105 GST_WARNING ("Unexpected end of data parsing ext content desc object");
3106 gst_tag_list_unref (taglist);
3107 return GST_FLOW_OK; /* not really fatal */
3111 static GstStructure *
3112 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3117 g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3119 for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3122 s = gst_caps_get_structure (demux->metadata, i);
3123 if (gst_structure_has_name (s, sname))
3127 gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3129 /* try lookup again; demux->metadata took ownership of the structure, so we
3130 * can't really make any assumptions about what happened to it, so we can't
3131 * just return it directly after appending it */
3132 return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3135 static GstFlowReturn
3136 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3139 guint16 blockcount, i;
3141 GST_INFO_OBJECT (demux, "object is a metadata object");
3143 /* Content Descriptor Count */
3145 goto not_enough_data;
3147 blockcount = gst_asf_demux_get_uint16 (&data, &size);
3149 for (i = 0; i < blockcount; ++i) {
3151 guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3152 guint32 data_len, ival;
3155 if (size < (2 + 2 + 2 + 2 + 4))
3156 goto not_enough_data;
3158 lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3159 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3160 name_len = gst_asf_demux_get_uint16 (&data, &size);
3161 data_type = gst_asf_demux_get_uint16 (&data, &size);
3162 data_len = gst_asf_demux_get_uint32 (&data, &size);
3164 if (size < name_len + data_len)
3165 goto not_enough_data;
3167 /* convert name to UTF-8 */
3168 name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3170 gst_asf_demux_skip_bytes (name_len, &data, &size);
3172 if (name_utf8 == NULL) {
3173 GST_WARNING ("Failed to convert value name to UTF8, skipping");
3174 gst_asf_demux_skip_bytes (data_len, &data, &size);
3178 if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3179 gst_asf_demux_skip_bytes (data_len, &data, &size);
3187 goto not_enough_data;
3190 ival = gst_asf_demux_get_uint32 (&data, &size);
3192 /* skip anything else there may be, just in case */
3193 gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3195 s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3196 gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3200 GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3206 GST_WARNING ("Unexpected end of data parsing metadata object");
3207 return GST_FLOW_OK; /* not really fatal */
3211 static GstFlowReturn
3212 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3214 GstFlowReturn ret = GST_FLOW_OK;
3215 guint32 i, num_objects;
3216 guint8 unknown G_GNUC_UNUSED;
3218 /* Get the rest of the header's header */
3219 if (size < (4 + 1 + 1))
3220 goto not_enough_data;
3222 num_objects = gst_asf_demux_get_uint32 (&data, &size);
3223 unknown = gst_asf_demux_get_uint8 (&data, &size);
3224 unknown = gst_asf_demux_get_uint8 (&data, &size);
3226 GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3228 /* Loop through the header's objects, processing those */
3229 for (i = 0; i < num_objects; ++i) {
3230 GST_INFO_OBJECT (demux, "reading header part %u", i);
3231 ret = gst_asf_demux_process_object (demux, &data, &size);
3232 if (ret != GST_FLOW_OK) {
3233 GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3242 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3243 ("short read parsing HEADER object"));
3244 return GST_FLOW_ERROR;
3248 static GstFlowReturn
3249 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3251 guint64 creation_time G_GNUC_UNUSED;
3252 guint64 file_size G_GNUC_UNUSED;
3253 guint64 send_time G_GNUC_UNUSED;
3254 guint64 packets_count, play_time, preroll;
3255 guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3257 if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3258 goto not_enough_data;
3260 gst_asf_demux_skip_bytes (16, &data, &size); /* skip GUID */
3261 file_size = gst_asf_demux_get_uint64 (&data, &size);
3262 creation_time = gst_asf_demux_get_uint64 (&data, &size);
3263 packets_count = gst_asf_demux_get_uint64 (&data, &size);
3264 play_time = gst_asf_demux_get_uint64 (&data, &size);
3265 send_time = gst_asf_demux_get_uint64 (&data, &size);
3266 preroll = gst_asf_demux_get_uint64 (&data, &size);
3267 flags = gst_asf_demux_get_uint32 (&data, &size);
3268 min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3269 max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3270 min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3272 demux->broadcast = ! !(flags & 0x01);
3273 demux->seekable = ! !(flags & 0x02);
3275 GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3276 GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3277 GST_DEBUG_OBJECT (demux, "flags::seekable = %d", demux->seekable);
3279 if (demux->broadcast) {
3280 /* these fields are invalid if the broadcast flag is set */
3285 if (min_pktsize != max_pktsize)
3286 goto non_fixed_packet_size;
3288 demux->packet_size = max_pktsize;
3290 /* FIXME: do we need send_time as well? what is it? */
3291 if ((play_time * 100) >= (preroll * GST_MSECOND))
3292 demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3294 demux->play_time = 0;
3296 demux->preroll = preroll * GST_MSECOND;
3298 /* initial latency */
3299 demux->latency = demux->preroll;
3301 if (demux->play_time == 0)
3302 demux->seekable = FALSE;
3304 GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3305 GST_TIME_ARGS (demux->play_time));
3306 GST_DEBUG_OBJECT (demux, "preroll %" GST_TIME_FORMAT,
3307 GST_TIME_ARGS (demux->preroll));
3309 if (demux->play_time > 0) {
3310 demux->segment.duration = demux->play_time;
3313 GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3315 GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3320 non_fixed_packet_size:
3322 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3323 ("packet size must be fixed"));
3324 return GST_FLOW_ERROR;
3328 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3329 ("short read parsing FILE object"));
3330 return GST_FLOW_ERROR;
3334 /* Content Description Object */
3335 static GstFlowReturn
3336 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3340 const gchar *gst_tag;
3345 GST_TAG_TITLE, 0, NULL}, {
3346 GST_TAG_ARTIST, 0, NULL}, {
3347 GST_TAG_COPYRIGHT, 0, NULL}, {
3348 GST_TAG_DESCRIPTION, 0, NULL}, {
3349 GST_TAG_COMMENT, 0, NULL}
3351 GstTagList *taglist;
3352 GValue value = { 0 };
3356 GST_INFO_OBJECT (demux, "object is a comment");
3358 if (size < (2 + 2 + 2 + 2 + 2))
3359 goto not_enough_data;
3361 tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3362 tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3363 tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3364 tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3365 tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3367 GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3368 "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3369 tags[2].val_length, tags[3].val_length, tags[4].val_length);
3371 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3372 if (size < tags[i].val_length)
3373 goto not_enough_data;
3375 /* might be just '/0', '/0'... */
3376 if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3377 /* convert to UTF-8 */
3378 tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3379 "UTF-8", "UTF-16LE", &in, &out, NULL);
3381 gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3384 /* parse metadata into taglist */
3385 taglist = gst_tag_list_new_empty ();
3386 g_value_init (&value, G_TYPE_STRING);
3387 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3388 if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3389 g_value_set_string (&value, tags[i].val_utf8);
3390 gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3391 tags[i].gst_tag, &value, NULL);
3394 g_value_unset (&value);
3396 gst_asf_demux_add_global_tags (demux, taglist);
3398 for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3399 g_free (tags[i].val_utf8);
3405 GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3406 "comment tag section %d, skipping comment object", i);
3407 for (i = 0; i < G_N_ELEMENTS (tags); i++)
3408 g_free (tags[i].val_utf8);
3409 return GST_FLOW_OK; /* not really fatal */
3413 static GstFlowReturn
3414 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3417 guint16 num_streams, i;
3421 goto not_enough_data;
3423 num_streams = gst_asf_demux_get_uint16 (&data, &size);
3425 GST_INFO ("object is a bitrate properties object with %u streams",
3428 if (size < (num_streams * (2 + 4)))
3429 goto not_enough_data;
3431 for (i = 0; i < num_streams; ++i) {
3435 stream_id = gst_asf_demux_get_uint16 (&data, &size);
3436 bitrate = gst_asf_demux_get_uint32 (&data, &size);
3438 if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3439 GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3440 stream = gst_asf_demux_get_stream (demux, stream_id);
3442 if (stream->pending_tags == NULL) {
3443 stream->pending_tags =
3444 gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
3447 GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3450 GST_WARNING ("stream id %u is too large", stream_id);
3458 GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3459 return GST_FLOW_OK; /* not really fatal */
3463 static GstFlowReturn
3464 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3467 GstFlowReturn ret = GST_FLOW_OK;
3470 /* Get the rest of the header's header */
3471 if (size < (16 + 2 + 4))
3472 goto not_enough_data;
3474 /* skip GUID and two other bytes */
3475 gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3476 hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3478 GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3480 /* FIXME: does data_size include the rest of the header that we have read? */
3481 if (hdr_size > size)
3482 goto not_enough_data;
3484 while (hdr_size > 0) {
3485 ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3486 if (ret != GST_FLOW_OK)
3494 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3495 ("short read parsing extended header object"));
3496 return GST_FLOW_ERROR;
3500 static GstFlowReturn
3501 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3507 goto not_enough_data;
3509 if (demux->languages) {
3510 GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3511 g_strfreev (demux->languages);
3512 demux->languages = NULL;
3513 demux->num_languages = 0;
3516 demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3517 GST_LOG ("%u languages:", demux->num_languages);
3519 demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3520 for (i = 0; i < demux->num_languages; ++i) {
3521 guint8 len, *lang_data = NULL;
3524 goto not_enough_data;
3525 len = gst_asf_demux_get_uint8 (&data, &size);
3526 if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3529 utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3532 /* truncate "en-us" etc. to just "en" */
3533 if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3536 GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3537 demux->languages[i] = utf8;
3540 goto not_enough_data;
3548 GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3549 g_free (demux->languages);
3550 demux->languages = NULL;
3551 return GST_FLOW_OK; /* not fatal */
3555 static GstFlowReturn
3556 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3559 GstClockTime interval;
3562 if (size < (16 + 8 + 4 + 4))
3563 goto not_enough_data;
3566 gst_asf_demux_skip_bytes (16, &data, &size);
3567 interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3568 gst_asf_demux_skip_bytes (4, &data, &size);
3569 count = gst_asf_demux_get_uint32 (&data, &size);
3571 demux->sidx_interval = interval;
3572 demux->sidx_num_entries = count;
3573 g_free (demux->sidx_entries);
3574 demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3576 for (i = 0; i < count; ++i) {
3577 if (G_UNLIKELY (size < 6)) {
3578 /* adjust for broken files, to avoid having entries at the end
3579 * of the parsed index that point to time=0. Resulting in seeking to
3580 * the end of the file leading back to the beginning */
3581 demux->sidx_num_entries -= (count - i);
3584 demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3585 demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3586 GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u count : %2d",
3587 GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3588 demux->sidx_entries[i].count);
3591 GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3598 GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3599 return GST_FLOW_OK; /* not fatal */
3603 static GstFlowReturn
3604 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3605 guint8 * data, guint64 size)
3611 if (size < 16 + 2 + (2 * 2))
3612 goto not_enough_data;
3614 gst_asf_demux_get_guid (&guid, &data, &size);
3615 num = gst_asf_demux_get_uint16 (&data, &size);
3618 GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3622 if (size < (num * sizeof (guint16)))
3623 goto not_enough_data;
3625 /* read mutually exclusive stream numbers */
3626 mes = g_new (guint8, num + 1);
3627 for (i = 0; i < num; ++i) {
3628 mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3629 GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3632 /* add terminator so we can easily get the count or know when to stop */
3633 mes[i] = (guint8) - 1;
3635 demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3642 GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3643 return GST_FLOW_OK; /* not absolutely fatal */
3648 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3650 return g_slist_find (demux->other_streams,
3651 GINT_TO_POINTER (stream_num)) == NULL;
3654 static GstFlowReturn
3655 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3658 AsfStreamExtProps esp;
3659 AsfStream *stream = NULL;
3660 AsfObject stream_obj;
3661 guint16 stream_name_count;
3662 guint16 num_payload_ext;
3664 guint8 *stream_obj_data = NULL;
3667 guint i, stream_num;
3670 obj_size = (guint) size;
3673 goto not_enough_data;
3676 esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3677 esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3678 esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3679 esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3680 esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3681 esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3682 esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3683 esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3684 esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3685 esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3686 stream_num = gst_asf_demux_get_uint16 (&data, &size);
3687 esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3688 esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3689 stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3690 num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3692 GST_INFO ("start_time = %" GST_TIME_FORMAT,
3693 GST_TIME_ARGS (esp.start_time));
3694 GST_INFO ("end_time = %" GST_TIME_FORMAT,
3695 GST_TIME_ARGS (esp.end_time));
3696 GST_INFO ("flags = %08x", esp.flags);
3697 GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3698 GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3699 GST_INFO ("stream number = %u", stream_num);
3700 GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3701 (esp.lang_idx < demux->num_languages) ?
3702 GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3703 GST_INFO ("stream name count = %u", stream_name_count);
3705 /* read stream names */
3706 for (i = 0; i < stream_name_count; ++i) {
3707 guint16 stream_lang_idx G_GNUC_UNUSED;
3708 gchar *stream_name = NULL;
3711 goto not_enough_data;
3712 stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3713 if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3714 goto not_enough_data;
3715 GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3716 g_free (stream_name); /* TODO: store names in struct */
3719 /* read payload extension systems stuff */
3720 GST_LOG ("payload extension systems count = %u", num_payload_ext);
3722 if (num_payload_ext > 0)
3723 esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3725 esp.payload_extensions = NULL;
3727 for (i = 0; i < num_payload_ext; ++i) {
3728 AsfPayloadExtension ext;
3730 guint32 sys_info_len;
3732 if (size < 16 + 2 + 4)
3733 goto not_enough_data;
3735 gst_asf_demux_get_guid (&ext_guid, &data, &size);
3736 ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3737 ext.len = gst_asf_demux_get_uint16 (&data, &size);
3739 sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3740 GST_LOG ("payload systems info len = %u", sys_info_len);
3741 if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3742 goto not_enough_data;
3744 esp.payload_extensions[i] = ext;
3747 GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3749 /* there might be an optional STREAM_INFO object here now; if not, we
3750 * should have parsed the corresponding stream info object already (since
3751 * we are parsing the extended stream properties objects delayed) */
3753 stream = gst_asf_demux_get_stream (demux, stream_num);
3757 /* get size of the stream object */
3758 if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3759 goto not_enough_data;
3761 if (stream_obj.id != ASF_OBJ_STREAM)
3762 goto expected_stream_object;
3764 if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3765 stream_obj.size > (10 * 1024 * 1024))
3766 goto not_enough_data;
3768 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3770 /* process this stream object later after all the other 'normal' ones
3771 * have been processed (since the others are more important/non-hidden) */
3772 len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3773 if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3774 goto not_enough_data;
3776 /* parse stream object */
3777 stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3778 g_free (stream_obj_data);
3783 stream->ext_props = esp;
3785 /* try to set the framerate */
3786 if (stream->is_video && stream->caps) {
3787 GValue framerate = { 0 };
3791 g_value_init (&framerate, GST_TYPE_FRACTION);
3793 num = GST_SECOND / 100;
3794 denom = esp.avg_time_per_frame;
3796 /* avoid division by 0, assume 25/1 framerate */
3797 denom = GST_SECOND / 2500;
3800 gst_value_set_fraction (&framerate, num, denom);
3802 stream->caps = gst_caps_make_writable (stream->caps);
3803 s = gst_caps_get_structure (stream->caps, 0);
3804 gst_structure_set_value (s, "framerate", &framerate);
3805 g_value_unset (&framerate);
3806 GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3807 num, denom, ((gdouble) num) / denom);
3810 /* add language info now if we have it */
3811 if (stream->ext_props.lang_idx < demux->num_languages) {
3812 if (stream->pending_tags == NULL)
3813 stream->pending_tags = gst_tag_list_new_empty ();
3814 GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3815 demux->languages[stream->ext_props.lang_idx]);
3816 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3817 GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3820 } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
3821 GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3829 GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3830 return GST_FLOW_OK; /* not absolutely fatal */
3832 expected_stream_object:
3834 GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3835 "object: expected embedded stream object, but got %s object instead!",
3836 gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3837 return GST_FLOW_OK; /* not absolutely fatal */
3841 static const gchar *
3842 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3846 nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3847 if (g_str_has_prefix (nick, "ASF_OBJ_"))
3848 nick += strlen ("ASF_OBJ_");
3850 if (demux->objpath == NULL) {
3851 demux->objpath = g_strdup (nick);
3855 newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3856 g_free (demux->objpath);
3857 demux->objpath = newpath;
3860 return (const gchar *) demux->objpath;
3864 gst_asf_demux_pop_obj (GstASFDemux * demux)
3868 if ((s = g_strrstr (demux->objpath, "/"))) {
3871 g_free (demux->objpath);
3872 demux->objpath = NULL;
3877 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3882 /* Parse the queued extended stream property objects and add the info
3883 * to the existing streams or add the new embedded streams, but without
3884 * activating them yet */
3885 GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3886 g_slist_length (demux->ext_stream_props));
3888 for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3889 GstBuffer *buf = GST_BUFFER (l->data);
3892 gst_buffer_map (buf, &map, GST_MAP_READ);
3894 GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3895 gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
3896 gst_buffer_unmap (buf, &map);
3897 gst_buffer_unref (buf);
3899 g_slist_free (demux->ext_stream_props);
3900 demux->ext_stream_props = NULL;
3905 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3909 for (i = 0; i < demux->num_streams; ++i) {
3914 stream = &demux->stream[i];
3916 GST_LOG_OBJECT (demux, "checking stream %2u", stream->id);
3918 if (stream->active) {
3919 GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3924 for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3927 /* check for each mutual exclusion whether it affects this stream */
3928 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3929 if (*mes == stream->id) {
3930 /* if yes, check if we've already added streams that are mutually
3931 * exclusive with the stream we're about to add */
3932 for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3933 for (j = 0; j < demux->num_streams; ++j) {
3934 /* if the broadcast flag is set, assume the hidden streams aren't
3935 * actually streamed and hide them (or playbin won't work right),
3936 * otherwise assume their data is available */
3937 if (demux->stream[j].id == *mes && demux->broadcast) {
3939 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3940 "mutually exclusive with already existing stream ID %d, "
3941 "hiding stream", stream->id, demux->stream[j].id);
3953 /* FIXME: we should do stream activation based on preroll data in
3954 * streaming mode too */
3955 if (demux->streaming && !is_hidden)
3956 gst_asf_demux_activate_stream (demux, stream);
3961 static GstFlowReturn
3962 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3965 GstFlowReturn ret = GST_FLOW_OK;
3967 guint64 obj_data_size;
3969 if (*p_size < ASF_OBJECT_HEADER_SIZE)
3970 return ASF_FLOW_NEED_MORE_DATA;
3972 asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3973 gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3975 obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3977 if (*p_size < obj_data_size)
3978 return ASF_FLOW_NEED_MORE_DATA;
3980 gst_asf_demux_push_obj (demux, obj.id);
3982 GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3985 case ASF_OBJ_STREAM:
3986 gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3990 ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3992 case ASF_OBJ_HEADER:
3993 ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3995 case ASF_OBJ_COMMENT:
3996 ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3999 ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4001 case ASF_OBJ_BITRATE_PROPS:
4003 gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4006 case ASF_OBJ_EXT_CONTENT_DESC:
4008 gst_asf_demux_process_ext_content_desc (demux, *p_data,
4011 case ASF_OBJ_METADATA_OBJECT:
4012 ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4014 case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4017 /* process these later, we might not have parsed the corresponding
4018 * stream object yet */
4019 GST_LOG ("%s: queued for later parsing", demux->objpath);
4020 buf = gst_buffer_new_and_alloc (obj_data_size);
4021 gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4022 demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4026 case ASF_OBJ_LANGUAGE_LIST:
4027 ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4029 case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4030 ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4033 case ASF_OBJ_SIMPLE_INDEX:
4034 ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4036 case ASF_OBJ_CONTENT_ENCRYPTION:
4037 case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4038 case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4039 case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4040 goto error_encrypted;
4041 case ASF_OBJ_CONCEAL_NONE:
4043 case ASF_OBJ_UNDEFINED:
4044 case ASF_OBJ_CODEC_COMMENT:
4046 case ASF_OBJ_PADDING:
4047 case ASF_OBJ_BITRATE_MUTEX:
4048 case ASF_OBJ_COMPATIBILITY:
4049 case ASF_OBJ_INDEX_PLACEHOLDER:
4050 case ASF_OBJ_INDEX_PARAMETERS:
4051 case ASF_OBJ_STREAM_PRIORITIZATION:
4052 case ASF_OBJ_SCRIPT_COMMAND:
4054 /* Unknown/unhandled object, skip it and hope for the best */
4055 GST_INFO ("%s: skipping object", demux->objpath);
4060 /* this can't fail, we checked the number of bytes available before */
4061 gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4063 GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4065 gst_asf_demux_pop_obj (demux);
4072 GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4073 return GST_FLOW_ERROR;
4078 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4079 GstBuffer ** p_buffer)
4081 GstBuffer *descrambled_buffer;
4082 GstBuffer *scrambled_buffer;
4083 GstBuffer *sub_buffer;
4090 /* descrambled_buffer is initialised in the first iteration */
4091 descrambled_buffer = NULL;
4092 scrambled_buffer = *p_buffer;
4094 if (gst_buffer_get_size (scrambled_buffer) <
4095 demux->ds_packet_size * demux->span)
4098 for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4099 offset += demux->ds_chunk_size) {
4100 off = offset / demux->ds_chunk_size;
4101 row = off / demux->span;
4102 col = off % demux->span;
4103 idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
4104 GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4105 col, off, demux->ds_chunk_size);
4106 GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4107 ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4108 demux->span, demux->ds_packet_size);
4109 GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4110 gst_buffer_get_size (scrambled_buffer));
4112 gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4113 idx * demux->ds_chunk_size, demux->ds_chunk_size);
4115 descrambled_buffer = sub_buffer;
4117 descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4121 GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4122 GST_BUFFER_TIMESTAMP (scrambled_buffer);
4123 GST_BUFFER_DURATION (descrambled_buffer) =
4124 GST_BUFFER_DURATION (scrambled_buffer);
4125 GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4126 GST_BUFFER_OFFSET_END (descrambled_buffer) =
4127 GST_BUFFER_OFFSET_END (scrambled_buffer);
4129 /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4131 gst_buffer_unref (scrambled_buffer);
4132 *p_buffer = descrambled_buffer;
4136 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4138 GstASFDemux *demux = GST_ASF_DEMUX (element);
4141 GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4143 for (i = 0; i < demux->num_streams; ++i) {
4144 gst_event_ref (event);
4145 if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4146 GST_OBJECT_CAST (element), event)) {
4147 gst_event_unref (event);
4152 gst_event_unref (event);
4156 /* takes ownership of the passed event */
4158 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4160 gboolean ret = TRUE;
4163 GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4164 GST_EVENT_TYPE_NAME (event));
4166 for (i = 0; i < demux->num_streams; ++i) {
4167 gst_event_ref (event);
4168 ret &= gst_pad_push_event (demux->stream[i].pad, event);
4170 gst_event_unref (event);
4175 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4179 gboolean res = FALSE;
4181 demux = GST_ASF_DEMUX (parent);
4183 GST_DEBUG ("handling %s query",
4184 gst_query_type_get_name (GST_QUERY_TYPE (query)));
4186 switch (GST_QUERY_TYPE (query)) {
4187 case GST_QUERY_DURATION:
4191 gst_query_parse_duration (query, &format, NULL);
4193 if (format != GST_FORMAT_TIME) {
4194 GST_LOG ("only support duration queries in TIME format");
4198 GST_OBJECT_LOCK (demux);
4200 if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4201 GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4202 GST_TIME_ARGS (demux->segment.duration));
4204 gst_query_set_duration (query, GST_FORMAT_TIME,
4205 demux->segment.duration);
4209 GST_LOG ("duration not known yet");
4212 GST_OBJECT_UNLOCK (demux);
4216 case GST_QUERY_POSITION:{
4219 gst_query_parse_position (query, &format, NULL);
4221 if (format != GST_FORMAT_TIME) {
4222 GST_LOG ("only support position queries in TIME format");
4226 GST_OBJECT_LOCK (demux);
4228 if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4229 GST_LOG ("returning position: %" GST_TIME_FORMAT,
4230 GST_TIME_ARGS (demux->segment.position));
4232 gst_query_set_position (query, GST_FORMAT_TIME,
4233 demux->segment.position);
4237 GST_LOG ("position not known yet");
4240 GST_OBJECT_UNLOCK (demux);
4244 case GST_QUERY_SEEKING:{
4247 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4248 if (format == GST_FORMAT_TIME) {
4251 GST_OBJECT_LOCK (demux);
4252 duration = demux->segment.duration;
4253 GST_OBJECT_UNLOCK (demux);
4255 if (!demux->streaming || !demux->seekable) {
4256 gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4263 /* try downstream first in TIME */
4264 res = gst_pad_query_default (pad, parent, query);
4266 gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4267 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4268 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4269 /* if no luck, maybe in BYTES */
4270 if (!seekable || fmt != GST_FORMAT_TIME) {
4273 q = gst_query_new_seeking (GST_FORMAT_BYTES);
4274 if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4275 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4276 GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4277 GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4278 if (fmt != GST_FORMAT_BYTES)
4281 gst_query_unref (q);
4282 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4288 GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4292 case GST_QUERY_LATENCY:
4295 GstClockTime min, max;
4297 /* preroll delay does not matter in non-live pipeline,
4298 * but we might end up in a live (rtsp) one ... */
4301 res = gst_pad_query_default (pad, parent, query);
4305 gst_query_parse_latency (query, &live, &min, &max);
4307 GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4308 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4309 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4311 GST_OBJECT_LOCK (demux);
4313 min += demux->latency;
4315 max += demux->latency;
4316 GST_OBJECT_UNLOCK (demux);
4318 gst_query_set_latency (query, live, min, max);
4321 case GST_QUERY_SEGMENT:
4326 format = demux->segment.format;
4329 gst_segment_to_stream_time (&demux->segment, format,
4330 demux->segment.start);
4331 if ((stop = demux->segment.stop) == -1)
4332 stop = demux->segment.duration;
4334 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4336 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4341 res = gst_pad_query_default (pad, parent, query);
4348 static GstStateChangeReturn
4349 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4351 GstASFDemux *demux = GST_ASF_DEMUX (element);
4352 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4354 switch (transition) {
4355 case GST_STATE_CHANGE_NULL_TO_READY:{
4356 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4357 demux->need_newsegment = TRUE;
4358 demux->segment_running = FALSE;
4359 demux->accurate = FALSE;
4360 demux->adapter = gst_adapter_new ();
4361 demux->metadata = gst_caps_new_empty ();
4362 demux->global_metadata = gst_structure_new_empty ("metadata");
4363 demux->data_size = 0;
4364 demux->data_offset = 0;
4365 demux->index_offset = 0;
4366 demux->base_offset = 0;
4373 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4374 if (ret == GST_STATE_CHANGE_FAILURE)
4377 switch (transition) {
4378 case GST_STATE_CHANGE_PAUSED_TO_READY:
4379 case GST_STATE_CHANGE_READY_TO_NULL:
4380 gst_asf_demux_reset (demux, FALSE);