]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugins-ugly0-10.git/blob - gst/asfdemux/gstasfdemux.c
gst/asfdemux/gstasfdemux.c: Remove duplicate and broken code for the streaming case...
[glsdk/gst-plugins-ugly0-10.git] / gst / asfdemux / gstasfdemux.c
1 /* GStreamer ASF/WMV/WMA demuxer
2  * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) 2006-2007 Tim-Philipp Müller <tim centricular net>
4  *
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.
9  *
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.
14  *
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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
21 /* TODO:
22  *
23  * - _loop():
24  *   stop if at end of segment if != end of file, ie. demux->segment.stop
25  *
26  * - _chain(): fix newsegment events for live streams where timestamps don't
27  *   start at zero (need sample files/streams for this)
28  *
29  * - fix packet parsing:
30  *   there's something wrong with timestamps for packets with keyframes,
31  *   and durations too.
32  */
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
38 #include <gst/gstutils.h>
39 #include <gst/riff/riff-media.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <stdlib.h>
42 #include <string.h>
44 #include "gstasfdemux.h"
45 #include "asfheaders.h"
46 #include "asfpacket.h"
48 static GstStaticPadTemplate gst_asf_demux_sink_template =
49 GST_STATIC_PAD_TEMPLATE ("sink",
50     GST_PAD_SINK,
51     GST_PAD_ALWAYS,
52     GST_STATIC_CAPS ("video/x-ms-asf")
53     );
55 static GstStaticPadTemplate audio_src_template =
56 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
57     GST_PAD_SRC,
58     GST_PAD_SOMETIMES,
59     GST_STATIC_CAPS_ANY);
61 static GstStaticPadTemplate video_src_template =
62 GST_STATIC_PAD_TEMPLATE ("video_%02d",
63     GST_PAD_SRC,
64     GST_PAD_SOMETIMES,
65     GST_STATIC_CAPS_ANY);
67 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
68 #define ASF_OBJECT_HEADER_SIZE  (16+8)
70 /* FIXME: get rid of this */
71 /* abuse this GstFlowReturn enum for internal usage */
72 #define ASF_FLOW_NEED_MORE_DATA  99
74 #define gst_asf_get_flow_name(flow)    \
75   (flow == ASF_FLOW_NEED_MORE_DATA) ?  \
76   "need-more-data" : gst_flow_get_name (flow)
78 GST_DEBUG_CATEGORY (asfdemux_dbg);
80 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
81     GstStateChange transition);
82 static gboolean gst_asf_demux_element_send_event (GstElement * element,
83     GstEvent * event);
84 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
85     GstEvent * event);
86 static gboolean gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query);
87 static const GstQueryType *gst_asf_demux_get_src_query_types (GstPad * pad);
88 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstBuffer * buf);
89 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstEvent * event);
90 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
91     guint8 ** p_data, guint64 * p_size);
92 static gboolean gst_asf_demux_activate (GstPad * sinkpad);
93 static gboolean gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active);
94 static gboolean gst_asf_demux_activate_pull (GstPad * sinkpad, gboolean active);
95 static void gst_asf_demux_loop (GstASFDemux * demux);
96 static void
97 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
98 static void gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux);
99 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
100 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
101 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
102 static gboolean
103 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
104 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
105     AsfStream * stream, GstBuffer ** p_buffer);
106 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
107     AsfStream * stream);
108 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
109     guint stream_num);
111 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
113 static void
114 gst_asf_demux_base_init (gpointer g_class)
116   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
117   static GstElementDetails gst_asf_demux_details = {
118     "ASF Demuxer",
119     "Codec/Demuxer",
120     "Demultiplexes ASF Streams",
121     "Owen Fraser-Green <owen@discobabe.net>"
122   };
124   gst_element_class_add_pad_template (element_class,
125       gst_static_pad_template_get (&audio_src_template));
126   gst_element_class_add_pad_template (element_class,
127       gst_static_pad_template_get (&video_src_template));
128   gst_element_class_add_pad_template (element_class,
129       gst_static_pad_template_get (&gst_asf_demux_sink_template));
131   gst_element_class_set_details (element_class, &gst_asf_demux_details);
134 static void
135 gst_asf_demux_class_init (GstASFDemuxClass * klass)
137   GstElementClass *gstelement_class;
139   gstelement_class = (GstElementClass *) klass;
141   gstelement_class->change_state =
142       GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
143   gstelement_class->send_event =
144       GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
147 static void
148 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
150   gst_buffer_replace (&stream->cache, NULL);
151   gst_buffer_replace (&stream->payload, NULL);
152   gst_caps_replace (&stream->caps, NULL);
153   if (stream->pending_tags) {
154     gst_tag_list_free (stream->pending_tags);
155     stream->pending_tags = NULL;
156   }
157   if (stream->pad) {
158     if (stream->active)
159       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
160     else
161       gst_object_unref (stream->pad);
162     stream->pad = NULL;
163   }
164   if (stream->payloads) {
165     g_array_free (stream->payloads, TRUE);
166     stream->payloads = NULL;
167   }
168   if (stream->ext_props.valid) {
169     g_free (stream->ext_props.payload_extensions);
170     stream->ext_props.payload_extensions = NULL;
171   }
174 static void
175 gst_asf_demux_reset (GstASFDemux * demux)
177   GST_LOG_OBJECT (demux, "resetting");
179   gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
180   demux->segment_running = FALSE;
181   if (demux->adapter) {
182     gst_adapter_clear (demux->adapter);
183     g_object_unref (demux->adapter);
184     demux->adapter = NULL;
185   }
186   if (demux->taglist) {
187     gst_tag_list_free (demux->taglist);
188     demux->taglist = NULL;
189   }
190   if (demux->metadata) {
191     gst_caps_unref (demux->metadata);
192     demux->metadata = NULL;
193   }
194   demux->state = GST_ASF_DEMUX_STATE_HEADER;
195   g_free (demux->objpath);
196   demux->objpath = NULL;
197   g_strfreev (demux->languages);
198   demux->languages = NULL;
199   demux->num_languages = 0;
200   g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
201       NULL);
202   g_slist_free (demux->ext_stream_props);
203   demux->ext_stream_props = NULL;
204   while (demux->num_streams > 0) {
205     gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
206     --demux->num_streams;
207   }
208   memset (demux->stream, 0, sizeof (demux->stream));
209   demux->num_audio_streams = 0;
210   demux->num_video_streams = 0;
211   demux->num_streams = 0;
212   demux->activated_streams = FALSE;
213   demux->first_ts = GST_CLOCK_TIME_NONE;
214   demux->state = GST_ASF_DEMUX_STATE_HEADER;
215   demux->seekable = FALSE;
216   demux->broadcast = FALSE;
217   demux->sidx_interval = 0;
218   demux->sidx_num_entries = 0;
219   g_free (demux->sidx_entries);
220   demux->sidx_entries = NULL;
223 static void
224 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
226   demux->sinkpad =
227       gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
228   gst_pad_set_chain_function (demux->sinkpad,
229       GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
230   gst_pad_set_event_function (demux->sinkpad,
231       GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
232   gst_pad_set_activate_function (demux->sinkpad,
233       GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
234   gst_pad_set_activatepull_function (demux->sinkpad,
235       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
236   gst_pad_set_activatepush_function (demux->sinkpad,
237       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
238   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
240   /* We should zero everything to be on the safe side */
241   demux->num_audio_streams = 0;
242   demux->num_video_streams = 0;
243   demux->num_streams = 0;
245   demux->taglist = NULL;
246   demux->first_ts = GST_CLOCK_TIME_NONE;
247   demux->state = GST_ASF_DEMUX_STATE_HEADER;
250 static gboolean
251 gst_asf_demux_activate (GstPad * sinkpad)
253   if (gst_pad_check_pull_range (sinkpad)) {
254     return gst_pad_activate_pull (sinkpad, TRUE);
255   } else {
256     return gst_pad_activate_push (sinkpad, TRUE);
257   }
260 static gboolean
261 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
263   GstASFDemux *demux;
265   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
267   demux->state = GST_ASF_DEMUX_STATE_HEADER;
268   demux->streaming = TRUE;
270   return TRUE;
273 static gboolean
274 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
276   GstASFDemux *demux;
278   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
280   if (active) {
281     demux->state = GST_ASF_DEMUX_STATE_HEADER;
282     demux->streaming = FALSE;
284     return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
285         demux);
286   } else {
287     return gst_pad_stop_task (pad);
288   }
292 static gboolean
293 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
295   GstASFDemux *demux;
296   gboolean ret = TRUE;
298   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
300   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
301   switch (GST_EVENT_TYPE (event)) {
302     case GST_EVENT_NEWSEGMENT:{
303       GstFormat newsegment_format;
304       gint64 newsegment_start;
306       gst_event_parse_new_segment (event, NULL, NULL, &newsegment_format,
307           &newsegment_start, NULL, NULL);
309       if (newsegment_format != GST_FORMAT_BYTES) {
310         GST_WARNING_OBJECT (demux, "newsegment format not BYTES, ignoring");
311         gst_event_unref (event);
312         break;
313       }
315       GST_OBJECT_LOCK (demux);
316       gst_asf_demux_reset_stream_state_after_discont (demux);
317       GST_OBJECT_UNLOCK (demux);
318       break;
319     }
320     case GST_EVENT_EOS:{
321       if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
322         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
323             (_("This stream contains no data.")),
324             ("got eos and didn't receive a complete header object"));
325         break;
326       }
327       GST_OBJECT_LOCK (demux);
328       gst_adapter_clear (demux->adapter);
329       GST_OBJECT_UNLOCK (demux);
330       gst_asf_demux_send_event_unlocked (demux, event);
331       break;
332     }
334     default:
335       ret = gst_pad_event_default (pad, event);
336       break;
337   }
339   gst_object_unref (demux);
340   return ret;
343 static gboolean
344 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
345     GstClockTime seek_time, GstClockTime * p_idx_time)
347   GstClockTime idx_time;
348   guint idx;
350   if (demux->sidx_num_entries == 0 || demux->sidx_interval == 0)
351     return FALSE;
353   idx = (guint) (seek_time / demux->sidx_interval);
355   /* FIXME: seek beyond end of file should result in immediate EOS from
356    * streaming thread instead of a failed seek */
357   if (idx >= demux->sidx_num_entries)
358     return FALSE;
360   *packet = demux->sidx_entries[idx];
362   /* so we get closer to the actual time of the packet ... actually, let's not
363    * do this, since we throw away superfluous payloads before the seek position
364    * anyway; this way, our key unit seek 'snap resolution' is a bit better
365    * (ie. same as index resolution) */
366   /*
367      while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
368      --idx;
369    */
371   idx_time = demux->sidx_interval * idx;
373   GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
374       GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
375       GST_TIME_ARGS (idx_time));
377   if (p_idx_time)
378     *p_idx_time = idx_time;
380   return TRUE;
383 static void
384 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
386   guint n;
388   demux->pts = 0;               //why?
389   gst_adapter_clear (demux->adapter);
391   for (n = 0; n < demux->num_streams; n++) {
392     gst_buffer_replace (&demux->stream[n].payload, NULL);
393     gst_buffer_replace (&demux->stream[n].cache, NULL);
394     demux->stream[n].frag_offset = 0;
395     demux->stream[n].last_pts = GST_CLOCK_TIME_NONE;
396     demux->stream[n].last_buffer_timestamp = GST_CLOCK_TIME_NONE;
397     demux->stream[n].sequence = 0;
398     demux->stream[n].discont = TRUE;
399     demux->stream[n].last_flow = GST_FLOW_OK;
401     while (demux->stream[n].payloads->len > 0) {
402       AsfPayload *payload;
403       guint last;
405       last = demux->stream[n].payloads->len - 1;
406       payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
407       gst_buffer_replace (&payload->buf, NULL);
408       g_array_remove_index (demux->stream[n].payloads, last);
409     }
410   }
413 static gboolean
414 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
416   GstClockTime idx_time;
417   GstSegment segment;
418   GstSeekFlags flags;
419   GstSeekType cur_type, stop_type;
420   GstFormat format;
421   gboolean only_need_update;
422   gboolean keyunit_sync;
423   gboolean accurate;
424   gboolean flush;
425   gdouble rate;
426   gint64 cur, stop;
427   gint64 seek_time;
428   guint packet;
430   if (demux->seekable == FALSE || demux->packet_size == 0 ||
431       demux->num_packets == 0 || demux->play_time == 0) {
432     GST_LOG_OBJECT (demux, "stream is not seekable");
433     return FALSE;
434   }
436   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
437       &stop_type, &stop);
439   if (format != GST_FORMAT_TIME) {
440     GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
441     return FALSE;
442   }
444   if (rate <= 0.0) {
445     GST_LOG_OBJECT (demux, "backward playback is not supported yet");
446     return FALSE;
447   }
449   flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
450   accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
451   keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
453   /* unlock the streaming thread */
454   if (flush) {
455     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
456     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
457   } else {
458     gst_pad_pause_task (demux->sinkpad);
459   }
461   /* grab the stream lock so that streaming cannot continue, for
462    * non flushing seeks when the element is in PAUSED this could block
463    * forever */
464   GST_PAD_STREAM_LOCK (demux->sinkpad);
466   /* we now can stop flushing, since we have the stream lock now */
467   gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
469   if (flush)
470     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
472   /* operating on copy of segment until we know the seek worked */
473   segment = demux->segment;
475   if (demux->segment_running && !flush) {
476     GstEvent *newseg;
478     /* create the segment event to close the current segment */
479     newseg = gst_event_new_new_segment (TRUE, segment.rate,
480         GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
482     gst_asf_demux_send_event_unlocked (demux, newseg);
483   }
485   gst_segment_set_seek (&segment, rate, format, flags, cur_type,
486       cur, stop_type, stop, &only_need_update);
488   GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
489       "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
491   seek_time = segment.start;
493   /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
494    * real start of data and segment_start to indexed time for key unit seek*/
495   if (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time, &idx_time)) {
496     /* First try to query our source to see if it can convert for us. This is
497        the case when our source is an mms stream, notice that in this case
498        gstmms will do a time based seek to get the byte offset, this is not a
499        problem as the seek to this offset needs to happen anway. */
500     gint64 offset;
501     GstFormat dest_format = GST_FORMAT_BYTES;
503     if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
504             &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
505       packet = (offset - demux->data_offset) / demux->packet_size;
506       GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
507           " to bytes query result: %lld, data_ofset: %llu, packet_size: %u,"
508           " resulting packet: %u\n", GST_TIME_ARGS (seek_time), offset,
509           demux->data_offset, demux->packet_size, packet);
510     } else {
511       /* Hackety hack, this sucks. We just seek to an earlier position
512        *  and let the sinks throw away the stuff before the segment start */
513       if (flush && (accurate || keyunit_sync)) {
514         seek_time -= 5 * GST_SECOND;
515         if (seek_time < 0)
516           seek_time = 0;
517       }
519       packet = (guint) gst_util_uint64_scale (demux->num_packets,
520           seek_time, demux->play_time);
522       if (packet > demux->num_packets)
523         packet = demux->num_packets;
524     }
525   } else {
526     if (keyunit_sync) {
527       GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
528           GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
529           GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
530       segment.start = idx_time;
531       segment.last_stop = idx_time;
532       segment.time = idx_time;
533     }
534   }
536   GST_DEBUG_OBJECT (demux, "seeking to packet %u", packet);
538   GST_OBJECT_LOCK (demux);
539   demux->segment = segment;
540   demux->packet = packet;
541   demux->need_newsegment = TRUE;
542   gst_asf_demux_reset_stream_state_after_discont (demux);
543   GST_OBJECT_UNLOCK (demux);
545   /* restart our task since it might have been stopped when we did the flush */
546   gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
547       demux);
549   /* streaming can continue now */
550   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
552   return TRUE;
555 static gboolean
556 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
558   GstASFDemux *demux;
559   gboolean ret;
561   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
563   switch (GST_EVENT_TYPE (event)) {
564     case GST_EVENT_SEEK:
565       GST_LOG_OBJECT (pad, "seek event");
566       ret = gst_asf_demux_handle_seek_event (demux, event);
567       gst_event_unref (event);
568       break;
569     case GST_EVENT_QOS:
570     case GST_EVENT_NAVIGATION:
571       /* just drop these two silently */
572       gst_event_unref (event);
573       ret = FALSE;
574       break;
575     default:
576       GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
577       ret = gst_pad_event_default (pad, event);
578       break;
579   }
581   gst_object_unref (demux);
582   return ret;
585 static inline guint32
586 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
588   guint32 ret;
590   ret = gst_asf_identify_guid (guids, guid);
592   GST_LOG ("%s  0x%08x-0x%08x-0x%08x-0x%08x",
593       gst_asf_get_guid_nick (guids, ret),
594       guid->v1, guid->v2, guid->v3, guid->v4);
596   return ret;
599 typedef struct
601   AsfObjectID id;
602   guint64 size;
603 } AsfObject;
605 static gboolean
606 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
607     guint data_len, AsfObject * object)
609   ASFGuid guid;
611   if (data_len < ASF_OBJECT_HEADER_SIZE)
612     return FALSE;
614   guid.v1 = GST_READ_UINT32_LE (data + 0);
615   guid.v2 = GST_READ_UINT32_LE (data + 4);
616   guid.v3 = GST_READ_UINT32_LE (data + 8);
617   guid.v4 = GST_READ_UINT32_LE (data + 12);
619   object->size = GST_READ_UINT64_LE (data + 16);
621   /* FIXME: make asf_demux_identify_object_guid() */
622   object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
623   if (object->id == ASF_OBJ_UNDEFINED) {
624     GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
625         guid.v1, guid.v2, guid.v3, guid.v4);
626   }
628   return TRUE;
631 static GstFlowReturn
632 gst_asf_demux_chain_headers (GstASFDemux * demux)
634   GstFlowReturn flow;
635   AsfObject obj;
636   guint8 *header_data, *data = NULL;
637   guint64 header_size;
639   data = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
640   if (data == NULL)
641     goto need_more_data;
643   asf_demux_peek_object (demux, data, ASF_OBJECT_HEADER_SIZE, &obj);
644   if (obj.id != ASF_OBJ_HEADER)
645     goto wrong_type;
647   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
649   /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
650   if (gst_adapter_available (demux->adapter) < obj.size + 50)
651     goto need_more_data;
653   data = gst_adapter_take (demux->adapter, obj.size + 50);
655   header_data = data;
656   header_size = obj.size;
657   flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
658   if (flow != GST_FLOW_OK)
659     goto parse_failed;
661   /* calculate where the packet data starts */
662   demux->data_offset = obj.size + 50;
664   /* now parse the beginning of the ASF_OBJ_DATA object */
665   if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
666     goto wrong_type;
668   if (demux->num_streams == 0)
669     goto no_streams;
671   /* FIXME: remove when we activate streams after internal preroll in
672    * streaming mode as well */
673   GST_LOG_OBJECT (demux, "signalling no more pads");
674   gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
676   g_free (data);
677   return GST_FLOW_OK;
679 /* NON-FATAL */
680 need_more_data:
681   {
682     GST_LOG_OBJECT (demux, "not enough data in adapter yet");
683     return GST_FLOW_OK;
684   }
686 /* ERRORS */
687 wrong_type:
688   {
689     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
690         ("This doesn't seem to be an ASF file"));
691     g_free (data);
692     return GST_FLOW_ERROR;
693   }
694 no_streams:
695 parse_failed:
696   {
697     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
698         ("header parsing failed, or no streams found, flow = %s",
699             gst_flow_get_name (flow)));
700     g_free (data);
701     return GST_FLOW_ERROR;
702   }
705 static GstFlowReturn
706 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux)
708   int i;
709   GST_DEBUG_OBJECT (demux, "Aggregating");
711   for (i = 0; i < demux->num_streams; i++) {
712     if (demux->stream[i].active) {
713       GstFlowReturn flowret = demux->stream[i].last_flow;
714       GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
715           gst_flow_get_name (flowret));
716       if (flowret != GST_FLOW_NOT_LINKED)
717         return flowret;
718     }
719   }
721   /* If we got here, then all our active streams are not linked */
722   return GST_FLOW_NOT_LINKED;
725 static gboolean
726 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
727     GstBuffer ** p_buf, GstFlowReturn * p_flow)
729   GstFlowReturn flow;
731   GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
732       offset, size);
734   flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
736   if (p_flow)
737     *p_flow = flow;
739   if (flow != GST_FLOW_OK) {
740     GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
741         "+%u", gst_flow_get_name (flow), offset, size);
742     *p_buf = NULL;
743     return FALSE;
744   }
746   g_assert (*p_buf != NULL);
748   if (GST_BUFFER_SIZE (*p_buf) < size) {
749     GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
750         "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
751     gst_buffer_unref (*p_buf);
752     if (p_flow)
753       *p_flow = GST_FLOW_UNEXPECTED;
754     *p_buf = NULL;
755     return FALSE;
756   }
758   return TRUE;
761 static void
762 gst_asf_demux_pull_indices (GstASFDemux * demux)
764   GstBuffer *buf = NULL;
765   guint64 offset;
766   guint num_read = 0;
768   offset = demux->index_offset;
770   if (offset == 0) {
771     GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
772     return;
773   }
775   while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
776     GstFlowReturn flow;
777     AsfObject obj;
779     asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj);
780     gst_buffer_replace (&buf, NULL);
782     /* check for sanity */
783     if (obj.size > (5 * 1024 * 1024)) {
784       GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
785       break;
786     }
788     if (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf, NULL))
789       break;
791     GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
792         ", size %u", offset, (guint) obj.size);
794     offset += obj.size;         /* increase before _process_object changes it */
796     flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
797     gst_buffer_replace (&buf, NULL);
799     if (flow != GST_FLOW_OK)
800       break;
802     ++num_read;
803   }
804   GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
807 static gboolean
808 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
810   AsfObject obj;
812   asf_demux_peek_object (demux, data, 50, &obj);
813   if (obj.id != ASF_OBJ_DATA) {
814     GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
815     return FALSE;
816   }
818   demux->state = GST_ASF_DEMUX_STATE_DATA;
820   if (!demux->broadcast && obj.size > 50) {
821     demux->data_size = obj.size - 50;
822     /* CHECKME: for at least one file this is off by +158 bytes?! */
823     demux->index_offset = demux->data_offset + demux->data_size;
824   } else {
825     demux->data_size = 0;
826     demux->index_offset = 0;
827   }
829   demux->packet = 0;
831   if (!demux->broadcast) {
832     /* skip object header (24 bytes) and file GUID (16 bytes) */
833     demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
834   } else {
835     demux->num_packets = 0;
836   }
838   if (demux->num_packets == 0)
839     demux->seekable = FALSE;
841   /* fallback in the unlikely case that headers are inconsistent, can't hurt */
842   if (demux->data_size == 0 && demux->num_packets > 0) {
843     demux->data_size = demux->num_packets * demux->packet_size;
844     demux->index_offset = demux->data_offset + demux->data_size;
845   }
847   /* process pending stream objects and create pads for those */
848   gst_asf_demux_process_queued_extended_stream_objects (demux);
849   gst_asf_demux_activate_ext_props_streams (demux);
851   GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
852       "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
853       ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
854       demux->data_offset, demux->data_size, demux->index_offset);
856   return TRUE;
859 static gboolean
860 gst_asf_demux_pull_headers (GstASFDemux * demux)
862   GstFlowReturn flow;
863   AsfObject obj;
864   GstBuffer *buf = NULL;
865   guint64 size;
867   GST_LOG_OBJECT (demux, "reading headers");
869   /* pull HEADER object header, so we know its size */
870   if (!gst_asf_demux_pull_data (demux, 0, 16 + 8, &buf, NULL))
871     goto read_failed;
873   asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj);
874   gst_buffer_replace (&buf, NULL);
876   if (obj.id != ASF_OBJ_HEADER)
877     goto wrong_type;
879   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
881   /* pull HEADER object */
882   if (!gst_asf_demux_pull_data (demux, 0, obj.size, &buf, NULL))
883     goto read_failed;
885   size = obj.size;              /* don't want obj.size changed */
886   flow = gst_asf_demux_process_object (demux, &buf->data, &size);
887   gst_buffer_replace (&buf, NULL);
889   if (flow != GST_FLOW_OK) {
890     GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
891     goto parse_failed;
892   }
894   /* calculate where the packet data starts */
895   demux->data_offset = obj.size + 50;
897   /* now pull beginning of DATA object before packet data */
898   if (!gst_asf_demux_pull_data (demux, obj.size, 50, &buf, NULL))
899     goto read_failed;
901   if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
902     goto wrong_type;
904   if (demux->num_streams == 0)
905     goto no_streams;
907   gst_buffer_replace (&buf, NULL);
908   return TRUE;
910 /* ERRORS */
911 wrong_type:
912   {
913     gst_buffer_replace (&buf, NULL);
914     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
915         ("This doesn't seem to be an ASF file"));
916     return FALSE;
917   }
918 no_streams:
919 read_failed:
920 parse_failed:
921   {
922     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
923     return FALSE;
924   }
927 static gboolean
928 all_streams_prerolled (GstASFDemux * demux)
930   GstClockTime preroll_time;
931   guint i, num_no_data = 0;
933   preroll_time = demux->preroll * GST_MSECOND;
935   /* returns TRUE as long as there isn't a stream which (a) has data queued
936    * and (b) the timestamp of last piece of data queued is < demux->preroll
937    * AND there is at least one other stream with data queued */
938   for (i = 0; i < demux->num_streams; ++i) {
939     AsfPayload *last_payload;
940     AsfStream *stream;
941     guint last_idx;
943     stream = &demux->stream[i];
944     if (stream->payloads->len == 0) {
945       ++num_no_data;
946       GST_LOG_OBJECT (stream->pad, "no data queued");
947       continue;
948     }
950     last_idx = stream->payloads->len - 1;
951     last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
953     GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
954         GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
955         GST_TIME_ARGS (preroll_time));
956     if (last_payload->ts <= preroll_time) {
957       GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
958       return FALSE;
959     }
960   }
962   if (num_no_data == demux->num_streams)
963     return FALSE;
965   return TRUE;
968 #if 0
969 static gboolean
970 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
971     AsfStream * stream)
973   GSList *l;
975   for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
976     guint8 *mes;
978     /* check for each mutual exclusion group whether it affects this stream */
979     for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
980       if (*mes == stream->id) {
981         /* we are in this group; let's check if we've already activated streams
982          * that are in the same group (and hence mutually exclusive to this
983          * one) */
984         for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
985           guint i;
987           for (i = 0; i < demux->num_streams; ++i) {
988             if (demux->stream[i].id == *mes && demux->stream[i].active) {
989               GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
990                   "to already active stream with ID %d", stream->id,
991                   demux->stream[i].id);
992               return TRUE;
993             }
994           }
995         }
996         /* we can only be in this group once, let's break out and move on to
997          * the next mutual exclusion group */
998         break;
999       }
1000     }
1001   }
1003   return FALSE;
1005 #endif
1007 static gboolean
1008 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1010   guint i;
1012   if (demux->activated_streams)
1013     return TRUE;
1015   if (!all_streams_prerolled (demux) && !force) {
1016     GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1017     return FALSE;
1018   }
1020   for (i = 0; i < demux->num_streams; ++i) {
1021     AsfStream *stream = &demux->stream[i];
1023     if (stream->payloads->len > 0) {
1024       /* we don't check mutual exclusion stuff here; either we have data for
1025        * a stream, then we active it, or we don't, then we'll ignore it */
1026       GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1027       gst_asf_demux_activate_stream (demux, stream);
1028     } else {
1029       GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1030     }
1031   }
1033   demux->activated_streams = TRUE;
1034   GST_LOG_OBJECT (demux, "signalling no more pads");
1035   gst_element_no_more_pads (GST_ELEMENT (demux));
1036   return TRUE;
1039 /* returns the stream that has a complete payload with the lowest timestamp
1040  * queued, or NULL (we push things by timestamp because during the internal
1041  * prerolling we might accumulate more data then the external queues can take,
1042  * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1043 static AsfStream *
1044 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1046   AsfPayload *best_payload = NULL;
1047   AsfStream *best_stream = NULL;
1048   guint i;
1050   for (i = 0; i < demux->num_streams; ++i) {
1051     AsfStream *stream;
1053     stream = &demux->stream[i];
1055     /* Don't push any data until we have at least one payload that falls within
1056      * the current segment. This way we can remove out-of-segment payloads that
1057      * don't need to be decoded after a seek, sending only data from the
1058      * keyframe directly before our segment start */
1059     if (stream->payloads->len > 0) {
1060       AsfPayload *payload;
1061       guint last_idx;
1063       last_idx = stream->payloads->len - 1;
1064       payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1065       if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1066           payload->ts < demux->segment.start) {
1067         GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1068             GST_TIME_FORMAT " which is before our segment start %"
1069             GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1070             GST_TIME_ARGS (demux->segment.start));
1071         continue;
1072       }
1073     }
1075     /* Now see if there's a complete payload queued for this stream */
1076     if (stream->payloads->len > 0) {
1077       AsfPayload *payload;
1079       payload = &g_array_index (stream->payloads, AsfPayload, 0);
1080       if (!gst_asf_payload_is_complete (payload))
1081         continue;
1083       /* ... and whether its timestamp is lower than the current best */
1084       if (best_stream == NULL || best_payload->ts > payload->ts) {
1085         best_stream = stream;
1086         best_payload = payload;
1087       }
1088     }
1089   }
1091   return best_stream;
1094 static GstFlowReturn
1095 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1097   AsfStream *stream;
1099   if (G_UNLIKELY (!demux->activated_streams)) {
1100     if (!gst_asf_demux_check_activate_streams (demux, force))
1101       return GST_FLOW_OK;
1102     /* streams are now activated */
1103   }
1105   /* do we need to send a newsegment event */
1106   if (demux->need_newsegment) {
1107     if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1108         demux->segment.duration > 0) {
1109       demux->segment.stop = demux->segment.duration;
1110     }
1112     GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1113         &demux->segment);
1115     /* note: we fix up all timestamps to start from 0, so this should be ok */
1116     gst_asf_demux_send_event_unlocked (demux,
1117         gst_event_new_new_segment (FALSE, demux->segment.rate,
1118             GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1119             demux->segment.start));
1121     demux->need_newsegment = FALSE;
1122     demux->segment_running = TRUE;
1123   }
1125   while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1126     AsfPayload *payload;
1128     payload = &g_array_index (stream->payloads, AsfPayload, 0);
1130     /* Do we have tags pending for this stream? */
1131     if (stream->pending_tags) {
1132       GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1133       gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1134           stream->pending_tags);
1135       stream->pending_tags = NULL;
1136     }
1138     /* We have the whole packet now so we should push the packet to
1139      * the src pad now. First though we should check if we need to do
1140      * descrambling */
1141     if (demux->span > 1) {
1142       gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1143     }
1145     payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1147     if (!payload->keyframe) {
1148       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1149     }
1151     if (stream->discont) {
1152       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1153       stream->discont = FALSE;
1154     }
1156     gst_buffer_set_caps (payload->buf, stream->caps);
1158     GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts;
1159     GST_BUFFER_DURATION (payload->buf) = payload->duration;
1161     /* FIXME: we should really set durations on buffers if we can */
1163     GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1164         ", dur=%" GST_TIME_FORMAT " size=%u",
1165         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1166         GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1167         GST_BUFFER_SIZE (payload->buf));
1169     stream->last_flow = gst_pad_push (stream->pad, payload->buf);
1170     payload->buf = NULL;
1171     g_array_remove_index (stream->payloads, 0);
1172   }
1174   return gst_asf_demux_aggregate_flow_return (demux);
1177 static void
1178 gst_asf_demux_loop (GstASFDemux * demux)
1180   GstFlowReturn flow;
1181   GstBuffer *buf = NULL;
1182   guint64 off;
1184   if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
1185     if (!gst_asf_demux_pull_headers (demux)) {
1186       flow = GST_FLOW_ERROR;
1187       goto pause;
1188     }
1190     gst_asf_demux_pull_indices (demux);
1191   }
1193   g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1195   if (demux->num_packets != 0 && demux->packet >= demux->num_packets)
1196     goto eos;
1198   GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1199       (guint) demux->num_packets);
1201   off = demux->data_offset + (demux->packet * demux->packet_size);
1203   if (!gst_asf_demux_pull_data (demux, off, demux->packet_size, &buf, &flow)) {
1204     GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1205     if (flow == GST_FLOW_UNEXPECTED)
1206       goto eos;
1207     else if (!GST_FLOW_IS_FATAL (flow)) {
1208       GST_DEBUG_OBJECT (demux, "Not fatal");
1209       goto pause;
1210     } else
1211       goto read_failed;
1212   }
1214   /* FIXME: maybe we should just skip broken packets and error out only
1215    * after a few broken packets in a row? */
1216   if (!gst_asf_demux_parse_packet (demux, buf))
1217     goto parse_error;
1219   gst_buffer_unref (buf);
1221   flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1223   ++demux->packet;
1225   if (demux->num_packets > 0 && demux->packet >= demux->num_packets) {
1226     GST_LOG_OBJECT (demux, "reached EOS");
1227     goto eos;
1228   }
1230   if (flow != GST_FLOW_OK) {
1231     GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1232     goto pause;
1233   }
1235   /* check if we're at the end of the configured segment */
1236   /* FIXME: check if segment end reached etc. */
1238   return;
1240 eos:
1241   {
1242     /* if we haven't activated our streams yet, this might be because we have
1243      * less data queued than required for preroll; force stream activation and
1244      * send any pending payloads before sending EOS */
1245     if (!demux->activated_streams)
1246       flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
1248     if (GST_FLOW_IS_FATAL (flow) || flow == GST_FLOW_NOT_LINKED) {
1249       GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1250       goto pause;
1251     }
1253     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1254       gint64 stop;
1256       /* for segment playback we need to post when (in stream time)
1257        * we stopped, this is either stop (when set) or the duration. */
1258       if ((stop = demux->segment.stop) == -1)
1259         stop = demux->segment.duration;
1261       GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1262       gst_element_post_message (GST_ELEMENT_CAST (demux),
1263           gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1264               stop));
1265     } else {
1266       /* normal playback, send EOS to all linked pads */
1267       GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1268       gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1269     }
1270     /* ... and fall through to pause */
1271     GST_DEBUG_OBJECT (demux, "EOSing");
1272   }
1273 pause:
1274   {
1275     GST_DEBUG_OBJECT (demux, "pausing task");
1276     demux->segment_running = FALSE;
1277     gst_pad_pause_task (demux->sinkpad);
1279     /* For the error cases (not EOS) */
1280     if (GST_FLOW_IS_FATAL (flow) || flow == GST_FLOW_NOT_LINKED) {
1281       /* Post an error. Hopefully something else already has, but if not... */
1282       GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1283           (_("Internal data stream error.")),
1284           ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1285     }
1286     return;
1287   }
1289 /* ERRORS */
1290 read_failed:
1291   {
1292     GST_DEBUG_OBJECT (demux, "Read failed, doh");
1293     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1294     flow = GST_FLOW_UNEXPECTED;
1295     goto pause;
1296   }
1297 parse_error:
1298   {
1299     gst_buffer_unref (buf);
1300     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1301         ("Error parsing ASF packet %u", (guint) demux->packet));
1302     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1303     flow = GST_FLOW_ERROR;
1304     goto pause;
1305   }
1308 static GstFlowReturn
1309 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1311   GstFlowReturn ret = GST_FLOW_OK;
1312   GstASFDemux *demux;
1314   demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1316   GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT,
1317       GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf));
1319   if (GST_BUFFER_IS_DISCONT (buf))
1320     gst_asf_demux_reset_stream_state_after_discont (demux);
1322   gst_adapter_push (demux->adapter, buf);
1324   switch (demux->state) {
1325     case GST_ASF_DEMUX_STATE_HEADER:{
1326       ret = gst_asf_demux_chain_headers (demux);
1327       if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1328         break;
1329       /* otherwise fall through */
1330     }
1331     case GST_ASF_DEMUX_STATE_DATA:
1332     {
1333       guint64 data_size;
1335       data_size = demux->packet_size;
1337       while (gst_adapter_available (demux->adapter) >= data_size) {
1338         GstBuffer *buf;
1340         buf = gst_adapter_take_buffer (demux->adapter, data_size);
1342         /* FIXME: maybe we should just skip broken packets and error out only
1343          * after a few broken packets in a row? */
1344         if (!gst_asf_demux_parse_packet (demux, buf)) {
1345           GST_WARNING_OBJECT (demux, "Parse error");
1346         }
1348         gst_buffer_unref (buf);
1350         ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1352         ++demux->packet;
1353       }
1354       break;
1355     }
1356     default:
1357       g_assert_not_reached ();
1358   }
1360   if (ret != GST_FLOW_OK)
1361     GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1363   return ret;
1366 static inline gboolean
1367 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1369   if (*p_size < num_bytes)
1370     return FALSE;
1372   *p_data += num_bytes;
1373   *p_size -= num_bytes;
1374   return TRUE;
1377 static inline guint8
1378 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1380   guint8 ret;
1382   g_assert (*p_size >= 1);
1383   ret = GST_READ_UINT8 (*p_data);
1384   *p_data += sizeof (guint8);
1385   *p_size -= sizeof (guint8);
1386   return ret;
1389 static inline guint16
1390 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1392   guint16 ret;
1394   g_assert (*p_size >= 2);
1395   ret = GST_READ_UINT16_LE (*p_data);
1396   *p_data += sizeof (guint16);
1397   *p_size -= sizeof (guint16);
1398   return ret;
1401 static inline guint32
1402 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1404   guint32 ret;
1406   g_assert (*p_size >= 4);
1407   ret = GST_READ_UINT32_LE (*p_data);
1408   *p_data += sizeof (guint32);
1409   *p_size -= sizeof (guint32);
1410   return ret;
1413 static inline guint64
1414 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1416   guint64 ret;
1418   g_assert (*p_size >= 8);
1419   ret = GST_READ_UINT64_LE (*p_data);
1420   *p_data += sizeof (guint64);
1421   *p_size -= sizeof (guint64);
1422   return ret;
1425 static inline guint32
1426 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1428   switch (type) {
1429     case 0:
1430       return 0;
1432     case 1:
1433       g_assert (*p_size >= 1);
1434       return gst_asf_demux_get_uint8 (p_data, p_size);
1436     case 2:
1437       g_assert (*p_size >= 2);
1438       return gst_asf_demux_get_uint16 (p_data, p_size);
1440     case 3:
1441       g_assert (*p_size >= 4);
1442       return gst_asf_demux_get_uint32 (p_data, p_size);
1444     default:
1445       break;
1446   }
1448   g_assert_not_reached ();
1451 static gboolean
1452 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1453     guint8 ** p_data, guint64 * p_size)
1455   *p_buf = NULL;
1457   if (*p_size < num_bytes_to_read)
1458     return FALSE;
1460   *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1461   memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1462   *p_data += num_bytes_to_read;
1463   *p_size -= num_bytes_to_read;
1464   return TRUE;
1467 static gboolean
1468 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1469     guint8 ** p_data, guint64 * p_size)
1471   *p_buf = NULL;
1473   if (*p_size < num_bytes_to_read)
1474     return FALSE;
1476   *p_buf = g_memdup (*p_data, num_bytes_to_read);
1477   *p_data += num_bytes_to_read;
1478   *p_size -= num_bytes_to_read;
1479   return TRUE;
1482 static gboolean
1483 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1484     guint8 ** p_data, guint64 * p_size)
1486   guint16 s_length;
1487   guint8 *s;
1489   *p_str = NULL;
1491   if (*p_size < 2)
1492     return FALSE;
1494   s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1496   if (p_strlen)
1497     *p_strlen = s_length;
1499   if (s_length == 0) {
1500     GST_WARNING ("zero-length string");
1501     *p_str = g_strdup ("");
1502     return TRUE;
1503   }
1505   if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1506     return FALSE;
1508   g_assert (s != NULL);
1510   /* just because They don't exist doesn't
1511    * mean They are not out to get you ... */
1512   if (s[s_length - 1] != '\0') {
1513     s = g_realloc (s, s_length + 1);
1514     s[s_length] = '\0';
1515   }
1517   *p_str = (gchar *) s;
1518   return TRUE;
1522 static void
1523 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
1525   g_assert (*p_size >= 4 * sizeof (guint32));
1527   guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
1528   guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
1529   guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
1530   guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
1533 static gboolean
1534 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
1535     guint64 * p_size)
1537   if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
1538     return FALSE;
1540   /* WAVEFORMATEX Structure */
1541   audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
1542   audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
1543   audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1544   audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1545   audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
1546   audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
1547   /* Codec specific data size */
1548   audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
1549   return TRUE;
1552 static gboolean
1553 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
1554     guint64 * p_size)
1556   if (*p_size < (4 + 4 + 1 + 2))
1557     return FALSE;
1559   video->width = gst_asf_demux_get_uint32 (p_data, p_size);
1560   video->height = gst_asf_demux_get_uint32 (p_data, p_size);
1561   video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
1562   video->size = gst_asf_demux_get_uint16 (p_data, p_size);
1563   return TRUE;
1566 static gboolean
1567 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
1568     guint8 ** p_data, guint64 * p_size)
1570   if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
1571     return FALSE;
1573   fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
1574   fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
1575   fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
1576   fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
1577   fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
1578   fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
1579   fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
1580   fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1581   fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1582   fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1583   fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1584   return TRUE;
1587 AsfStream *
1588 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
1590   guint i;
1592   for (i = 0; i < demux->num_streams; i++) {
1593     if (demux->stream[i].id == id)
1594       return &demux->stream[i];
1595   }
1597   GST_WARNING ("Segment found for undefined stream: (%d)", id);
1598   return NULL;
1601 static void
1602 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
1603     GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
1605   AsfStream *stream;
1607   gst_pad_use_fixed_caps (src_pad);
1608   gst_pad_set_caps (src_pad, caps);
1610   gst_pad_set_event_function (src_pad,
1611       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
1612   gst_pad_set_query_type_function (src_pad,
1613       GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
1614   gst_pad_set_query_function (src_pad,
1615       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
1617   stream = &demux->stream[demux->num_streams];
1618   stream->caps = caps;
1619   stream->pad = src_pad;
1620   stream->id = id;
1621   stream->frag_offset = 0;
1622   stream->sequence = 0;
1623   stream->delay = 0;
1624   stream->first_pts = GST_CLOCK_TIME_NONE;
1625   stream->last_pts = GST_CLOCK_TIME_NONE;
1626   stream->last_buffer_timestamp = GST_CLOCK_TIME_NONE;
1627   stream->fps_known = !is_video;        /* bit hacky for audio */
1628   stream->is_video = is_video;
1629   stream->pending_tags = tags;
1630   stream->discont = TRUE;
1632   stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
1634   GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
1635       GST_PAD_NAME (src_pad), demux->num_streams, caps);
1637   ++demux->num_streams;
1639   stream->active = FALSE;
1642 static void
1643 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
1644     asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
1646   GstTagList *tags = NULL;
1647   GstBuffer *extradata = NULL;
1648   GstPad *src_pad;
1649   GstCaps *caps;
1650   guint16 size_left = 0;
1651   gchar *codec_name = NULL;
1652   gchar *name = NULL;
1654   size_left = audio->size;
1656   /* Create the audio pad */
1657   name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
1659   src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
1660   g_free (name);
1662   /* Swallow up any left over data and set up the 
1663    * standard properties from the header info */
1664   if (size_left) {
1665     GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
1666         "codec specific data", size_left);
1668     g_assert (size_left <= *p_size);
1669     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
1670   }
1672   /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
1673    * additional two bytes indicating extradata. */
1674   caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
1675       (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
1677   if (caps == NULL) {
1678     caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
1679         G_TYPE_INT, (gint) audio->codec_tag, NULL);
1680   }
1682   /* Informing about that audio format we just added */
1683   if (codec_name) {
1684     tags = gst_tag_list_new ();
1685     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
1686         codec_name, NULL);
1687     g_free (codec_name);
1688   }
1690   if (extradata)
1691     gst_buffer_unref (extradata);
1693   GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
1694       GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
1695       audio->codec_tag, tags);
1697   ++demux->num_audio_streams;
1699   gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
1702 static void
1703 gst_asf_demux_add_video_stream (GstASFDemux * demux,
1704     asf_stream_video_format * video, guint16 id,
1705     guint8 ** p_data, guint64 * p_size)
1707   GstTagList *tags = NULL;
1708   GstBuffer *extradata = NULL;
1709   GstPad *src_pad;
1710   GstCaps *caps;
1711   gchar *name = NULL;
1712   gchar *codec_name = NULL;
1713   gint size_left = video->size - 40;
1715   /* Create the video pad */
1716   name = g_strdup_printf ("video_%02d", demux->num_video_streams);
1717   src_pad = gst_pad_new_from_static_template (&video_src_template, name);
1718   g_free (name);
1720   /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
1721   if (size_left) {
1722     GST_LOG ("Video header has %d bytes of codec specific data", size_left);
1723     g_assert (size_left <= *p_size);
1724     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
1725   }
1727   GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
1729   /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
1730   caps = gst_riff_create_video_caps (video->tag, NULL,
1731       (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
1733   if (caps == NULL) {
1734     caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
1735         GST_TYPE_FOURCC, video->tag, NULL);
1736   } else {
1737     GstStructure *s;
1738     gint ax, ay;
1740     s = gst_asf_demux_get_metadata_for_stream (demux, id);
1741     if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
1742         gst_structure_get_int (s, "AspectRatioY", &ay)) {
1743       /* only copy sane values */
1744       if (ax > 0 && ay > 0) {
1745         gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1746             ax, ay, NULL);
1747       }
1748     }
1749     /* remove the framerate we will guess and add it later */
1750     s = gst_caps_get_structure (caps, 0);
1751     gst_structure_remove_field (s, "framerate");
1752   }
1754   /* add fourcc format to caps, some proprietary decoders seem to need it */
1755   gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
1757   if (codec_name) {
1758     tags = gst_tag_list_new ();
1759     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
1760         codec_name, NULL);
1761     g_free (codec_name);
1762   }
1764   if (extradata)
1765     gst_buffer_unref (extradata);
1767   GST_INFO ("Adding video stream %u codec %" GST_FOURCC_FORMAT " (0x%08x)",
1768       demux->num_video_streams, GST_FOURCC_ARGS (video->tag), video->tag);
1770   ++demux->num_video_streams;
1772   gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
1775 static void
1776 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
1778   if (!stream->active) {
1779     GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
1780         GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
1781     gst_pad_set_active (stream->pad, TRUE);
1782     gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
1783     stream->active = TRUE;
1784   }
1787 static AsfStream *
1788 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
1789     guint64 size)
1791   AsfCorrectionType correction_type;
1792   AsfStreamType stream_type;
1793   GstClockTime time_offset;
1794   gboolean is_encrypted;
1795   guint16 stream_id;
1796   guint16 flags;
1797   ASFGuid guid;
1798   guint stream_specific_size;
1799   guint type_specific_size;
1800   guint unknown;
1802   /* Get the rest of the header's header */
1803   if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
1804     goto not_enough_data;
1806   gst_asf_demux_get_guid (&guid, &data, &size);
1807   stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
1809   gst_asf_demux_get_guid (&guid, &data, &size);
1810   correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
1812   time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
1814   type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
1815   stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
1817   flags = gst_asf_demux_get_uint16 (&data, &size);
1818   stream_id = flags & 0x7f;
1819   is_encrypted = !!((flags & 0x8000) << 15);
1820   unknown = gst_asf_demux_get_uint32 (&data, &size);
1822   GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
1823       stream_id, GST_TIME_ARGS (time_offset));
1825   switch (stream_type) {
1826     case ASF_STREAM_AUDIO:{
1827       asf_stream_audio audio_object;
1829       if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
1830         goto not_enough_data;
1832       GST_INFO ("Object is an audio stream with %u bytes of additional data",
1833           audio_object.size);
1835       gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
1836           &data, &size);
1838       switch (correction_type) {
1839         case ASF_CORRECTION_ON:{
1840           guint span, packet_size, chunk_size, data_size, silence_data;
1842           GST_INFO ("Using error correction");
1844           if (size < (1 + 2 + 2 + 2 + 1))
1845             goto not_enough_data;
1847           span = gst_asf_demux_get_uint8 (&data, &size);
1848           packet_size = gst_asf_demux_get_uint16 (&data, &size);
1849           chunk_size = gst_asf_demux_get_uint16 (&data, &size);
1850           data_size = gst_asf_demux_get_uint16 (&data, &size);
1851           silence_data = gst_asf_demux_get_uint8 (&data, &size);
1853           /* FIXME: shouldn't this be per-stream? */
1854           demux->span = span;
1856           GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
1857               packet_size, chunk_size, data_size, span, silence_data);
1859           if (demux->span > 1) {
1860             if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
1861               /* Disable descrambling */
1862               demux->span = 0;
1863             } else {
1864               /* FIXME: this else branch was added for
1865                * weird_al_yankovic - the saga begins.asf */
1866               demux->ds_packet_size = packet_size;
1867               demux->ds_chunk_size = chunk_size;
1868             }
1869           } else {
1870             /* Descambling is enabled */
1871             demux->ds_packet_size = packet_size;
1872             demux->ds_chunk_size = chunk_size;
1873           }
1874 #if 0
1875           /* Now skip the rest of the silence data */
1876           if (data_size > 1)
1877             gst_bytestream_flush (demux->bs, data_size - 1);
1878 #else
1879           /* FIXME: CHECKME. And why -1? */
1880           if (data_size > 1) {
1881             if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
1882               goto not_enough_data;
1883             }
1884           }
1885 #endif
1886           break;
1887         }
1888         case ASF_CORRECTION_OFF:{
1889           GST_INFO ("Error correction off");
1890           if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
1891             goto not_enough_data;
1892           break;
1893         }
1894         default:
1895           GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1896               ("Audio stream using unknown error correction"));
1897           return NULL;
1898       }
1900       break;
1901     }
1903     case ASF_STREAM_VIDEO:{
1904       asf_stream_video_format video_format_object;
1905       asf_stream_video video_object;
1906       guint16 vsize;
1908       if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
1909         goto not_enough_data;
1911       vsize = video_object.size - 40;   /* Byte order gets offset by single byte */
1913       GST_INFO ("object is a video stream with %u bytes of "
1914           "additional data", vsize);
1916       if (!gst_asf_demux_get_stream_video_format (&video_format_object,
1917               &data, &size)) {
1918         goto not_enough_data;
1919       }
1921       gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
1922           &data, &size);
1924       break;
1925     }
1927     default:
1928       GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
1929           stream_id);
1930       break;
1931   }
1933   return gst_asf_demux_get_stream (demux, stream_id);
1935 not_enough_data:
1936   {
1937     GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
1938     /* we'll error out later if we found no streams */
1939     return NULL;
1940   }
1943 static const gchar *
1944 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf16le,
1945     gsize name_len)
1947   const struct
1948   {
1949     const gchar *asf_name;
1950     const gchar *gst_name;
1951   } tags[] = {
1952     {
1953     "WM/Genre", GST_TAG_GENRE}, {
1954     "WM/AlbumTitle", GST_TAG_ALBUM}, {
1955     "WM/AlbumArtist", GST_TAG_ARTIST}, {
1956     "WM/Track", GST_TAG_TRACK_NUMBER}, {
1957     "WM/Year", GST_TAG_DATE}
1958     /* { "WM/Composer", GST_TAG_COMPOSER } */
1959   };
1960   gchar *name_utf8;
1961   gsize in, out;
1962   guint i;
1964   /* convert name to UTF-8 */
1965   name_utf8 = g_convert (name_utf16le, name_len, "UTF-8", "UTF-16LE", &in,
1966       &out, NULL);
1968   if (name_utf8 == NULL) {
1969     GST_WARNING ("Failed to convert name to UTF8, skipping");
1970     return NULL;
1971   }
1973   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
1974     if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
1975       GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
1976       g_free (name_utf8);
1977       return tags[i].gst_name;
1978     }
1979   }
1981   GST_LOG ("unhandled tagname '%s'", name_utf8);
1982   g_free (name_utf8);
1983   return NULL;
1986 /* gst_asf_demux_commit_taglist() takes ownership of taglist! */
1987 static void
1988 gst_asf_demux_commit_taglist (GstASFDemux * demux, GstTagList * taglist)
1990   GST_DEBUG ("Committing tags: %" GST_PTR_FORMAT, taglist);
1992   gst_element_found_tags (GST_ELEMENT (demux), gst_tag_list_copy (taglist));
1994   /* save internally */
1995   if (!demux->taglist)
1996     demux->taglist = taglist;
1997   else {
1998     GstTagList *t;
2000     t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2001     gst_tag_list_free (demux->taglist);
2002     gst_tag_list_free (taglist);
2003     demux->taglist = t;
2004   }
2007 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING  0
2008 #define ASF_DEMUX_DATA_TYPE_DWORD           3
2010 /* Extended Content Description Object */
2011 static GstFlowReturn
2012 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2013     guint64 size)
2015   /* Other known (and unused) 'text/unicode' metadata available :
2016    *
2017    *   WM/Lyrics =
2018    *   WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2019    *   WMFSDKVersion = 9.00.00.2980
2020    *   WMFSDKNeeded = 0.0.0.0000
2021    *   WM/UniqueFileIdentifier = AMGa_id=R    15334;AMGp_id=P     5149;AMGt_id=T  2324984
2022    *   WM/Publisher = 4AD
2023    *   WM/Provider = AMG
2024    *   WM/ProviderRating = 8
2025    *   WM/ProviderStyle = Rock (similar to WM/Genre)
2026    *   WM/GenreID (similar to WM/Genre)
2027    *   WM/TrackNumber (same as WM/Track but as a string)
2028    *
2029    * Other known (and unused) 'non-text' metadata available :
2030    *
2031    *   WM/EncodingTime
2032    *   WM/MCDI
2033    *   IsVBR
2034    *
2035    * We might want to read WM/TrackNumber and use atoi() if we don't have
2036    * WM/Track
2037    */
2039   GstTagList *taglist;
2040   guint16 blockcount, i;
2042   GST_INFO_OBJECT (demux, "object is an extended content description");
2044   taglist = gst_tag_list_new ();
2046   /* Content Descriptor Count */
2047   if (size < 2)
2048     goto not_enough_data;
2050   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2052   for (i = 1; i <= blockcount; ++i) {
2053     const gchar *gst_tag_name;
2054     guint16 datatype;
2055     guint16 value_len;
2056     guint16 name_len;
2057     GValue tag_value = { 0, };
2058     gsize in, out;
2059     gchar *name;
2060     gchar *value;
2062     /* Descriptor */
2063     if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2064       goto not_enough_data;
2066     if (size < 2) {
2067       g_free (name);
2068       goto not_enough_data;
2069     }
2070     /* Descriptor Value Data Type */
2071     datatype = gst_asf_demux_get_uint16 (&data, &size);
2073     /* Descriptor Value (not really a string, but same thing reading-wise) */
2074     if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2075       g_free (name);
2076       goto not_enough_data;
2077     }
2079     gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name, name_len);
2080     if (gst_tag_name != NULL) {
2081       switch (datatype) {
2082         case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2083           gchar *value_utf8;
2085           value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2086               &in, &out, NULL);
2088           /* get rid of tags with empty value */
2089           if (value_utf8 != NULL && *value_utf8 != '\0') {
2090             value_utf8[out] = '\0';
2092             if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2093               guint year = atoi (value_utf8);
2095               if (year > 0) {
2096                 GDate *date = g_date_new_dmy (1, 1, year);
2098                 g_value_init (&tag_value, GST_TYPE_DATE);
2099                 gst_value_set_date (&tag_value, date);
2100                 g_date_free (date);
2101               }
2102             } else {
2103               GType tag_type;
2105               /* convert tag from string to other type if required */
2106               tag_type = gst_tag_get_type (gst_tag_name);
2107               g_value_init (&tag_value, tag_type);
2108               if (!gst_value_deserialize (&tag_value, value_utf8)) {
2109                 GValue from_val = { 0, };
2111                 g_value_init (&from_val, G_TYPE_STRING);
2112                 g_value_set_string (&from_val, value_utf8);
2113                 if (!g_value_transform (&from_val, &tag_value)) {
2114                   GST_WARNING_OBJECT (demux,
2115                       "Could not transform string tag to " "%s tag type %s",
2116                       gst_tag_name, g_type_name (tag_type));
2117                   g_value_unset (&tag_value);
2118                 }
2119                 g_value_unset (&from_val);
2120               }
2121             }
2122           } else if (value_utf8 == NULL) {
2123             GST_WARNING ("Failed to convert string value to UTF8, skipping");
2124           } else {
2125             GST_DEBUG ("Skipping empty string value for %s", gst_tag_name);
2126           }
2127           g_free (value_utf8);
2128           break;
2129         }
2130         case ASF_DEMUX_DATA_TYPE_DWORD:{
2131           /* this is the track number */
2132           g_value_init (&tag_value, G_TYPE_UINT);
2133           g_value_set_uint (&tag_value, (guint) GST_READ_UINT32_LE (value));
2134           break;
2135         }
2136         default:{
2137           GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2138           break;
2139         }
2140       }
2142       if (G_IS_VALUE (&tag_value)) {
2143         gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2144             gst_tag_name, &tag_value, NULL);
2146         g_value_unset (&tag_value);
2147       }
2148     }
2150     g_free (name);
2151     g_free (value);
2152   }
2154   if (gst_structure_n_fields (GST_STRUCTURE (taglist)) > 0) {
2155     gst_asf_demux_commit_taglist (demux, taglist);
2156   } else {
2157     gst_tag_list_free (taglist);
2158   }
2160   return GST_FLOW_OK;
2162   /* Errors */
2163 not_enough_data:
2164   {
2165     GST_WARNING ("Unexpected end of data parsing ext content desc object");
2166     gst_tag_list_free (taglist);
2167     return GST_FLOW_OK;         /* not really fatal */
2168   }
2171 static GstStructure *
2172 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2174   gchar sname[32];
2175   guint i;
2177   g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2179   for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2180     GstStructure *s;
2182     s = gst_caps_get_structure (demux->metadata, i);
2183     if (gst_structure_has_name (s, sname))
2184       return s;
2185   }
2187   gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2189   /* try lookup again; demux->metadata took ownership of the structure, so we
2190    * can't really make any assumptions about what happened to it, so we can't
2191    * just return it directly after appending it */
2192   return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2195 static GstFlowReturn
2196 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2197     guint64 size)
2199   guint16 blockcount, i;
2201   GST_INFO_OBJECT (demux, "object is a metadata object");
2203   /* Content Descriptor Count */
2204   if (size < 2)
2205     goto not_enough_data;
2207   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2209   for (i = 0; i < blockcount; ++i) {
2210     GstStructure *s;
2211     guint16 lang_idx, stream_num, name_len, data_type;
2212     guint32 data_len, ival;
2213     gchar *name_utf8;
2215     if (size < (2 + 2 + 2 + 2 + 4))
2216       goto not_enough_data;
2218     lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2219     stream_num = gst_asf_demux_get_uint16 (&data, &size);
2220     name_len = gst_asf_demux_get_uint16 (&data, &size);
2221     data_type = gst_asf_demux_get_uint16 (&data, &size);
2222     data_len = gst_asf_demux_get_uint32 (&data, &size);
2224     if (size < name_len + data_len)
2225       goto not_enough_data;
2227     /* convert name to UTF-8 */
2228     name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2229         NULL, NULL, NULL);
2230     gst_asf_demux_skip_bytes (name_len, &data, &size);
2232     if (name_utf8 == NULL) {
2233       GST_WARNING ("Failed to convert value name to UTF8, skipping");
2234       gst_asf_demux_skip_bytes (data_len, &data, &size);
2235       continue;
2236     }
2238     if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2239       gst_asf_demux_skip_bytes (data_len, &data, &size);
2240       continue;
2241     }
2243     /* read DWORD */
2244     if (size < 4)
2245       goto not_enough_data;
2247     ival = gst_asf_demux_get_uint32 (&data, &size);
2249     /* skip anything else there may be, just in case */
2250     gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2252     s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2253     gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2254     g_free (name_utf8);
2255   }
2257   GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2258   return GST_FLOW_OK;
2260   /* Errors */
2261 not_enough_data:
2262   {
2263     GST_WARNING ("Unexpected end of data parsing metadata object");
2264     return GST_FLOW_OK;         /* not really fatal */
2265   }
2268 static GstFlowReturn
2269 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2271   GstFlowReturn ret = GST_FLOW_OK;
2272   guint32 i, num_objects;
2273   guint8 unknown;
2275   /* Get the rest of the header's header */
2276   if (size < (4 + 1 + 1))
2277     goto not_enough_data;
2279   num_objects = gst_asf_demux_get_uint32 (&data, &size);
2280   unknown = gst_asf_demux_get_uint8 (&data, &size);
2281   unknown = gst_asf_demux_get_uint8 (&data, &size);
2283   GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2285   /* Loop through the header's objects, processing those */
2286   for (i = 0; i < num_objects; ++i) {
2287     GST_INFO_OBJECT (demux, "reading header part %u", i);
2288     ret = gst_asf_demux_process_object (demux, &data, &size);
2289     if (ret != GST_FLOW_OK) {
2290       GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2291       break;
2292     }
2293   }
2295   return ret;
2297 not_enough_data:
2298   {
2299     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2300         ("short read parsing HEADER object"));
2301     return GST_FLOW_ERROR;
2302   }
2305 static GstFlowReturn
2306 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2308   guint64 file_size, creation_time, packets_count;
2309   guint64 play_time, send_time, preroll;
2310   guint32 flags, min_pktsize, max_pktsize, min_bitrate;
2312   if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2313     goto not_enough_data;
2315   gst_asf_demux_skip_bytes (16, &data, &size);  /* skip GUID */
2316   file_size = gst_asf_demux_get_uint64 (&data, &size);
2317   creation_time = gst_asf_demux_get_uint64 (&data, &size);
2318   packets_count = gst_asf_demux_get_uint64 (&data, &size);
2319   play_time = gst_asf_demux_get_uint64 (&data, &size);
2320   send_time = gst_asf_demux_get_uint64 (&data, &size);
2321   preroll = gst_asf_demux_get_uint64 (&data, &size);
2322   flags = gst_asf_demux_get_uint32 (&data, &size);
2323   min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2324   max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2325   min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2327   demux->broadcast = !!(flags & 0x01);
2328   demux->seekable = !!(flags & 0x02);
2330   GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2331   GST_DEBUG_OBJECT (demux, "flags::seekable  = %d", demux->seekable);
2333   if (demux->broadcast) {
2334     /* these fields are invalid if the broadcast flag is set */
2335     play_time = 0;
2336     file_size = 0;
2337   }
2339   if (min_pktsize != max_pktsize)
2340     goto non_fixed_packet_size;
2342   demux->packet_size = max_pktsize;
2344   /* FIXME: do we need send_time as well? what is it? */
2345   if ((play_time * 100) >= (preroll * GST_MSECOND))
2346     demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2347   else
2348     demux->play_time = 0;
2350   demux->preroll = preroll;     /* FIXME: make GstClockTime */
2352   if (demux->play_time == 0)
2353     demux->seekable = FALSE;
2355   GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2356       GST_TIME_ARGS (demux->play_time));
2357   GST_DEBUG_OBJECT (demux, "preroll   %" GST_TIME_FORMAT,
2358       GST_TIME_ARGS (demux->preroll * GST_MSECOND));
2360   if (demux->play_time > 0) {
2361     gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2362         demux->play_time);
2363   }
2365   GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2366       packets_count);
2367   GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2369   return GST_FLOW_OK;
2371 /* ERRORS */
2372 non_fixed_packet_size:
2373   {
2374     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2375         ("packet size must be fixed"));
2376     return GST_FLOW_ERROR;
2377   }
2378 not_enough_data:
2379   {
2380     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2381         ("short read parsing FILE object"));
2382     return GST_FLOW_ERROR;
2383   }
2386 /* Content Description Object */
2387 static GstFlowReturn
2388 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2390   struct
2391   {
2392     const gchar *gst_tag;
2393     guint16 val_length;
2394     gchar *val_utf8;
2395   } tags[5] = {
2396     {
2397     GST_TAG_TITLE, 0, NULL}, {
2398     GST_TAG_ARTIST, 0, NULL}, {
2399     GST_TAG_COPYRIGHT, 0, NULL}, {
2400     GST_TAG_DESCRIPTION, 0, NULL}, {
2401     GST_TAG_COMMENT, 0, NULL}
2402   };
2403   GstTagList *taglist;
2404   GValue value = { 0 };
2405   gsize in, out;
2406   gint i = -1;
2408   GST_INFO_OBJECT (demux, "object is a comment");
2410   if (size < (2 + 2 + 2 + 2 + 2))
2411     goto not_enough_data;
2413   tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
2414   tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
2415   tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
2416   tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
2417   tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
2419   GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
2420       "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
2421       tags[2].val_length, tags[3].val_length, tags[4].val_length);
2423   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2424     if (size < tags[i].val_length)
2425       goto not_enough_data;
2427     /* might be just '/0', '/0'... */
2428     if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
2429       /* convert to UTF-8 */
2430       tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
2431           "UTF-8", "UTF-16LE", &in, &out, NULL);
2432     }
2433     gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
2434   }
2436   /* parse metadata into taglist */
2437   taglist = gst_tag_list_new ();
2438   g_value_init (&value, G_TYPE_STRING);
2439   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2440     if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
2441       g_value_set_string (&value, tags[i].val_utf8);
2442       gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2443           tags[i].gst_tag, &value, NULL);
2444     }
2445   }
2446   g_value_unset (&value);
2448   if (gst_structure_n_fields (GST_STRUCTURE (taglist)) > 0) {
2449     gst_asf_demux_commit_taglist (demux, taglist);
2450   } else {
2451     gst_tag_list_free (taglist);
2452   }
2454   for (i = 0; i < G_N_ELEMENTS (tags); ++i)
2455     g_free (tags[i].val_utf8);
2457   return GST_FLOW_OK;
2459 not_enough_data:
2460   {
2461     GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
2462         "comment tag section %d, skipping comment object", i);
2463     for (i = 0; i < G_N_ELEMENTS (tags); i++)
2464       g_free (tags[i].val_utf8);
2465     return GST_FLOW_OK;         /* not really fatal */
2466   }
2469 static GstFlowReturn
2470 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
2471     guint64 size)
2473   guint16 num_streams, i;
2475   if (size < 2)
2476     goto not_enough_data;
2478   num_streams = gst_asf_demux_get_uint16 (&data, &size);
2480   GST_INFO ("object is a bitrate properties object with %u streams",
2481       num_streams);
2483   if (size < (num_streams * (2 + 4)))
2484     goto not_enough_data;
2486   for (i = 0; i < num_streams; ++i) {
2487     guint32 bitrate;
2488     guint16 stream_id;
2490     stream_id = gst_asf_demux_get_uint16 (&data, &size);
2491     bitrate = gst_asf_demux_get_uint32 (&data, &size);
2493     if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
2494       demux->bitrate[stream_id] = bitrate;
2495       GST_DEBUG ("bitrate[%u] = %u", stream_id, bitrate);
2496     } else {
2497       GST_WARNING ("stream id %u is too large", stream_id);
2498     }
2499   }
2501   return GST_FLOW_OK;
2503 not_enough_data:
2504   {
2505     GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
2506     return GST_FLOW_OK;         /* not really fatal */
2507   }
2510 static GstFlowReturn
2511 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
2512     guint64 size)
2514   GstFlowReturn ret = GST_FLOW_OK;
2515   guint64 hdr_size;
2517   /* Get the rest of the header's header */
2518   if (size < (16 + 2 + 4))
2519     goto not_enough_data;
2521   /* skip GUID and two other bytes */
2522   gst_asf_demux_skip_bytes (16 + 2, &data, &size);
2523   hdr_size = gst_asf_demux_get_uint32 (&data, &size);
2525   GST_INFO ("extended header object with a size of %u bytes", (guint) size);
2527   /* FIXME: does data_size include the rest of the header that we have read? */
2528   if (hdr_size > size)
2529     goto not_enough_data;
2531   while (hdr_size > 0) {
2532     ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
2533     if (ret != GST_FLOW_OK)
2534       break;
2535   }
2537   return ret;
2539 not_enough_data:
2540   {
2541     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2542         ("short read parsing extended header object"));
2543     return GST_FLOW_ERROR;
2544   }
2547 static GstFlowReturn
2548 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
2549     guint64 size)
2551   guint i;
2553   if (size < 2)
2554     goto not_enough_data;
2556   if (demux->languages) {
2557     GST_WARNING ("More than one LANGUAGE_LIST object in stream");
2558     g_strfreev (demux->languages);
2559     demux->languages = NULL;
2560     demux->num_languages = 0;
2561   }
2563   demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
2564   GST_LOG ("%u languages:", demux->num_languages);
2566   demux->languages = g_new0 (gchar *, demux->num_languages + 1);
2567   for (i = 0; i < demux->num_languages; ++i) {
2568     guint8 len, *lang_data = NULL;
2570     if (size < 1)
2571       goto not_enough_data;
2572     len = gst_asf_demux_get_uint8 (&data, &size);
2573     if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
2574       gchar *utf8;
2576       utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
2577           NULL, NULL);
2579       /* truncate "en-us" etc. to just "en" */
2580       if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
2581         utf8[2] = '\0';
2582       }
2583       GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
2584       demux->languages[i] = utf8;
2585       g_free (lang_data);
2586     } else {
2587       goto not_enough_data;
2588     }
2589   }
2591   return GST_FLOW_OK;
2593 not_enough_data:
2594   {
2595     GST_WARNING_OBJECT (demux, "short read parsing language list object!");
2596     g_free (demux->languages);
2597     demux->languages = NULL;
2598     return GST_FLOW_OK;         /* not fatal */
2599   }
2602 static GstFlowReturn
2603 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
2604     guint64 size)
2606   GstClockTime interval;
2607   guint32 x, count, i;
2609   if (size < (16 + 8 + 4 + 4))
2610     goto not_enough_data;
2612   /* skip file id */
2613   gst_asf_demux_skip_bytes (16, &data, &size);
2614   interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
2615   x = gst_asf_demux_get_uint32 (&data, &size);
2616   count = gst_asf_demux_get_uint32 (&data, &size);
2617   if (count > 0) {
2618     demux->sidx_interval = interval;
2619     demux->sidx_num_entries = count;
2620     g_free (demux->sidx_entries);
2621     demux->sidx_entries = g_new0 (guint32, count);
2623     for (i = 0; i < count && size > (4 + 2); ++i) {
2624       demux->sidx_entries[i] = gst_asf_demux_get_uint32 (&data, &size);
2625       x = (guint32) gst_asf_demux_get_uint16 (&data, &size);
2626       GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u",
2627           GST_TIME_ARGS (i * interval), demux->sidx_entries[i]);
2628     }
2629   } else {
2630     GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
2631   }
2633   return GST_FLOW_OK;
2635 not_enough_data:
2636   {
2637     GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
2638     return GST_FLOW_OK;         /* not fatal */
2639   }
2642 static GstFlowReturn
2643 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
2644     guint8 * data, guint64 size)
2646   ASFGuid guid;
2647   guint16 num, i;
2648   guint8 *mes;
2650   if (size < 16 + 2 + (2 * 2))
2651     goto not_enough_data;
2653   gst_asf_demux_get_guid (&guid, &data, &size);
2654   num = gst_asf_demux_get_uint16 (&data, &size);
2656   if (num < 2) {
2657     GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
2658     return GST_FLOW_OK;
2659   }
2661   if (size < (num * sizeof (guint16)))
2662     goto not_enough_data;
2664   /* read mutually exclusive stream numbers */
2665   mes = g_new (guint8, num + 1);
2666   for (i = 0; i < num; ++i) {
2667     mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
2668     GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
2669   }
2671   /* add terminator so we can easily get the count or know when to stop */
2672   mes[i] = (guint8) - 1;
2674   demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
2676   return GST_FLOW_OK;
2678   /* Errors */
2679 not_enough_data:
2680   {
2681     GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
2682     return GST_FLOW_OK;         /* not absolutely fatal */
2683   }
2686 static GstFlowReturn
2687 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
2688     guint64 size)
2690   AsfStreamExtProps esp;
2691   AsfStream *stream = NULL;
2692   AsfObject stream_obj;
2693   guint16 stream_name_count;
2694   guint16 num_payload_ext;
2695   guint64 len;
2696   guint8 *stream_obj_data = NULL;
2697   guint8 *data_start;
2698   guint obj_size;
2699   guint i, stream_num;
2701   data_start = data;
2702   obj_size = (guint) size;
2704   if (size < 64)
2705     goto not_enough_data;
2707   esp.valid = TRUE;
2708   esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
2709   esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
2710   esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2711   esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
2712   esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
2713   esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
2714   esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
2715   esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
2716   esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
2717   esp.flags = gst_asf_demux_get_uint32 (&data, &size);
2718   stream_num = gst_asf_demux_get_uint16 (&data, &size);
2719   esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2720   esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
2721   stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
2722   num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
2724   GST_INFO ("start_time             = %" GST_TIME_FORMAT,
2725       GST_TIME_ARGS (esp.start_time));
2726   GST_INFO ("end_time               = %" GST_TIME_FORMAT,
2727       GST_TIME_ARGS (esp.end_time));
2728   GST_INFO ("flags                  = %08x", esp.flags);
2729   GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
2730       GST_TIME_ARGS (esp.avg_time_per_frame * 100));
2731   GST_INFO ("stream number          = %u", stream_num);
2732   GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
2733       (esp.lang_idx < demux->num_languages) ?
2734       GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
2735   GST_INFO ("stream name count      = %u", stream_name_count);
2737   /* read stream names */
2738   for (i = 0; i < stream_name_count; ++i) {
2739     guint16 stream_lang_idx;
2740     gchar *stream_name = NULL;
2742     if (size < 2)
2743       goto not_enough_data;
2744     stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2745     if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
2746       goto not_enough_data;
2747     GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
2748     g_free (stream_name);       /* TODO: store names in struct */
2749   }
2751   /* read payload extension systems stuff */
2752   GST_LOG ("payload extension systems count = %u", num_payload_ext);
2754   if (num_payload_ext > 0)
2755     esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
2756   else
2757     esp.payload_extensions = NULL;
2759   for (i = 0; i < num_payload_ext; ++i) {
2760     AsfPayloadExtension ext;
2761     ASFGuid ext_guid;
2762     guint32 sys_info_len;
2764     if (size < 16 + 2 + 4)
2765       goto not_enough_data;
2767     gst_asf_demux_get_guid (&ext_guid, &data, &size);
2768     ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
2769     ext.len = gst_asf_demux_get_uint16 (&data, &size);
2771     sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
2772     GST_LOG ("payload systems info len = %u", sys_info_len);
2773     if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
2774       goto not_enough_data;
2776     esp.payload_extensions[i] = ext;
2777   }
2779   GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
2781   /* there might be an optional STREAM_INFO object here now; if not, we
2782    * should have parsed the corresponding stream info object already (since
2783    * we are parsing the extended stream properties objects delayed) */
2784   if (size == 0) {
2785     stream = gst_asf_demux_get_stream (demux, stream_num);
2786     goto done;
2787   }
2789   /* get size of the stream object */
2790   if (!asf_demux_peek_object (demux, data, size, &stream_obj))
2791     goto not_enough_data;
2793   if (stream_obj.id != ASF_OBJ_STREAM)
2794     goto expected_stream_object;
2796   if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
2797       stream_obj.size > (10 * 1024 * 1024))
2798     goto not_enough_data;
2800   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
2802   /* process this stream object later after all the other 'normal' ones
2803    * have been processed (since the others are more important/non-hidden) */
2804   len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
2805   if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
2806     goto not_enough_data;
2808   /* parse stream object */
2809   stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
2810   g_free (stream_obj_data);
2812 done:
2814   if (stream) {
2815     stream->ext_props = esp;
2817     /* try to set the framerate */
2818     if (stream->is_video && stream->caps) {
2819       GValue framerate = { 0 };
2820       GstStructure *s;
2821       gint num, denom;
2823       g_value_init (&framerate, GST_TYPE_FRACTION);
2825       num = GST_SECOND / 100;
2826       denom = esp.avg_time_per_frame;
2827       if (denom == 0) {
2828         /* avoid division by 0, assume 25/1 framerate */
2829         denom = GST_SECOND / 2500;
2830       }
2832       gst_value_set_fraction (&framerate, num, denom);
2834       stream->caps = gst_caps_make_writable (stream->caps);
2835       s = gst_caps_get_structure (stream->caps, 0);
2836       gst_structure_set_value (s, "framerate", &framerate);
2837       g_value_unset (&framerate);
2838       GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
2839           num, denom, ((gdouble) num) / denom);
2840     }
2842     /* add language info now if we have it */
2843     if (stream->ext_props.lang_idx < demux->num_languages) {
2844       if (stream->pending_tags == NULL)
2845         stream->pending_tags = gst_tag_list_new ();
2846       GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
2847           demux->languages[stream->ext_props.lang_idx]);
2848       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
2849           GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
2850           NULL);
2851     }
2852   } else {
2853     GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
2854   }
2856   return GST_FLOW_OK;
2858   /* Errors */
2859 not_enough_data:
2860   {
2861     GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
2862     return GST_FLOW_OK;         /* not absolutely fatal */
2863   }
2864 expected_stream_object:
2865   {
2866     GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
2867         "object: expected embedded stream object, but got %s object instead!",
2868         gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
2869     return GST_FLOW_OK;         /* not absolutely fatal */
2870   }
2873 static const gchar *
2874 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
2876   const gchar *nick;
2878   nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
2879   if (g_str_has_prefix (nick, "ASF_OBJ_"))
2880     nick += strlen ("ASF_OBJ_");
2882   if (demux->objpath == NULL) {
2883     demux->objpath = g_strdup (nick);
2884   } else {
2885     gchar *newpath;
2887     newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
2888     g_free (demux->objpath);
2889     demux->objpath = newpath;
2890   }
2892   return (const gchar *) demux->objpath;
2895 static void
2896 gst_asf_demux_pop_obj (GstASFDemux * demux)
2898   gchar *s;
2900   if ((s = g_strrstr (demux->objpath, "/"))) {
2901     *s = '\0';
2902   } else {
2903     g_free (demux->objpath);
2904     demux->objpath = NULL;
2905   }
2908 static void
2909 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
2911   GSList *l;
2912   guint i;
2914   /* Parse the queued extended stream property objects and add the info
2915    * to the existing streams or add the new embedded streams, but without
2916    * activating them yet */
2917   GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
2918       g_slist_length (demux->ext_stream_props));
2920   for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
2921     GstBuffer *buf = GST_BUFFER (l->data);
2923     GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
2924     gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
2925         GST_BUFFER_SIZE (buf));
2926     gst_buffer_unref (buf);
2927   }
2928   g_slist_free (demux->ext_stream_props);
2929   demux->ext_stream_props = NULL;
2932 static void
2933 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
2935   guint i, j;
2937   for (i = 0; i < demux->num_streams; ++i) {
2938     AsfStream *stream;
2939     gboolean is_hidden;
2940     GSList *x;
2942     stream = &demux->stream[i];
2944     GST_LOG_OBJECT (demux, "checking  stream %2u", stream->id);
2946     if (stream->active) {
2947       GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
2948       continue;
2949     }
2951     is_hidden = FALSE;
2952     for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
2953       guint8 *mes;
2955       /* check for each mutual exclusion whether it affects this stream */
2956       for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
2957         if (*mes == stream->id) {
2958           /* if yes, check if we've already added streams that are mutually
2959            * exclusive with the stream we're about to add */
2960           for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
2961             for (j = 0; j < demux->num_streams; ++j) {
2962               /* if the broadcast flag is set, assume the hidden streams aren't
2963                * actually streamed and hide them (or playbin won't work right),
2964                * otherwise assume their data is available */
2965               if (demux->stream[j].id == *mes && demux->broadcast) {
2966                 is_hidden = TRUE;
2967                 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
2968                     "mutually exclusive with already existing stream ID %d, "
2969                     "hiding stream", stream->id, demux->stream[j].id);
2970                 goto next;
2971               }
2972             }
2973           }
2974           break;
2975         }
2976       }
2977     }
2979   next:
2981     /* FIXME: we should do stream activation based on preroll data in
2982      * streaming mode too */
2983     if (demux->streaming && !is_hidden)
2984       gst_asf_demux_activate_stream (demux, stream);
2985   }
2988 static GstFlowReturn
2989 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
2990     guint64 * p_size)
2992   GstFlowReturn ret = GST_FLOW_OK;
2993   AsfObject obj;
2994   guint64 obj_data_size;
2996   if (*p_size < ASF_OBJECT_HEADER_SIZE)
2997     return ASF_FLOW_NEED_MORE_DATA;
2999   asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj);
3000   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3002   obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3004   if (*p_size < obj_data_size)
3005     return ASF_FLOW_NEED_MORE_DATA;
3007   gst_asf_demux_push_obj (demux, obj.id);
3009   GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3011   switch (obj.id) {
3012     case ASF_OBJ_STREAM:{
3013       AsfStream *stream;
3015       stream =
3016           gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3018       /* FIXME: we should do stream activation based on preroll data in
3019        * streaming mode too */
3020       if (demux->streaming && stream != NULL)
3021         gst_asf_demux_activate_stream (demux, stream);
3023       ret = GST_FLOW_OK;
3024       break;
3025     }
3026     case ASF_OBJ_FILE:
3027       ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3028       break;
3029     case ASF_OBJ_HEADER:
3030       ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3031       break;
3032     case ASF_OBJ_COMMENT:
3033       ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3034       break;
3035     case ASF_OBJ_HEAD1:
3036       ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3037       break;
3038     case ASF_OBJ_BITRATE_PROPS:
3039       ret =
3040           gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3041           obj_data_size);
3042       break;
3043     case ASF_OBJ_EXT_CONTENT_DESC:
3044       ret =
3045           gst_asf_demux_process_ext_content_desc (demux, *p_data,
3046           obj_data_size);
3047       break;
3048     case ASF_OBJ_METADATA_OBJECT:
3049       ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3050       break;
3051     case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3052       GstBuffer *buf;
3054       /* process these later, we might not have parsed the corresponding
3055        * stream object yet */
3056       GST_LOG ("%s: queued for later parsing", demux->objpath);
3057       buf = gst_buffer_new_and_alloc (obj_data_size);
3058       memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3059       demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3060       ret = GST_FLOW_OK;
3061       break;
3062     }
3063     case ASF_OBJ_LANGUAGE_LIST:
3064       ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3065       break;
3066     case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3067       ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3068           obj_data_size);
3069       break;
3070     case ASF_OBJ_SIMPLE_INDEX:
3071       ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3072       break;
3073     case ASF_OBJ_CONTENT_ENCRYPTION:
3074     case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3075     case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3076       goto error_encrypted;
3077     case ASF_OBJ_CONCEAL_NONE:
3078     case ASF_OBJ_HEAD2:
3079     case ASF_OBJ_UNDEFINED:
3080     case ASF_OBJ_CODEC_COMMENT:
3081     case ASF_OBJ_INDEX:
3082     case ASF_OBJ_PADDING:
3083     case ASF_OBJ_BITRATE_MUTEX:
3084     case ASF_OBJ_COMPATIBILITY:
3085     case ASF_OBJ_INDEX_PLACEHOLDER:
3086     case ASF_OBJ_INDEX_PARAMETERS:
3087     case ASF_OBJ_STREAM_PRIORITIZATION:
3088     case ASF_OBJ_SCRIPT_COMMAND:
3089     default:
3090       /* Unknown/unhandled object, skip it and hope for the best */
3091       GST_INFO ("%s: skipping object", demux->objpath);
3092       ret = GST_FLOW_OK;
3093       break;
3094   }
3096   /* this can't fail, we checked the number of bytes available before */
3097   gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3099   GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3101   gst_asf_demux_pop_obj (demux);
3103   return ret;
3105 /* ERRORS */
3106 error_encrypted:
3107   {
3108     GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3109     return GST_FLOW_ERROR;
3110   }
3113 static void
3114 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3115     GstBuffer ** p_buffer)
3117   GstBuffer *descrambled_buffer;
3118   GstBuffer *scrambled_buffer;
3119   GstBuffer *sub_buffer;
3120   guint offset;
3121   guint off;
3122   guint row;
3123   guint col;
3124   guint idx;
3126   /* descrambled_buffer is initialised in the first iteration */
3127   descrambled_buffer = NULL;
3128   scrambled_buffer = *p_buffer;
3130   if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3131     return;
3133   for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3134       offset += demux->ds_chunk_size) {
3135     off = offset / demux->ds_chunk_size;
3136     row = off / demux->span;
3137     col = off % demux->span;
3138     idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3139     GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3140         col, off, demux->ds_chunk_size);
3141     GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3142         GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3143     GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3144         GST_BUFFER_SIZE (scrambled_buffer));
3145     sub_buffer =
3146         gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3147         demux->ds_chunk_size);
3148     if (!offset) {
3149       descrambled_buffer = sub_buffer;
3150     } else {
3151       descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3152     }
3153   }
3155   gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3156       GST_BUFFER_COPY_TIMESTAMPS);
3158   /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3160   gst_buffer_unref (scrambled_buffer);
3161   *p_buffer = descrambled_buffer;
3164 static gboolean
3165 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3167   GstASFDemux *demux = GST_ASF_DEMUX (element);
3168   gint i;
3170   GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3172   for (i = 0; i < demux->num_streams; ++i) {
3173     gst_event_ref (event);
3174     if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3175       gst_event_unref (event);
3176       return TRUE;
3177     }
3178   }
3180   gst_event_unref (event);
3181   return FALSE;
3184 /* takes ownership of the passed event */
3185 static gboolean
3186 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3188   gboolean ret = TRUE;
3189   gint i;
3191   GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3192       GST_EVENT_TYPE_NAME (event));
3194   for (i = 0; i < demux->num_streams; ++i) {
3195     gst_event_ref (event);
3196     ret &= gst_pad_push_event (demux->stream[i].pad, event);
3197   }
3198   gst_event_unref (event);
3199   return ret;
3202 static const GstQueryType *
3203 gst_asf_demux_get_src_query_types (GstPad * pad)
3205   static const GstQueryType types[] = {
3206     GST_QUERY_POSITION,
3207     GST_QUERY_DURATION,
3208     GST_QUERY_SEEKING,
3209     0
3210   };
3212   return types;
3215 static gboolean
3216 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3218   GstASFDemux *demux;
3219   gboolean res = FALSE;
3221   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3223   GST_DEBUG ("handling %s query",
3224       gst_query_type_get_name (GST_QUERY_TYPE (query)));
3226   switch (GST_QUERY_TYPE (query)) {
3227     case GST_QUERY_DURATION:
3228     {
3229       GstFormat format;
3231       gst_query_parse_duration (query, &format, NULL);
3233       if (format != GST_FORMAT_TIME) {
3234         GST_LOG ("only support duration queries in TIME format");
3235         break;
3236       }
3238       GST_OBJECT_LOCK (demux);
3240       if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3241         GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3242             GST_TIME_ARGS (demux->segment.duration));
3244         gst_query_set_duration (query, GST_FORMAT_TIME,
3245             demux->segment.duration);
3247         res = TRUE;
3248       } else {
3249         GST_LOG ("duration not known yet");
3250       }
3252       GST_OBJECT_UNLOCK (demux);
3253       break;
3254     }
3256     case GST_QUERY_POSITION:{
3257       GstFormat format;
3259       gst_query_parse_position (query, &format, NULL);
3261       if (format != GST_FORMAT_TIME) {
3262         GST_LOG ("only support position queries in TIME format");
3263         break;
3264       }
3266       GST_OBJECT_LOCK (demux);
3268       if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3269         GST_LOG ("returning position: %" GST_TIME_FORMAT,
3270             GST_TIME_ARGS (demux->segment.last_stop));
3272         gst_query_set_position (query, GST_FORMAT_TIME,
3273             demux->segment.last_stop);
3275         res = TRUE;
3276       } else {
3277         GST_LOG ("position not known yet");
3278       }
3280       GST_OBJECT_UNLOCK (demux);
3281       break;
3282     }
3284     case GST_QUERY_SEEKING:{
3285       GstFormat format;
3287       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3288       if (format == GST_FORMAT_TIME) {
3289         gint64 duration;
3291         GST_OBJECT_LOCK (demux);
3292         duration = demux->segment.duration;
3293         GST_OBJECT_UNLOCK (demux);
3295         gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable,
3296             0, duration);
3297         res = TRUE;
3298       }
3299       break;
3300     }
3302     default:
3303       res = gst_pad_query_default (pad, query);
3304       break;
3305   }
3307   gst_object_unref (demux);
3308   return res;
3311 static GstStateChangeReturn
3312 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3314   GstASFDemux *demux = GST_ASF_DEMUX (element);
3315   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3317   switch (transition) {
3318     case GST_STATE_CHANGE_NULL_TO_READY:{
3319       gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3320       demux->need_newsegment = TRUE;
3321       demux->segment_running = FALSE;
3322       demux->adapter = gst_adapter_new ();
3323       demux->metadata = gst_caps_new_empty ();
3324       demux->data_size = 0;
3325       demux->data_offset = 0;
3326       demux->index_offset = 0;
3327       break;
3328     }
3329     default:
3330       break;
3331   }
3333   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3334   if (ret == GST_STATE_CHANGE_FAILURE)
3335     return ret;
3337   switch (transition) {
3338     case GST_STATE_CHANGE_PAUSED_TO_READY:
3339     case GST_STATE_CHANGE_READY_TO_NULL:
3340       gst_asf_demux_reset (demux);
3341       break;
3342     default:
3343       break;
3344   }
3346   return ret;