]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugins-ugly0-10.git/blob - gst/asfdemux/gstasfdemux.c
asfdemux: Don't leak pending payload buffers
[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-2009 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  * - fix packet parsing:
27  *   there's something wrong with timestamps for packets with keyframes,
28  *   and durations too.
29  */
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/riff/riff-media.h>
38 #include <gst/tag/tag.h>
39 #include <gst/gst-i18n-plugin.h>
40 #include <stdio.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 gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
99 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
100 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
101 static gboolean
102 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
103 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
104     AsfStream * stream, GstBuffer ** p_buffer);
105 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
106     AsfStream * stream);
107 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
108     guint stream_num);
109 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
110     gboolean force);
112 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
114 static void
115 gst_asf_demux_base_init (gpointer g_class)
117   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
119   gst_element_class_add_pad_template (element_class,
120       gst_static_pad_template_get (&audio_src_template));
121   gst_element_class_add_pad_template (element_class,
122       gst_static_pad_template_get (&video_src_template));
123   gst_element_class_add_pad_template (element_class,
124       gst_static_pad_template_get (&gst_asf_demux_sink_template));
126   gst_element_class_set_details_simple (element_class, "ASF Demuxer",
127       "Codec/Demuxer",
128       "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
131 static void
132 gst_asf_demux_class_init (GstASFDemuxClass * klass)
134   GstElementClass *gstelement_class;
136   gstelement_class = (GstElementClass *) klass;
138   gstelement_class->change_state =
139       GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140   gstelement_class->send_event =
141       GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
144 static void
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
147   gst_caps_replace (&stream->caps, NULL);
148   if (stream->pending_tags) {
149     gst_tag_list_free (stream->pending_tags);
150     stream->pending_tags = NULL;
151   }
152   if (stream->pad) {
153     if (stream->active)
154       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
155     else
156       gst_object_unref (stream->pad);
157     stream->pad = NULL;
158   }
160   while (stream->payloads->len > 0) {
161     AsfPayload *payload;
162     guint last;
164     last = stream->payloads->len - 1;
165     payload = &g_array_index (stream->payloads, AsfPayload, last);
166     gst_buffer_replace (&payload->buf, NULL);
167     g_array_remove_index (stream->payloads, last);
168   }
169   if (stream->payloads) {
170     g_array_free (stream->payloads, TRUE);
171     stream->payloads = NULL;
172   }
173   if (stream->ext_props.valid) {
174     g_free (stream->ext_props.payload_extensions);
175     stream->ext_props.payload_extensions = NULL;
176   }
179 static void
180 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
182   GST_LOG_OBJECT (demux, "resetting");
184   gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
185   demux->segment_running = FALSE;
186   if (demux->adapter && !chain_reset) {
187     gst_adapter_clear (demux->adapter);
188     g_object_unref (demux->adapter);
189     demux->adapter = NULL;
190   }
191   if (demux->taglist) {
192     gst_tag_list_free (demux->taglist);
193     demux->taglist = NULL;
194   }
195   if (demux->metadata) {
196     gst_caps_unref (demux->metadata);
197     demux->metadata = NULL;
198   }
199   if (demux->global_metadata) {
200     gst_structure_free (demux->global_metadata);
201     demux->global_metadata = NULL;
202   }
204   demux->state = GST_ASF_DEMUX_STATE_HEADER;
205   g_free (demux->objpath);
206   demux->objpath = NULL;
207   g_strfreev (demux->languages);
208   demux->languages = NULL;
209   demux->num_languages = 0;
210   g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
211       NULL);
212   g_slist_free (demux->ext_stream_props);
213   demux->ext_stream_props = NULL;
215   while (demux->old_num_streams > 0) {
216     gst_asf_demux_free_stream (demux,
217         &demux->old_stream[demux->old_num_streams - 1]);
218     --demux->old_num_streams;
219   }
220   memset (demux->old_stream, 0, sizeof (demux->old_stream));
221   demux->old_num_streams = 0;
223   /* when resetting for a new chained asf, we don't want to remove the pads
224    * before adding the new ones */
225   if (chain_reset) {
226     memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
227     demux->old_num_streams = demux->num_streams;
228     demux->num_streams = 0;
229   }
231   while (demux->num_streams > 0) {
232     gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
233     --demux->num_streams;
234   }
235   memset (demux->stream, 0, sizeof (demux->stream));
236   if (!chain_reset) {
237     /* do not remove those for not adding pads with same name */
238     demux->num_audio_streams = 0;
239     demux->num_video_streams = 0;
240   }
241   demux->num_streams = 0;
242   demux->activated_streams = FALSE;
243   demux->first_ts = GST_CLOCK_TIME_NONE;
244   demux->segment_ts = GST_CLOCK_TIME_NONE;
245   demux->in_gap = 0;
246   if (!chain_reset)
247     gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
248   demux->state = GST_ASF_DEMUX_STATE_HEADER;
249   demux->seekable = FALSE;
250   demux->broadcast = FALSE;
251   demux->sidx_interval = 0;
252   demux->sidx_num_entries = 0;
253   g_free (demux->sidx_entries);
254   demux->sidx_entries = NULL;
256   demux->speed_packets = 1;
258   if (chain_reset) {
259     GST_LOG_OBJECT (demux, "Restarting");
260     gst_segment_init (&demux->segment, GST_FORMAT_TIME);
261     demux->need_newsegment = TRUE;
262     demux->segment_running = FALSE;
263     demux->accurate = FALSE;
264     demux->metadata = gst_caps_new_empty ();
265     demux->global_metadata = gst_structure_empty_new ("metadata");
266     demux->data_size = 0;
267     demux->data_offset = 0;
268     demux->index_offset = 0;
269   } else {
270     demux->base_offset = 0;
271   }
274 static void
275 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
277   demux->sinkpad =
278       gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
279   gst_pad_set_chain_function (demux->sinkpad,
280       GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
281   gst_pad_set_event_function (demux->sinkpad,
282       GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
283   gst_pad_set_activate_function (demux->sinkpad,
284       GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
285   gst_pad_set_activatepull_function (demux->sinkpad,
286       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
287   gst_pad_set_activatepush_function (demux->sinkpad,
288       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
289   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
291   /* set initial state */
292   gst_asf_demux_reset (demux, FALSE);
295 static gboolean
296 gst_asf_demux_activate (GstPad * sinkpad)
298   if (gst_pad_check_pull_range (sinkpad)) {
299     return gst_pad_activate_pull (sinkpad, TRUE);
300   } else {
301     return gst_pad_activate_push (sinkpad, TRUE);
302   }
305 static gboolean
306 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
308   GstASFDemux *demux;
310   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
312   demux->state = GST_ASF_DEMUX_STATE_HEADER;
313   demux->streaming = TRUE;
315   return TRUE;
318 static gboolean
319 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
321   GstASFDemux *demux;
323   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
325   if (active) {
326     demux->state = GST_ASF_DEMUX_STATE_HEADER;
327     demux->streaming = FALSE;
329     return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
330         demux);
331   } else {
332     return gst_pad_stop_task (pad);
333   }
337 static gboolean
338 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
340   GstASFDemux *demux;
341   gboolean ret = TRUE;
343   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
345   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
346   switch (GST_EVENT_TYPE (event)) {
347     case GST_EVENT_NEWSEGMENT:{
348       GstFormat newsegment_format;
349       gint64 newsegment_start, stop, time;
350       gdouble rate, arate;
351       gboolean update;
353       gst_event_parse_new_segment_full (event, &update, &rate, &arate,
354           &newsegment_format, &newsegment_start, &stop, &time);
356       if (newsegment_format == GST_FORMAT_BYTES) {
357         if (demux->packet_size && newsegment_start > demux->data_offset)
358           demux->packet = (newsegment_start - demux->data_offset) /
359               demux->packet_size;
360         else
361           demux->packet = 0;
362       } else if (newsegment_format == GST_FORMAT_TIME) {
363         /* do not know packet position, not really a problem */
364         demux->packet = -1;
365       } else {
366         GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
367         gst_event_unref (event);
368         break;
369       }
371       /* record upstream segment for interpolation */
372       if (newsegment_format != demux->in_segment.format)
373         gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
374       gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate,
375           newsegment_format, newsegment_start, stop, time);
377       /* in either case, clear some state and generate newsegment later on */
378       GST_OBJECT_LOCK (demux);
379       demux->segment_ts = GST_CLOCK_TIME_NONE;
380       demux->in_gap = GST_CLOCK_TIME_NONE;
381       demux->need_newsegment = TRUE;
382       gst_asf_demux_reset_stream_state_after_discont (demux);
383       GST_OBJECT_UNLOCK (demux);
385       gst_event_unref (event);
386       break;
387     }
388     case GST_EVENT_EOS:{
389       GstFlowReturn flow;
391       if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
392         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
393             (_("This stream contains no data.")),
394             ("got eos and didn't receive a complete header object"));
395         break;
396       }
397       flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
398       if (flow < GST_FLOW_UNEXPECTED || flow == GST_FLOW_NOT_LINKED) {
399         GST_ELEMENT_ERROR (demux, STREAM, FAILED,
400             (_("Internal data stream error.")),
401             ("streaming stopped, reason %s", gst_flow_get_name (flow)));
402         break;
403       }
405       GST_OBJECT_LOCK (demux);
406       gst_adapter_clear (demux->adapter);
407       GST_OBJECT_UNLOCK (demux);
408       gst_asf_demux_send_event_unlocked (demux, event);
409       break;
410     }
412     case GST_EVENT_FLUSH_STOP:
413       GST_OBJECT_LOCK (demux);
414       gst_asf_demux_reset_stream_state_after_discont (demux);
415       GST_OBJECT_UNLOCK (demux);
416       gst_asf_demux_send_event_unlocked (demux, event);
417       /* upon activation, latency is no longer introduced, e.g. after seek */
418       if (demux->activated_streams)
419         demux->latency = 0;
420       break;
422     default:
423       ret = gst_pad_event_default (pad, event);
424       break;
425   }
427   gst_object_unref (demux);
428   return ret;
431 static gboolean
432 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
433     GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
435   GstClockTime idx_time;
436   guint idx;
438   if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
439     return FALSE;
441   idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
443   /* FIXME: seek beyond end of file should result in immediate EOS from
444    * streaming thread instead of a failed seek */
445   if (G_UNLIKELY (idx >= demux->sidx_num_entries))
446     return FALSE;
448   *packet = demux->sidx_entries[idx].packet;
449   if (speed)
450     *speed = demux->sidx_entries[idx].count;
452   /* so we get closer to the actual time of the packet ... actually, let's not
453    * do this, since we throw away superfluous payloads before the seek position
454    * anyway; this way, our key unit seek 'snap resolution' is a bit better
455    * (ie. same as index resolution) */
456   /*
457      while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
458      --idx;
459    */
461   idx_time = demux->sidx_interval * idx;
462   if (G_LIKELY (idx_time >= demux->preroll))
463     idx_time -= demux->preroll;
465   GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
466       GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
467       GST_TIME_ARGS (idx_time));
469   if (G_LIKELY (p_idx_time))
470     *p_idx_time = idx_time;
472   return TRUE;
475 static void
476 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
478   guint n;
480   gst_adapter_clear (demux->adapter);
482   GST_DEBUG_OBJECT (demux, "reset stream state");
484   for (n = 0; n < demux->num_streams; n++) {
485     demux->stream[n].discont = TRUE;
486     demux->stream[n].last_flow = GST_FLOW_OK;
488     while (demux->stream[n].payloads->len > 0) {
489       AsfPayload *payload;
490       guint last;
492       last = demux->stream[n].payloads->len - 1;
493       payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
494       gst_buffer_replace (&payload->buf, NULL);
495       g_array_remove_index (demux->stream[n].payloads, last);
496     }
497   }
500 static void
501 gst_asf_demux_mark_discont (GstASFDemux * demux)
503   guint n;
505   GST_DEBUG_OBJECT (demux, "Mark stream discont");
507   for (n = 0; n < demux->num_streams; n++)
508     demux->stream[n].discont = TRUE;
511 /* do a seek in push based mode */
512 static gboolean
513 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
515   gdouble rate;
516   GstFormat format;
517   GstSeekFlags flags;
518   GstSeekType cur_type, stop_type;
519   gint64 cur, stop;
520   guint packet;
521   gboolean res;
523   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
524       &stop_type, &stop);
526   stop_type = GST_SEEK_TYPE_NONE;
527   stop = -1;
529   GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
531   /* determine packet, by index or by estimation */
532   if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
533     packet = (guint) gst_util_uint64_scale (demux->num_packets,
534         cur, demux->play_time);
535   }
537   if (packet > demux->num_packets) {
538     GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
539         "seek aborted.");
540     return FALSE;
541   }
543   GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
545   cur = demux->data_offset + (packet * demux->packet_size);
547   GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
548       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
549   /* BYTE seek event */
550   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
551       stop_type, stop);
552   res = gst_pad_push_event (demux->sinkpad, event);
554   return res;
557 static gboolean
558 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
560   GstClockTime idx_time;
561   GstSegment segment;
562   GstSeekFlags flags;
563   GstSeekType cur_type, stop_type;
564   GstFormat format;
565   gboolean only_need_update;
566   gboolean keyunit_sync;
567   gboolean flush;
568   gdouble rate;
569   gint64 cur, stop;
570   gint64 seek_time;
571   guint packet, speed_count = 1;
573   if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
574           demux->num_packets == 0 || demux->play_time == 0)) {
575     GST_LOG_OBJECT (demux, "stream is not seekable");
576     return FALSE;
577   }
579   if (G_UNLIKELY (!demux->activated_streams)) {
580     GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
581     return FALSE;
582   }
584   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
585       &stop_type, &stop);
587   if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
588     GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
589     return FALSE;
590   }
592   if (G_UNLIKELY (rate <= 0.0)) {
593     GST_LOG_OBJECT (demux, "backward playback is not supported yet");
594     return FALSE;
595   }
597   flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
598   demux->accurate =
599       ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
600   keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
602   if (G_UNLIKELY (demux->streaming)) {
603     /* support it safely needs more segment handling, e.g. closing etc */
604     if (!flush) {
605       GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
606       return FALSE;
607     }
608     /* we can (re)construct the start later on, but not the end */
609     if (stop_type != GST_SEEK_TYPE_NONE) {
610       GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
611       return FALSE;
612     }
613     gst_event_ref (event);
614     /* upstream might handle TIME seek, e.g. mms or rtsp,
615      * or not, e.g. http, then we give it a hand */
616     if (!gst_pad_push_event (demux->sinkpad, event))
617       return gst_asf_demux_handle_seek_push (demux, event);
618     else
619       return TRUE;
620   }
622   /* unlock the streaming thread */
623   if (G_LIKELY (flush)) {
624     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
625     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
626   } else {
627     gst_pad_pause_task (demux->sinkpad);
628   }
630   /* grab the stream lock so that streaming cannot continue, for
631    * non flushing seeks when the element is in PAUSED this could block
632    * forever */
633   GST_PAD_STREAM_LOCK (demux->sinkpad);
635   /* we now can stop flushing, since we have the stream lock now */
636   gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
638   if (G_LIKELY (flush))
639     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
641   /* operating on copy of segment until we know the seek worked */
642   segment = demux->segment;
644   if (G_UNLIKELY (demux->segment_running && !flush)) {
645     GstEvent *newseg;
647     /* create the segment event to close the current segment */
648     newseg = gst_event_new_new_segment (TRUE, segment.rate,
649         GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
651     gst_asf_demux_send_event_unlocked (demux, newseg);
652   }
654   gst_segment_set_seek (&segment, rate, format, flags, cur_type,
655       cur, stop_type, stop, &only_need_update);
657   GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
658       "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
660   seek_time = segment.start;
662   /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
663    * real start of data and segment_start to indexed time for key unit seek*/
664   if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
665               &idx_time, &speed_count))) {
666     /* First try to query our source to see if it can convert for us. This is
667        the case when our source is an mms stream, notice that in this case
668        gstmms will do a time based seek to get the byte offset, this is not a
669        problem as the seek to this offset needs to happen anway. */
670     gint64 offset;
671     GstFormat dest_format = GST_FORMAT_BYTES;
673     if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
674             &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
675       packet = (offset - demux->data_offset) / demux->packet_size;
676       GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
677           " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
678           G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
679           GST_TIME_ARGS (seek_time), offset, demux->data_offset,
680           demux->packet_size, packet);
681     } else {
682       /* FIXME: For streams containing video, seek to an earlier position in
683        * the hope of hitting a keyframe and let the sinks throw away the stuff
684        * before the segment start. For audio-only this is unnecessary as every
685        * frame is 'key'. */
686       if (flush && (demux->accurate || keyunit_sync)
687           && demux->num_video_streams > 0) {
688         seek_time -= 5 * GST_SECOND;
689         if (seek_time < 0)
690           seek_time = 0;
691       }
693       packet = (guint) gst_util_uint64_scale (demux->num_packets,
694           seek_time, demux->play_time);
696       if (packet > demux->num_packets)
697         packet = demux->num_packets;
698     }
699   } else {
700     if (G_LIKELY (keyunit_sync)) {
701       GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
702           GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
703           GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
704       segment.start = idx_time;
705       segment.last_stop = idx_time;
706       segment.time = idx_time;
707     }
708   }
710   GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
712   GST_OBJECT_LOCK (demux);
713   demux->segment = segment;
714   demux->packet = packet;
715   demux->need_newsegment = TRUE;
716   demux->speed_packets = speed_count;
717   gst_asf_demux_reset_stream_state_after_discont (demux);
718   GST_OBJECT_UNLOCK (demux);
720   /* restart our task since it might have been stopped when we did the flush */
721   gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
722       demux);
724   /* streaming can continue now */
725   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
727   return TRUE;
730 static gboolean
731 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
733   GstASFDemux *demux;
734   gboolean ret;
736   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
738   switch (GST_EVENT_TYPE (event)) {
739     case GST_EVENT_SEEK:
740       GST_LOG_OBJECT (pad, "seek event");
741       ret = gst_asf_demux_handle_seek_event (demux, event);
742       gst_event_unref (event);
743       break;
744     case GST_EVENT_QOS:
745     case GST_EVENT_NAVIGATION:
746       /* just drop these two silently */
747       gst_event_unref (event);
748       ret = FALSE;
749       break;
750     default:
751       GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
752       ret = gst_pad_event_default (pad, event);
753       break;
754   }
756   gst_object_unref (demux);
757   return ret;
760 static inline guint32
761 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
763   guint32 ret;
765   ret = gst_asf_identify_guid (guids, guid);
767   GST_LOG ("%s  0x%08x-0x%08x-0x%08x-0x%08x",
768       gst_asf_get_guid_nick (guids, ret),
769       guid->v1, guid->v2, guid->v3, guid->v4);
771   return ret;
774 typedef struct
776   AsfObjectID id;
777   guint64 size;
778 } AsfObject;
781 /* expect is true when the user is expeting an object,
782  * when false, it will give no warnings if the object
783  * is not identified
784  */
785 static gboolean
786 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
787     guint data_len, AsfObject * object, gboolean expect)
789   ASFGuid guid;
791   if (data_len < ASF_OBJECT_HEADER_SIZE)
792     return FALSE;
794   guid.v1 = GST_READ_UINT32_LE (data + 0);
795   guid.v2 = GST_READ_UINT32_LE (data + 4);
796   guid.v3 = GST_READ_UINT32_LE (data + 8);
797   guid.v4 = GST_READ_UINT32_LE (data + 12);
799   object->size = GST_READ_UINT64_LE (data + 16);
801   /* FIXME: make asf_demux_identify_object_guid() */
802   object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
803   if (object->id == ASF_OBJ_UNDEFINED && expect) {
804     GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
805         guid.v1, guid.v2, guid.v3, guid.v4);
806   }
808   return TRUE;
811 static void
812 gst_asf_demux_release_old_pads (GstASFDemux * demux)
814   GST_DEBUG_OBJECT (demux, "Releasing old pads");
816   while (demux->old_num_streams > 0) {
817     gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
818         gst_event_new_eos ());
819     gst_asf_demux_free_stream (demux,
820         &demux->old_stream[demux->old_num_streams - 1]);
821     --demux->old_num_streams;
822   }
823   memset (demux->old_stream, 0, sizeof (demux->old_stream));
824   demux->old_num_streams = 0;
827 static GstFlowReturn
828 gst_asf_demux_chain_headers (GstASFDemux * demux)
830   GstFlowReturn flow;
831   AsfObject obj;
832   guint8 *header_data, *data = NULL;
833   const guint8 *cdata = NULL;
834   guint64 header_size;
836   cdata = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
837   if (cdata == NULL)
838     goto need_more_data;
840   asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
841   if (obj.id != ASF_OBJ_HEADER)
842     goto wrong_type;
844   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
846   /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
847   if (gst_adapter_available (demux->adapter) < obj.size + 50)
848     goto need_more_data;
850   data = gst_adapter_take (demux->adapter, obj.size + 50);
852   header_data = data;
853   header_size = obj.size;
854   flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
855   if (flow != GST_FLOW_OK)
856     goto parse_failed;
858   /* calculate where the packet data starts */
859   demux->data_offset = obj.size + 50;
861   /* now parse the beginning of the ASF_OBJ_DATA object */
862   if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
863     goto wrong_type;
865   if (demux->num_streams == 0)
866     goto no_streams;
868   g_free (data);
869   return GST_FLOW_OK;
871 /* NON-FATAL */
872 need_more_data:
873   {
874     GST_LOG_OBJECT (demux, "not enough data in adapter yet");
875     return GST_FLOW_OK;
876   }
878 /* ERRORS */
879 wrong_type:
880   {
881     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
882         ("This doesn't seem to be an ASF file"));
883     g_free (data);
884     return GST_FLOW_ERROR;
885   }
886 no_streams:
887 parse_failed:
888   {
889     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
890         ("header parsing failed, or no streams found, flow = %s",
891             gst_flow_get_name (flow)));
892     g_free (data);
893     return GST_FLOW_ERROR;
894   }
897 static GstFlowReturn
898 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
899     GstFlowReturn flow)
901   int i;
903   GST_DEBUG_OBJECT (demux, "Aggregating");
905   /* Store the value */
906   stream->last_flow = flow;
908   /* any other error that is not not-linked can be returned right away */
909   if (flow != GST_FLOW_NOT_LINKED)
910     goto done;
912   for (i = 0; i < demux->num_streams; i++) {
913     if (demux->stream[i].active) {
914       flow = demux->stream[i].last_flow;
915       GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
916           gst_flow_get_name (flow));
917       if (flow != GST_FLOW_NOT_LINKED)
918         goto done;
919     }
920   }
922   /* If we got here, then all our active streams are not linked */
923 done:
924   return flow;
927 static gboolean
928 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
929     GstBuffer ** p_buf, GstFlowReturn * p_flow)
931   GstFlowReturn flow;
933   GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
934       offset, size);
936   flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
938   if (G_LIKELY (p_flow))
939     *p_flow = flow;
941   if (G_UNLIKELY (flow != GST_FLOW_OK)) {
942     GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
943         "+%u", gst_flow_get_name (flow), offset, size);
944     *p_buf = NULL;
945     return FALSE;
946   }
948   g_assert (*p_buf != NULL);
950   if (G_UNLIKELY (GST_BUFFER_SIZE (*p_buf) < size)) {
951     GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
952         "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
953     gst_buffer_unref (*p_buf);
954     if (G_LIKELY (p_flow))
955       *p_flow = GST_FLOW_UNEXPECTED;
956     *p_buf = NULL;
957     return FALSE;
958   }
960   return TRUE;
963 static void
964 gst_asf_demux_pull_indices (GstASFDemux * demux)
966   GstBuffer *buf = NULL;
967   guint64 offset;
968   guint num_read = 0;
970   offset = demux->index_offset;
972   if (G_UNLIKELY (offset == 0)) {
973     GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
974     return;
975   }
977   while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
978     GstFlowReturn flow;
979     AsfObject obj;
981     asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
982     gst_buffer_replace (&buf, NULL);
984     /* check for sanity */
985     if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
986       GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
987       break;
988     }
990     if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
991                 NULL)))
992       break;
994     GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
995         ", size %u", offset, (guint) obj.size);
997     offset += obj.size;         /* increase before _process_object changes it */
999     flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
1000     gst_buffer_replace (&buf, NULL);
1002     if (G_UNLIKELY (flow != GST_FLOW_OK))
1003       break;
1005     ++num_read;
1006   }
1007   GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1010 static gboolean
1011 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1013   AsfObject obj;
1015   asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1016   if (obj.id != ASF_OBJ_DATA) {
1017     GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1018     return FALSE;
1019   }
1021   demux->state = GST_ASF_DEMUX_STATE_DATA;
1023   if (!demux->broadcast && obj.size > 50) {
1024     demux->data_size = obj.size - 50;
1025     /* CHECKME: for at least one file this is off by +158 bytes?! */
1026     demux->index_offset = demux->data_offset + demux->data_size;
1027   } else {
1028     demux->data_size = 0;
1029     demux->index_offset = 0;
1030   }
1032   demux->packet = 0;
1034   if (!demux->broadcast) {
1035     /* skip object header (24 bytes) and file GUID (16 bytes) */
1036     demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1037   } else {
1038     demux->num_packets = 0;
1039   }
1041   if (demux->num_packets == 0)
1042     demux->seekable = FALSE;
1044   /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1045   if (demux->data_size == 0 && demux->num_packets > 0) {
1046     demux->data_size = demux->num_packets * demux->packet_size;
1047     demux->index_offset = demux->data_offset + demux->data_size;
1048   }
1050   /* process pending stream objects and create pads for those */
1051   gst_asf_demux_process_queued_extended_stream_objects (demux);
1053   GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1054       "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1055       ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1056       demux->data_offset, demux->data_size, demux->index_offset);
1058   return TRUE;
1061 static gboolean
1062 gst_asf_demux_pull_headers (GstASFDemux * demux)
1064   GstFlowReturn flow;
1065   AsfObject obj;
1066   GstBuffer *buf = NULL;
1067   guint64 size;
1069   GST_LOG_OBJECT (demux, "reading headers");
1071   /* pull HEADER object header, so we know its size */
1072   if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1073     goto read_failed;
1075   asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
1076   gst_buffer_replace (&buf, NULL);
1078   if (obj.id != ASF_OBJ_HEADER)
1079     goto wrong_type;
1081   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1083   /* pull HEADER object */
1084   if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1085           NULL))
1086     goto read_failed;
1088   size = obj.size;              /* don't want obj.size changed */
1089   flow = gst_asf_demux_process_object (demux, &buf->data, &size);
1090   gst_buffer_replace (&buf, NULL);
1092   if (flow != GST_FLOW_OK) {
1093     GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1094     goto parse_failed;
1095   }
1097   /* calculate where the packet data starts */
1098   demux->data_offset = demux->base_offset + obj.size + 50;
1100   /* now pull beginning of DATA object before packet data */
1101   if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1102           NULL))
1103     goto read_failed;
1105   if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
1106     goto wrong_type;
1108   if (demux->num_streams == 0)
1109     goto no_streams;
1111   gst_buffer_replace (&buf, NULL);
1112   return TRUE;
1114 /* ERRORS */
1115 wrong_type:
1116   {
1117     gst_buffer_replace (&buf, NULL);
1118     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1119         ("This doesn't seem to be an ASF file"));
1120     return FALSE;
1121   }
1122 no_streams:
1123 read_failed:
1124 parse_failed:
1125   {
1126     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1127     return FALSE;
1128   }
1131 static gboolean
1132 all_streams_prerolled (GstASFDemux * demux)
1134   GstClockTime preroll_time;
1135   guint i, num_no_data = 0;
1137   /* Allow at least 500ms of preroll_time  */
1138   preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1140   /* returns TRUE as long as there isn't a stream which (a) has data queued
1141    * and (b) the timestamp of last piece of data queued is < demux->preroll
1142    * AND there is at least one other stream with data queued */
1143   for (i = 0; i < demux->num_streams; ++i) {
1144     AsfPayload *last_payload;
1145     AsfStream *stream;
1146     guint last_idx;
1148     stream = &demux->stream[i];
1149     if (G_UNLIKELY (stream->payloads->len == 0)) {
1150       ++num_no_data;
1151       GST_LOG_OBJECT (stream->pad, "no data queued");
1152       continue;
1153     }
1155     last_idx = stream->payloads->len - 1;
1156     last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1158     GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1159         GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1160         GST_TIME_ARGS (preroll_time));
1161     if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1162       GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1163       return FALSE;
1164     }
1165   }
1167   if (G_UNLIKELY (num_no_data == demux->num_streams))
1168     return FALSE;
1170   return TRUE;
1173 #if 0
1174 static gboolean
1175 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1176     AsfStream * stream)
1178   GSList *l;
1180   for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1181     guint8 *mes;
1183     /* check for each mutual exclusion group whether it affects this stream */
1184     for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1185       if (*mes == stream->id) {
1186         /* we are in this group; let's check if we've already activated streams
1187          * that are in the same group (and hence mutually exclusive to this
1188          * one) */
1189         for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1190           guint i;
1192           for (i = 0; i < demux->num_streams; ++i) {
1193             if (demux->stream[i].id == *mes && demux->stream[i].active) {
1194               GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1195                   "to already active stream with ID %d", stream->id,
1196                   demux->stream[i].id);
1197               return TRUE;
1198             }
1199           }
1200         }
1201         /* we can only be in this group once, let's break out and move on to
1202          * the next mutual exclusion group */
1203         break;
1204       }
1205     }
1206   }
1208   return FALSE;
1210 #endif
1212 static gboolean
1213 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1215   guint i;
1217   if (demux->activated_streams)
1218     return TRUE;
1220   if (!all_streams_prerolled (demux) && !force) {
1221     GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1222     return FALSE;
1223   }
1225   for (i = 0; i < demux->num_streams; ++i) {
1226     AsfStream *stream = &demux->stream[i];
1228     if (stream->payloads->len > 0) {
1229       /* we don't check mutual exclusion stuff here; either we have data for
1230        * a stream, then we active it, or we don't, then we'll ignore it */
1231       GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1232       gst_asf_demux_activate_stream (demux, stream);
1233     } else {
1234       GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1235     }
1236   }
1238   gst_asf_demux_release_old_pads (demux);
1240   demux->activated_streams = TRUE;
1241   GST_LOG_OBJECT (demux, "signalling no more pads");
1242   gst_element_no_more_pads (GST_ELEMENT (demux));
1243   return TRUE;
1246 /* returns the stream that has a complete payload with the lowest timestamp
1247  * queued, or NULL (we push things by timestamp because during the internal
1248  * prerolling we might accumulate more data then the external queues can take,
1249  * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1250 static AsfStream *
1251 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1253   AsfPayload *best_payload = NULL;
1254   AsfStream *best_stream = NULL;
1255   guint i;
1257   for (i = 0; i < demux->num_streams; ++i) {
1258     AsfStream *stream;
1260     stream = &demux->stream[i];
1262     /* Don't push any data until we have at least one payload that falls within
1263      * the current segment. This way we can remove out-of-segment payloads that
1264      * don't need to be decoded after a seek, sending only data from the
1265      * keyframe directly before our segment start */
1266     if (stream->payloads->len > 0) {
1267       AsfPayload *payload;
1268       guint last_idx;
1270       last_idx = stream->payloads->len - 1;
1271       payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1272       if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1273               (payload->ts < demux->segment.start))) {
1274         if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1275           GST_DEBUG_OBJECT (stream->pad,
1276               "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1277               GST_TIME_ARGS (payload->ts));
1278           demux->segment.start = payload->ts;
1279           demux->segment.time = payload->ts;
1280         } else {
1281           GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1282               GST_TIME_FORMAT " which is before our segment start %"
1283               GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1284               GST_TIME_ARGS (demux->segment.start));
1285           continue;
1286         }
1287       }
1289       /* Now see if there's a complete payload queued for this stream */
1291       payload = &g_array_index (stream->payloads, AsfPayload, 0);
1292       if (!gst_asf_payload_is_complete (payload))
1293         continue;
1295       /* ... and whether its timestamp is lower than the current best */
1296       if (best_stream == NULL || best_payload->ts > payload->ts) {
1297         best_stream = stream;
1298         best_payload = payload;
1299       }
1300     }
1301   }
1303   return best_stream;
1306 static GstFlowReturn
1307 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1309   AsfStream *stream;
1310   GstFlowReturn ret = GST_FLOW_OK;
1312   if (G_UNLIKELY (!demux->activated_streams)) {
1313     if (!gst_asf_demux_check_activate_streams (demux, force))
1314       return GST_FLOW_OK;
1315     /* streams are now activated */
1316   }
1318   /* wait until we had a chance to "lock on" some payload's timestamp */
1319   if (G_UNLIKELY (demux->need_newsegment
1320           && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1321     return GST_FLOW_OK;
1323   while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1324     AsfPayload *payload;
1326     payload = &g_array_index (stream->payloads, AsfPayload, 0);
1328     /* do we need to send a newsegment event */
1329     if ((G_UNLIKELY (demux->need_newsegment))) {
1331       /* safe default if insufficient upstream info */
1332       if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1333         demux->in_gap = 0;
1335       if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1336           demux->segment.duration > 0) {
1337         /* slight HACK; prevent clipping of last bit */
1338         demux->segment.stop = demux->segment.duration + demux->in_gap;
1339       }
1341       /* FIXME : only if ACCURATE ! */
1342       if (G_LIKELY (!demux->accurate
1343               && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1344         GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1345             GST_TIME_ARGS (payload->ts));
1346         demux->segment.start = payload->ts;
1347         demux->segment.time = payload->ts;
1348       }
1350       GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1351           &demux->segment);
1353       /* note: we fix up all timestamps to start from 0, so this should be ok */
1354       gst_asf_demux_send_event_unlocked (demux,
1355           gst_event_new_new_segment (FALSE, demux->segment.rate,
1356               GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1357               demux->segment.start));
1359       /* now post any global tags we may have found */
1360       if (demux->taglist == NULL)
1361         demux->taglist = gst_tag_list_new ();
1363       gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1364           GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1366       GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1367       gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
1368       demux->taglist = NULL;
1370       demux->need_newsegment = FALSE;
1371       demux->segment_running = TRUE;
1372     }
1374     /* Do we have tags pending for this stream? */
1375     if (G_UNLIKELY (stream->pending_tags)) {
1376       GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1377       gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1378           stream->pending_tags);
1379       stream->pending_tags = NULL;
1380     }
1382     /* We have the whole packet now so we should push the packet to
1383      * the src pad now. First though we should check if we need to do
1384      * descrambling */
1385     if (G_UNLIKELY (demux->span > 1)) {
1386       gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1387     }
1389     payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1391     if (G_LIKELY (!payload->keyframe)) {
1392       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1393     }
1395     if (G_UNLIKELY (stream->discont)) {
1396       GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1397       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1398       stream->discont = FALSE;
1399     }
1401     if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1402             (payload->par_x != stream->par_x) &&
1403             (payload->par_y != stream->par_y))) {
1404       GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1405           stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1406       stream->par_x = payload->par_x;
1407       stream->par_y = payload->par_y;
1408       gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1409           GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1410       gst_pad_set_caps (stream->pad, stream->caps);
1411     }
1413     if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1414       GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1415           payload->interlaced);
1416       stream->interlaced = payload->interlaced;
1417       gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
1418           stream->interlaced, NULL);
1419     }
1421     gst_buffer_set_caps (payload->buf, stream->caps);
1423     /* (sort of) interpolate timestamps using upstream "frame of reference",
1424      * typically useful for live src, but might (unavoidably) mess with
1425      * position reporting if a live src is playing not so live content
1426      * (e.g. rtspsrc taking some time to fall back to tcp) */
1427     GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1428     if (payload->duration == GST_CLOCK_TIME_NONE
1429         && stream->ext_props.avg_time_per_frame != 0)
1430       GST_BUFFER_DURATION (payload->buf) =
1431           stream->ext_props.avg_time_per_frame * 100;
1432     else
1433       GST_BUFFER_DURATION (payload->buf) = payload->duration;
1435     /* FIXME: we should really set durations on buffers if we can */
1437     GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1438         ", dur=%" GST_TIME_FORMAT " size=%u",
1439         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1440         GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1441         GST_BUFFER_SIZE (payload->buf));
1443     ret = gst_pad_push (stream->pad, payload->buf);
1444     ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1445     payload->buf = NULL;
1446     g_array_remove_index (stream->payloads, 0);
1448     /* Break out as soon as we have an issue */
1449     if (G_UNLIKELY (ret != GST_FLOW_OK))
1450       break;
1451   }
1453   return ret;
1456 static gboolean
1457 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1459   AsfObject obj;
1460   g_assert (buf != NULL);
1462   GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1464   /* we return false on buffer too small */
1465   if (GST_BUFFER_SIZE (buf) < ASF_OBJECT_HEADER_SIZE)
1466     return FALSE;
1468   /* check if it is a header */
1469   asf_demux_peek_object (demux, GST_BUFFER_DATA (buf),
1470       ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1471   if (obj.id == ASF_OBJ_HEADER) {
1472     return TRUE;
1473   }
1474   return FALSE;
1477 static gboolean
1478 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1480   guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1481   GstFlowReturn ret = GST_FLOW_OK;
1482   GstBuffer *buf = NULL;
1483   gboolean header = FALSE;
1485   /* TODO maybe we should skip index objects after the data and look
1486    * further for a new header */
1487   if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1488     g_assert (buf != NULL);
1489     /* check if it is a header */
1490     if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1491       GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1492       demux->base_offset = off;
1493       header = TRUE;
1494     }
1496     gst_buffer_unref (buf);
1497   }
1499   return header;
1502 static void
1503 gst_asf_demux_loop (GstASFDemux * demux)
1505   GstFlowReturn flow = GST_FLOW_OK;
1506   GstBuffer *buf = NULL;
1507   guint64 off;
1508   gboolean sent_eos = FALSE;
1510   if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1511     if (!gst_asf_demux_pull_headers (demux)) {
1512       flow = GST_FLOW_ERROR;
1513       goto pause;
1514     }
1516     gst_asf_demux_pull_indices (demux);
1517   }
1519   g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1521   if (G_UNLIKELY (demux->num_packets != 0
1522           && demux->packet >= demux->num_packets))
1523     goto eos;
1525   GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1526       (guint) demux->num_packets);
1528   off = demux->data_offset + (demux->packet * demux->packet_size);
1530   if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1531               demux->packet_size * demux->speed_packets, &buf, &flow))) {
1532     GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1533     if (flow == GST_FLOW_UNEXPECTED)
1534       goto eos;
1535     else if (flow == GST_FLOW_WRONG_STATE) {
1536       GST_DEBUG_OBJECT (demux, "Not fatal");
1537       goto pause;
1538     } else
1539       goto read_failed;
1540   }
1542   if (G_LIKELY (demux->speed_packets == 1)) {
1543     /* FIXME: maybe we should just skip broken packets and error out only
1544      * after a few broken packets in a row? */
1545     if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1546       /* when we don't know when the data object ends, we should check
1547        * for a chained asf */
1548       if (demux->num_packets == 0) {
1549         if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1550           GST_INFO_OBJECT (demux, "Chained asf found");
1551           demux->base_offset = off;
1552           gst_asf_demux_reset (demux, TRUE);
1553           gst_buffer_unref (buf);
1554           return;
1555         }
1556       }
1557       goto parse_error;
1558     }
1560     flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1562     ++demux->packet;
1564   } else {
1565     guint n;
1566     for (n = 0; n < demux->speed_packets; n++) {
1567       GstBuffer *sub;
1569       sub =
1570           gst_buffer_create_sub (buf, n * demux->packet_size,
1571           demux->packet_size);
1572       /* FIXME: maybe we should just skip broken packets and error out only
1573        * after a few broken packets in a row? */
1574       if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub))) {
1575         /* when we don't know when the data object ends, we should check
1576          * for a chained asf */
1577         if (demux->num_packets == 0) {
1578           if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1579             GST_INFO_OBJECT (demux, "Chained asf found");
1580             demux->base_offset = off + n * demux->packet_size;
1581             gst_asf_demux_reset (demux, TRUE);
1582             gst_buffer_unref (sub);
1583             gst_buffer_unref (buf);
1584             return;
1585           }
1586         }
1587         goto parse_error;
1588       }
1590       gst_buffer_unref (sub);
1592       flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1594       ++demux->packet;
1596     }
1598     /* reset speed pull */
1599     demux->speed_packets = 1;
1600   }
1602   gst_buffer_unref (buf);
1604   if (G_UNLIKELY (demux->num_packets > 0
1605           && demux->packet >= demux->num_packets)) {
1606     GST_LOG_OBJECT (demux, "reached EOS");
1607     goto eos;
1608   }
1610   if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1611     GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1612     goto pause;
1613   }
1615   /* check if we're at the end of the configured segment */
1616   /* FIXME: check if segment end reached etc. */
1618   return;
1620 eos:
1621   {
1622     /* if we haven't activated our streams yet, this might be because we have
1623      * less data queued than required for preroll; force stream activation and
1624      * send any pending payloads before sending EOS */
1625     if (!demux->activated_streams)
1626       gst_asf_demux_push_complete_payloads (demux, TRUE);
1628     /* we want to push an eos or post a segment-done in any case */
1629     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1630       gint64 stop;
1632       /* for segment playback we need to post when (in stream time)
1633        * we stopped, this is either stop (when set) or the duration. */
1634       if ((stop = demux->segment.stop) == -1)
1635         stop = demux->segment.duration;
1637       GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1638       gst_element_post_message (GST_ELEMENT_CAST (demux),
1639           gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1640               stop));
1641     } else if (flow != GST_FLOW_UNEXPECTED) {
1642       /* check if we have a chained asf, in case, we don't eos yet */
1643       if (gst_asf_demux_check_chained_asf (demux)) {
1644         GST_INFO_OBJECT (demux, "Chained ASF starting");
1645         gst_asf_demux_reset (demux, TRUE);
1646         return;
1647       }
1648     }
1649     /* normal playback, send EOS to all linked pads */
1650     GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1651     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1652     sent_eos = TRUE;
1653     /* ... and fall through to pause */
1654   }
1655 pause:
1656   {
1657     GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1658         gst_flow_get_name (flow));
1659     demux->segment_running = FALSE;
1660     gst_pad_pause_task (demux->sinkpad);
1662     /* For the error cases (not EOS) */
1663     if (!sent_eos) {
1664       if (flow == GST_FLOW_UNEXPECTED)
1665         gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1666       else if (flow < GST_FLOW_UNEXPECTED || flow == GST_FLOW_NOT_LINKED) {
1667         /* Post an error. Hopefully something else already has, but if not... */
1668         GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1669             (_("Internal data stream error.")),
1670             ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1671       }
1672     }
1673     return;
1674   }
1676 /* ERRORS */
1677 read_failed:
1678   {
1679     GST_DEBUG_OBJECT (demux, "Read failed, doh");
1680     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1681     flow = GST_FLOW_UNEXPECTED;
1682     goto pause;
1683   }
1684 parse_error:
1685   {
1686     gst_buffer_unref (buf);
1687     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1688         ("Error parsing ASF packet %u", (guint) demux->packet));
1689     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1690     flow = GST_FLOW_ERROR;
1691     goto pause;
1692   }
1695 #define GST_ASF_DEMUX_CHECK_HEADER_YES       0
1696 #define GST_ASF_DEMUX_CHECK_HEADER_NO        1
1697 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1699 static gint
1700 gst_asf_demux_check_header (GstASFDemux * demux)
1702   AsfObject obj;
1703   guint8 *cdata = (guint8 *) gst_adapter_peek (demux->adapter,
1704       ASF_OBJECT_HEADER_SIZE);
1705   if (cdata == NULL)            /* need more data */
1706     return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1708   asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1709   if (obj.id != ASF_OBJ_HEADER) {
1710     return GST_ASF_DEMUX_CHECK_HEADER_NO;
1711   } else {
1712     return GST_ASF_DEMUX_CHECK_HEADER_YES;
1713   }
1716 static GstFlowReturn
1717 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1719   GstFlowReturn ret = GST_FLOW_OK;
1720   GstASFDemux *demux;
1722   demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1724   GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%"
1725       GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
1726       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1728   if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1729     GST_DEBUG_OBJECT (demux, "received DISCONT");
1730     gst_asf_demux_mark_discont (demux);
1731   }
1733   if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1734               GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1735     demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1736     GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1737         ", interpolation gap: %" GST_TIME_FORMAT,
1738         GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1739   }
1741   gst_adapter_push (demux->adapter, buf);
1743   switch (demux->state) {
1744     case GST_ASF_DEMUX_STATE_INDEX:{
1745       gint result = gst_asf_demux_check_header (demux);
1746       if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA)       /* need more data */
1747         break;
1749       if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1750         /* we don't care about this, probably an index */
1751         /* TODO maybe would be smarter to skip all the indices
1752          * until we got a new header or EOS to decide */
1753         GST_LOG_OBJECT (demux, "Received index object, its EOS");
1754         goto eos;
1755       } else {
1756         GST_INFO_OBJECT (demux, "Chained asf starting");
1757         /* cleanup and get ready for a chained asf */
1758         gst_asf_demux_reset (demux, TRUE);
1759         /* fall through */
1760       }
1761     }
1762     case GST_ASF_DEMUX_STATE_HEADER:{
1763       ret = gst_asf_demux_chain_headers (demux);
1764       if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1765         break;
1766       /* otherwise fall through */
1767     }
1768     case GST_ASF_DEMUX_STATE_DATA:
1769     {
1770       guint64 data_size;
1772       data_size = demux->packet_size;
1774       while (gst_adapter_available (demux->adapter) >= data_size) {
1775         GstBuffer *buf;
1777         /* we don't know the length of the stream
1778          * check for a chained asf everytime */
1779         if (demux->num_packets == 0) {
1780           gint result = gst_asf_demux_check_header (demux);
1782           if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1783             GST_INFO_OBJECT (demux, "Chained asf starting");
1784             /* cleanup and get ready for a chained asf */
1785             gst_asf_demux_reset (demux, TRUE);
1786             break;
1787           }
1788         } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1789                 && demux->packet >= demux->num_packets)) {
1790           /* do not overshoot data section when streaming */
1791           break;
1792         }
1794         buf = gst_adapter_take_buffer (demux->adapter, data_size);
1796         /* FIXME: maybe we should just skip broken packets and error out only
1797          * after a few broken packets in a row? */
1798         if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1799           GST_WARNING_OBJECT (demux, "Parse error");
1800         }
1802         gst_buffer_unref (buf);
1804         ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1806         if (demux->packet >= 0)
1807           ++demux->packet;
1808       }
1809       if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1810               && demux->packet >= demux->num_packets)) {
1811         demux->state = GST_ASF_DEMUX_STATE_INDEX;
1812       }
1813       break;
1814     }
1815     default:
1816       g_assert_not_reached ();
1817   }
1819 done:
1820   if (ret != GST_FLOW_OK)
1821     GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1823   return ret;
1825 eos:
1826   {
1827     GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1828     ret = GST_FLOW_UNEXPECTED;
1829     goto done;
1830   }
1833 static inline gboolean
1834 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1836   if (*p_size < num_bytes)
1837     return FALSE;
1839   *p_data += num_bytes;
1840   *p_size -= num_bytes;
1841   return TRUE;
1844 static inline guint8
1845 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1847   guint8 ret;
1849   g_assert (*p_size >= 1);
1850   ret = GST_READ_UINT8 (*p_data);
1851   *p_data += sizeof (guint8);
1852   *p_size -= sizeof (guint8);
1853   return ret;
1856 static inline guint16
1857 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1859   guint16 ret;
1861   g_assert (*p_size >= 2);
1862   ret = GST_READ_UINT16_LE (*p_data);
1863   *p_data += sizeof (guint16);
1864   *p_size -= sizeof (guint16);
1865   return ret;
1868 static inline guint32
1869 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1871   guint32 ret;
1873   g_assert (*p_size >= 4);
1874   ret = GST_READ_UINT32_LE (*p_data);
1875   *p_data += sizeof (guint32);
1876   *p_size -= sizeof (guint32);
1877   return ret;
1880 static inline guint64
1881 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1883   guint64 ret;
1885   g_assert (*p_size >= 8);
1886   ret = GST_READ_UINT64_LE (*p_data);
1887   *p_data += sizeof (guint64);
1888   *p_size -= sizeof (guint64);
1889   return ret;
1892 static inline guint32
1893 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1895   switch (type) {
1896     case 0:
1897       return 0;
1899     case 1:
1900       g_assert (*p_size >= 1);
1901       return gst_asf_demux_get_uint8 (p_data, p_size);
1903     case 2:
1904       g_assert (*p_size >= 2);
1905       return gst_asf_demux_get_uint16 (p_data, p_size);
1907     case 3:
1908       g_assert (*p_size >= 4);
1909       return gst_asf_demux_get_uint32 (p_data, p_size);
1911     default:
1912       g_assert_not_reached ();
1913       break;
1914   }
1915   return 0;
1918 static gboolean
1919 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1920     guint8 ** p_data, guint64 * p_size)
1922   *p_buf = NULL;
1924   if (*p_size < num_bytes_to_read)
1925     return FALSE;
1927   *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1928   memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1929   *p_data += num_bytes_to_read;
1930   *p_size -= num_bytes_to_read;
1931   return TRUE;
1934 static gboolean
1935 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1936     guint8 ** p_data, guint64 * p_size)
1938   *p_buf = NULL;
1940   if (*p_size < num_bytes_to_read)
1941     return FALSE;
1943   *p_buf = g_memdup (*p_data, num_bytes_to_read);
1944   *p_data += num_bytes_to_read;
1945   *p_size -= num_bytes_to_read;
1946   return TRUE;
1949 static gboolean
1950 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1951     guint8 ** p_data, guint64 * p_size)
1953   guint16 s_length;
1954   guint8 *s;
1956   *p_str = NULL;
1958   if (*p_size < 2)
1959     return FALSE;
1961   s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1963   if (p_strlen)
1964     *p_strlen = s_length;
1966   if (s_length == 0) {
1967     GST_WARNING ("zero-length string");
1968     *p_str = g_strdup ("");
1969     return TRUE;
1970   }
1972   if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1973     return FALSE;
1975   g_assert (s != NULL);
1977   /* just because They don't exist doesn't
1978    * mean They are not out to get you ... */
1979   if (s[s_length - 1] != '\0') {
1980     s = g_realloc (s, s_length + 1);
1981     s[s_length] = '\0';
1982   }
1984   *p_str = (gchar *) s;
1985   return TRUE;
1989 static void
1990 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
1992   g_assert (*p_size >= 4 * sizeof (guint32));
1994   guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
1995   guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
1996   guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
1997   guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2000 static gboolean
2001 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2002     guint64 * p_size)
2004   if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2005     return FALSE;
2007   /* WAVEFORMATEX Structure */
2008   audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2009   audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2010   audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2011   audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2012   audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2013   audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2014   /* Codec specific data size */
2015   audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2016   return TRUE;
2019 static gboolean
2020 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2021     guint64 * p_size)
2023   if (*p_size < (4 + 4 + 1 + 2))
2024     return FALSE;
2026   video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2027   video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2028   video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2029   video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2030   return TRUE;
2033 static gboolean
2034 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2035     guint8 ** p_data, guint64 * p_size)
2037   if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2038     return FALSE;
2040   fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2041   fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2042   fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2043   fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2044   fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2045   fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2046   fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2047   fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2048   fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2049   fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2050   fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2051   return TRUE;
2054 AsfStream *
2055 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2057   guint i;
2059   for (i = 0; i < demux->num_streams; i++) {
2060     if (demux->stream[i].id == id)
2061       return &demux->stream[i];
2062   }
2064   GST_WARNING ("Segment found for undefined stream: (%d)", id);
2065   return NULL;
2068 static void
2069 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2070     GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2072   AsfStream *stream;
2074   gst_pad_use_fixed_caps (src_pad);
2075   gst_pad_set_caps (src_pad, caps);
2077   gst_pad_set_event_function (src_pad,
2078       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2079   gst_pad_set_query_type_function (src_pad,
2080       GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
2081   gst_pad_set_query_function (src_pad,
2082       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2084   stream = &demux->stream[demux->num_streams];
2085   stream->caps = caps;
2086   stream->pad = src_pad;
2087   stream->id = id;
2088   stream->fps_known = !is_video;        /* bit hacky for audio */
2089   stream->is_video = is_video;
2090   stream->pending_tags = tags;
2091   stream->discont = TRUE;
2092   if (is_video) {
2093     GstStructure *st;
2094     gint par_x, par_y;
2095     st = gst_caps_get_structure (caps, 0);
2096     if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2097         par_x > 0 && par_y > 0) {
2098       GST_DEBUG ("PAR %d/%d", par_x, par_y);
2099       stream->par_x = par_x;
2100       stream->par_y = par_y;
2101     }
2102   }
2104   stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2106   GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2107       GST_PAD_NAME (src_pad), demux->num_streams, caps);
2109   ++demux->num_streams;
2111   stream->active = FALSE;
2114 static void
2115 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2116     asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2118   GstTagList *tags = NULL;
2119   GstBuffer *extradata = NULL;
2120   GstPad *src_pad;
2121   GstCaps *caps;
2122   guint16 size_left = 0;
2123   gchar *codec_name = NULL;
2124   gchar *name = NULL;
2126   size_left = audio->size;
2128   /* Create the audio pad */
2129   name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
2131   src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2132   g_free (name);
2134   /* Swallow up any left over data and set up the 
2135    * standard properties from the header info */
2136   if (size_left) {
2137     GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2138         "codec specific data", size_left);
2140     g_assert (size_left <= *p_size);
2141     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2142   }
2144   /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2145    * additional two bytes indicating extradata. */
2146   caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2147       (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
2149   if (caps == NULL) {
2150     caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2151         G_TYPE_INT, (gint) audio->codec_tag, NULL);
2152   }
2154   /* Informing about that audio format we just added */
2155   if (codec_name) {
2156     tags = gst_tag_list_new ();
2157     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
2158         codec_name, NULL);
2159     g_free (codec_name);
2160   }
2162   if (extradata)
2163     gst_buffer_unref (extradata);
2165   GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2166       GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2167       audio->codec_tag, tags);
2169   ++demux->num_audio_streams;
2171   gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2174 static void
2175 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2176     asf_stream_video_format * video, guint16 id,
2177     guint8 ** p_data, guint64 * p_size)
2179   GstTagList *tags = NULL;
2180   GstBuffer *extradata = NULL;
2181   GstPad *src_pad;
2182   GstCaps *caps;
2183   gchar *name = NULL;
2184   gchar *codec_name = NULL;
2185   gint size_left = video->size - 40;
2187   /* Create the video pad */
2188   name = g_strdup_printf ("video_%02d", demux->num_video_streams);
2189   src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2190   g_free (name);
2192   /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2193   if (size_left) {
2194     GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2195     g_assert (size_left <= *p_size);
2196     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2197   }
2199   GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2201   /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2202   caps = gst_riff_create_video_caps (video->tag, NULL,
2203       (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2205   if (caps == NULL) {
2206     caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2207         GST_TYPE_FOURCC, video->tag, NULL);
2208   } else {
2209     GstStructure *s;
2210     gint ax, ay;
2212     s = gst_asf_demux_get_metadata_for_stream (demux, id);
2213     if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2214         gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2215       gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2216           ax, ay, NULL);
2218     } else {
2219       guint ax, ay;
2220       /* retry with the global metadata */
2221       GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2222           demux->global_metadata);
2223       s = demux->global_metadata;
2224       if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2225           gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2226         GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2227         if (ax > 0 && ay > 0)
2228           gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2229               ax, ay, NULL);
2230       }
2231     }
2232     s = gst_caps_get_structure (caps, 0);
2233     gst_structure_remove_field (s, "framerate");
2234   }
2236   /* add fourcc format to caps, some proprietary decoders seem to need it */
2237   gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
2239   if (codec_name) {
2240     tags = gst_tag_list_new ();
2241     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
2242         codec_name, NULL);
2243     g_free (codec_name);
2244   }
2246   if (extradata)
2247     gst_buffer_unref (extradata);
2249   GST_INFO ("Adding video stream #%u, id %u, codec %"
2250       GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2251       GST_FOURCC_ARGS (video->tag), video->tag);
2253   ++demux->num_video_streams;
2255   gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2258 static void
2259 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2261   if (!stream->active) {
2262     GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2263         GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2264     gst_pad_set_active (stream->pad, TRUE);
2265     gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2266     stream->active = TRUE;
2267   }
2270 static AsfStream *
2271 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2272     guint64 size)
2274   AsfCorrectionType correction_type;
2275   AsfStreamType stream_type;
2276   GstClockTime time_offset;
2277   gboolean is_encrypted G_GNUC_UNUSED;
2278   guint16 stream_id;
2279   guint16 flags;
2280   ASFGuid guid;
2281   guint stream_specific_size;
2282   guint type_specific_size G_GNUC_UNUSED;
2283   guint unknown G_GNUC_UNUSED;
2285   /* Get the rest of the header's header */
2286   if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2287     goto not_enough_data;
2289   gst_asf_demux_get_guid (&guid, &data, &size);
2290   stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2292   gst_asf_demux_get_guid (&guid, &data, &size);
2293   correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2295   time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2297   type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2298   stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2300   flags = gst_asf_demux_get_uint16 (&data, &size);
2301   stream_id = flags & 0x7f;
2302   is_encrypted = ! !((flags & 0x8000) << 15);
2303   unknown = gst_asf_demux_get_uint32 (&data, &size);
2305   GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2306       stream_id, GST_TIME_ARGS (time_offset));
2308   switch (stream_type) {
2309     case ASF_STREAM_AUDIO:{
2310       asf_stream_audio audio_object;
2312       if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2313         goto not_enough_data;
2315       GST_INFO ("Object is an audio stream with %u bytes of additional data",
2316           audio_object.size);
2318       gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2319           &data, &size);
2321       switch (correction_type) {
2322         case ASF_CORRECTION_ON:{
2323           guint span, packet_size, chunk_size, data_size, silence_data;
2325           GST_INFO ("Using error correction");
2327           if (size < (1 + 2 + 2 + 2 + 1))
2328             goto not_enough_data;
2330           span = gst_asf_demux_get_uint8 (&data, &size);
2331           packet_size = gst_asf_demux_get_uint16 (&data, &size);
2332           chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2333           data_size = gst_asf_demux_get_uint16 (&data, &size);
2334           silence_data = gst_asf_demux_get_uint8 (&data, &size);
2336           /* FIXME: shouldn't this be per-stream? */
2337           demux->span = span;
2339           GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2340               packet_size, chunk_size, data_size, span, silence_data);
2342           if (demux->span > 1) {
2343             if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2344               /* Disable descrambling */
2345               demux->span = 0;
2346             } else {
2347               /* FIXME: this else branch was added for
2348                * weird_al_yankovic - the saga begins.asf */
2349               demux->ds_packet_size = packet_size;
2350               demux->ds_chunk_size = chunk_size;
2351             }
2352           } else {
2353             /* Descambling is enabled */
2354             demux->ds_packet_size = packet_size;
2355             demux->ds_chunk_size = chunk_size;
2356           }
2357 #if 0
2358           /* Now skip the rest of the silence data */
2359           if (data_size > 1)
2360             gst_bytestream_flush (demux->bs, data_size - 1);
2361 #else
2362           /* FIXME: CHECKME. And why -1? */
2363           if (data_size > 1) {
2364             if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2365               goto not_enough_data;
2366             }
2367           }
2368 #endif
2369           break;
2370         }
2371         case ASF_CORRECTION_OFF:{
2372           GST_INFO ("Error correction off");
2373           if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2374             goto not_enough_data;
2375           break;
2376         }
2377         default:
2378           GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2379               ("Audio stream using unknown error correction"));
2380           return NULL;
2381       }
2383       break;
2384     }
2386     case ASF_STREAM_VIDEO:{
2387       asf_stream_video_format video_format_object;
2388       asf_stream_video video_object;
2389       guint16 vsize;
2391       if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2392         goto not_enough_data;
2394       vsize = video_object.size - 40;   /* Byte order gets offset by single byte */
2396       GST_INFO ("object is a video stream with %u bytes of "
2397           "additional data", vsize);
2399       if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2400               &data, &size)) {
2401         goto not_enough_data;
2402       }
2404       gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2405           &data, &size);
2407       break;
2408     }
2410     default:
2411       GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2412           stream_id);
2413       break;
2414   }
2416   return gst_asf_demux_get_stream (demux, stream_id);
2418 not_enough_data:
2419   {
2420     GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2421     /* we'll error out later if we found no streams */
2422     return NULL;
2423   }
2426 static const gchar *
2427 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2429   const struct
2430   {
2431     const gchar *asf_name;
2432     const gchar *gst_name;
2433   } tags[] = {
2434     {
2435     "WM/Genre", GST_TAG_GENRE}, {
2436     "WM/AlbumTitle", GST_TAG_ALBUM}, {
2437     "WM/AlbumArtist", GST_TAG_ARTIST}, {
2438     "WM/Picture", GST_TAG_IMAGE}, {
2439     "WM/Track", GST_TAG_TRACK_NUMBER}, {
2440     "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2441     "WM/Year", GST_TAG_DATE}
2442     /* { "WM/Composer", GST_TAG_COMPOSER } */
2443   };
2444   gsize out;
2445   guint i;
2447   if (name_utf8 == NULL) {
2448     GST_WARNING ("Failed to convert name to UTF8, skipping");
2449     return NULL;
2450   }
2452   out = strlen (name_utf8);
2454   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2455     if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2456       GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2457       return tags[i].gst_name;
2458     }
2459   }
2461   return NULL;
2464 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2465 static void
2466 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2468   GstTagList *t;
2470   GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2472   if (taglist == NULL)
2473     return;
2475   if (gst_tag_list_is_empty (taglist)) {
2476     gst_tag_list_free (taglist);
2477     return;
2478   }
2480   t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2481   if (demux->taglist)
2482     gst_tag_list_free (demux->taglist);
2483   gst_tag_list_free (taglist);
2484   demux->taglist = t;
2485   GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2488 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING  0
2489 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY      1
2490 #define ASF_DEMUX_DATA_TYPE_DWORD           3
2492 static void
2493 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2494     guint tag_data_len)
2496   GstByteReader r;
2497   const guint8 *img_data = NULL;
2498   guint32 img_data_len = 0;
2499   guint8 pic_type = 0;
2501   gst_byte_reader_init (&r, tag_data, tag_data_len);
2503   /* skip mime type string (we don't trust it and do our own typefinding),
2504    * and also skip the description string, since we don't use it */
2505   if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2506       !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2507       !gst_byte_reader_skip_string_utf16 (&r) ||
2508       !gst_byte_reader_skip_string_utf16 (&r) ||
2509       !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2510     goto not_enough_data;
2511   }
2514   if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2515     GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2517   return;
2519 not_enough_data:
2520   {
2521     GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2522     GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2523     return;
2524   }
2527 /* Extended Content Description Object */
2528 static GstFlowReturn
2529 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2530     guint64 size)
2532   /* Other known (and unused) 'text/unicode' metadata available :
2533    *
2534    *   WM/Lyrics =
2535    *   WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2536    *   WMFSDKVersion = 9.00.00.2980
2537    *   WMFSDKNeeded = 0.0.0.0000
2538    *   WM/UniqueFileIdentifier = AMGa_id=R    15334;AMGp_id=P     5149;AMGt_id=T  2324984
2539    *   WM/Publisher = 4AD
2540    *   WM/Provider = AMG
2541    *   WM/ProviderRating = 8
2542    *   WM/ProviderStyle = Rock (similar to WM/Genre)
2543    *   WM/GenreID (similar to WM/Genre)
2544    *   WM/TrackNumber (same as WM/Track but as a string)
2545    *
2546    * Other known (and unused) 'non-text' metadata available :
2547    *
2548    *   WM/EncodingTime
2549    *   WM/MCDI
2550    *   IsVBR
2551    *
2552    * We might want to read WM/TrackNumber and use atoi() if we don't have
2553    * WM/Track
2554    */
2556   GstTagList *taglist;
2557   guint16 blockcount, i;
2559   GST_INFO_OBJECT (demux, "object is an extended content description");
2561   taglist = gst_tag_list_new ();
2563   /* Content Descriptor Count */
2564   if (size < 2)
2565     goto not_enough_data;
2567   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2569   for (i = 1; i <= blockcount; ++i) {
2570     const gchar *gst_tag_name;
2571     guint16 datatype;
2572     guint16 value_len;
2573     guint16 name_len;
2574     GValue tag_value = { 0, };
2575     gsize in, out;
2576     gchar *name;
2577     gchar *name_utf8 = NULL;
2578     gchar *value;
2580     /* Descriptor */
2581     if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2582       goto not_enough_data;
2584     if (size < 2) {
2585       g_free (name);
2586       goto not_enough_data;
2587     }
2588     /* Descriptor Value Data Type */
2589     datatype = gst_asf_demux_get_uint16 (&data, &size);
2591     /* Descriptor Value (not really a string, but same thing reading-wise) */
2592     if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2593       g_free (name);
2594       goto not_enough_data;
2595     }
2597     name_utf8 =
2598         g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2600     if (name_utf8 != NULL) {
2601       GST_DEBUG ("Found tag/metadata %s", name_utf8);
2603       gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2604       GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2606       switch (datatype) {
2607         case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2608           gchar *value_utf8;
2610           value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2611               &in, &out, NULL);
2613           /* get rid of tags with empty value */
2614           if (value_utf8 != NULL && *value_utf8 != '\0') {
2615             GST_DEBUG ("string value %s", value_utf8);
2617             value_utf8[out] = '\0';
2619             if (gst_tag_name != NULL) {
2620               if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2621                 guint year = atoi (value_utf8);
2623                 if (year > 0) {
2624                   GDate *date = g_date_new_dmy (1, 1, year);
2626                   g_value_init (&tag_value, GST_TYPE_DATE);
2627                   gst_value_set_date (&tag_value, date);
2628                   g_date_free (date);
2629                 }
2630               } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2631                 guint id3v1_genre_id;
2632                 const gchar *genre_str;
2634                 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2635                     ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2636                   GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2637                   g_free (value_utf8);
2638                   value_utf8 = g_strdup (genre_str);
2639                 }
2640               } else {
2641                 GType tag_type;
2643                 /* convert tag from string to other type if required */
2644                 tag_type = gst_tag_get_type (gst_tag_name);
2645                 g_value_init (&tag_value, tag_type);
2646                 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2647                   GValue from_val = { 0, };
2649                   g_value_init (&from_val, G_TYPE_STRING);
2650                   g_value_set_string (&from_val, value_utf8);
2651                   if (!g_value_transform (&from_val, &tag_value)) {
2652                     GST_WARNING_OBJECT (demux,
2653                         "Could not transform string tag to " "%s tag type %s",
2654                         gst_tag_name, g_type_name (tag_type));
2655                     g_value_unset (&tag_value);
2656                   }
2657                   g_value_unset (&from_val);
2658                 }
2659               }
2660             } else {
2661               /* metadata ! */
2662               GST_DEBUG ("Setting metadata");
2663               g_value_init (&tag_value, G_TYPE_STRING);
2664               g_value_set_string (&tag_value, value_utf8);
2665             }
2666           } else if (value_utf8 == NULL) {
2667             GST_WARNING ("Failed to convert string value to UTF8, skipping");
2668           } else {
2669             GST_DEBUG ("Skipping empty string value for %s",
2670                 GST_STR_NULL (gst_tag_name));
2671           }
2672           g_free (value_utf8);
2673           break;
2674         }
2675         case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2676           if (gst_tag_name) {
2677             if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2678               GST_FIXME ("Unhandled byte array tag %s",
2679                   GST_STR_NULL (gst_tag_name));
2680               break;
2681             } else {
2682               asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2683                   value_len);
2684             }
2685           }
2686           break;
2687         }
2688         case ASF_DEMUX_DATA_TYPE_DWORD:{
2689           guint uint_val = GST_READ_UINT32_LE (value);
2691           /* this is the track number */
2692           g_value_init (&tag_value, G_TYPE_UINT);
2694           /* WM/Track counts from 0 */
2695           if (!strcmp (name_utf8, "WM/Track"))
2696             ++uint_val;
2698           g_value_set_uint (&tag_value, uint_val);
2699           break;
2700         }
2701         default:{
2702           GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2703           break;
2704         }
2705       }
2707       if (G_IS_VALUE (&tag_value)) {
2708         if (gst_tag_name) {
2709           GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2711           /* WM/TrackNumber is more reliable than WM/Track, since the latter
2712            * is supposed to have a 0 base but is often wrongly written to start
2713            * from 1 as well, so prefer WM/TrackNumber when we have it: either
2714            * replace the value added earlier from WM/Track or put it first in
2715            * the list, so that it will get picked up by _get_uint() */
2716           if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2717             merge_mode = GST_TAG_MERGE_REPLACE;
2719           gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2720               &tag_value, NULL);
2721         } else {
2722           GST_DEBUG ("Setting global metadata %s", name_utf8);
2723           gst_structure_set_value (demux->global_metadata, name_utf8,
2724               &tag_value);
2725         }
2727         g_value_unset (&tag_value);
2728       }
2729     }
2731     g_free (name);
2732     g_free (value);
2733     g_free (name_utf8);
2734   }
2736   gst_asf_demux_add_global_tags (demux, taglist);
2738   return GST_FLOW_OK;
2740   /* Errors */
2741 not_enough_data:
2742   {
2743     GST_WARNING ("Unexpected end of data parsing ext content desc object");
2744     gst_tag_list_free (taglist);
2745     return GST_FLOW_OK;         /* not really fatal */
2746   }
2749 static GstStructure *
2750 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2752   gchar sname[32];
2753   guint i;
2755   g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2757   for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2758     GstStructure *s;
2760     s = gst_caps_get_structure (demux->metadata, i);
2761     if (gst_structure_has_name (s, sname))
2762       return s;
2763   }
2765   gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2767   /* try lookup again; demux->metadata took ownership of the structure, so we
2768    * can't really make any assumptions about what happened to it, so we can't
2769    * just return it directly after appending it */
2770   return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2773 static GstFlowReturn
2774 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2775     guint64 size)
2777   guint16 blockcount, i;
2779   GST_INFO_OBJECT (demux, "object is a metadata object");
2781   /* Content Descriptor Count */
2782   if (size < 2)
2783     goto not_enough_data;
2785   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2787   for (i = 0; i < blockcount; ++i) {
2788     GstStructure *s;
2789     guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
2790     guint32 data_len, ival;
2791     gchar *name_utf8;
2793     if (size < (2 + 2 + 2 + 2 + 4))
2794       goto not_enough_data;
2796     lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2797     stream_num = gst_asf_demux_get_uint16 (&data, &size);
2798     name_len = gst_asf_demux_get_uint16 (&data, &size);
2799     data_type = gst_asf_demux_get_uint16 (&data, &size);
2800     data_len = gst_asf_demux_get_uint32 (&data, &size);
2802     if (size < name_len + data_len)
2803       goto not_enough_data;
2805     /* convert name to UTF-8 */
2806     name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2807         NULL, NULL, NULL);
2808     gst_asf_demux_skip_bytes (name_len, &data, &size);
2810     if (name_utf8 == NULL) {
2811       GST_WARNING ("Failed to convert value name to UTF8, skipping");
2812       gst_asf_demux_skip_bytes (data_len, &data, &size);
2813       continue;
2814     }
2816     if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2817       gst_asf_demux_skip_bytes (data_len, &data, &size);
2818       g_free (name_utf8);
2819       continue;
2820     }
2822     /* read DWORD */
2823     if (size < 4) {
2824       g_free (name_utf8);
2825       goto not_enough_data;
2826     }
2828     ival = gst_asf_demux_get_uint32 (&data, &size);
2830     /* skip anything else there may be, just in case */
2831     gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2833     s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2834     gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2835     g_free (name_utf8);
2836   }
2838   GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2839   return GST_FLOW_OK;
2841   /* Errors */
2842 not_enough_data:
2843   {
2844     GST_WARNING ("Unexpected end of data parsing metadata object");
2845     return GST_FLOW_OK;         /* not really fatal */
2846   }
2849 static GstFlowReturn
2850 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2852   GstFlowReturn ret = GST_FLOW_OK;
2853   guint32 i, num_objects;
2854   guint8 unknown G_GNUC_UNUSED;
2856   /* Get the rest of the header's header */
2857   if (size < (4 + 1 + 1))
2858     goto not_enough_data;
2860   num_objects = gst_asf_demux_get_uint32 (&data, &size);
2861   unknown = gst_asf_demux_get_uint8 (&data, &size);
2862   unknown = gst_asf_demux_get_uint8 (&data, &size);
2864   GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2866   /* Loop through the header's objects, processing those */
2867   for (i = 0; i < num_objects; ++i) {
2868     GST_INFO_OBJECT (demux, "reading header part %u", i);
2869     ret = gst_asf_demux_process_object (demux, &data, &size);
2870     if (ret != GST_FLOW_OK) {
2871       GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2872       break;
2873     }
2874   }
2876   return ret;
2878 not_enough_data:
2879   {
2880     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2881         ("short read parsing HEADER object"));
2882     return GST_FLOW_ERROR;
2883   }
2886 static GstFlowReturn
2887 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2889   guint64 creation_time G_GNUC_UNUSED;
2890   guint64 file_size G_GNUC_UNUSED;
2891   guint64 send_time G_GNUC_UNUSED;
2892   guint64 packets_count, play_time, preroll;
2893   guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
2895   if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2896     goto not_enough_data;
2898   gst_asf_demux_skip_bytes (16, &data, &size);  /* skip GUID */
2899   file_size = gst_asf_demux_get_uint64 (&data, &size);
2900   creation_time = gst_asf_demux_get_uint64 (&data, &size);
2901   packets_count = gst_asf_demux_get_uint64 (&data, &size);
2902   play_time = gst_asf_demux_get_uint64 (&data, &size);
2903   send_time = gst_asf_demux_get_uint64 (&data, &size);
2904   preroll = gst_asf_demux_get_uint64 (&data, &size);
2905   flags = gst_asf_demux_get_uint32 (&data, &size);
2906   min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2907   max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2908   min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2910   demux->broadcast = ! !(flags & 0x01);
2911   demux->seekable = ! !(flags & 0x02);
2913   GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2914   GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2915   GST_DEBUG_OBJECT (demux, "flags::seekable  = %d", demux->seekable);
2917   if (demux->broadcast) {
2918     /* these fields are invalid if the broadcast flag is set */
2919     play_time = 0;
2920     file_size = 0;
2921   }
2923   if (min_pktsize != max_pktsize)
2924     goto non_fixed_packet_size;
2926   demux->packet_size = max_pktsize;
2928   /* FIXME: do we need send_time as well? what is it? */
2929   if ((play_time * 100) >= (preroll * GST_MSECOND))
2930     demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2931   else
2932     demux->play_time = 0;
2934   demux->preroll = preroll * GST_MSECOND;
2936   /* initial latency */
2937   demux->latency = demux->preroll;
2939   if (demux->play_time == 0)
2940     demux->seekable = FALSE;
2942   GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2943       GST_TIME_ARGS (demux->play_time));
2944   GST_DEBUG_OBJECT (demux, "preroll   %" GST_TIME_FORMAT,
2945       GST_TIME_ARGS (demux->preroll));
2947   if (demux->play_time > 0) {
2948     gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2949         demux->play_time);
2950   }
2952   GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2953       packets_count);
2954   GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2956   return GST_FLOW_OK;
2958 /* ERRORS */
2959 non_fixed_packet_size:
2960   {
2961     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2962         ("packet size must be fixed"));
2963     return GST_FLOW_ERROR;
2964   }
2965 not_enough_data:
2966   {
2967     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2968         ("short read parsing FILE object"));
2969     return GST_FLOW_ERROR;
2970   }
2973 /* Content Description Object */
2974 static GstFlowReturn
2975 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2977   struct
2978   {
2979     const gchar *gst_tag;
2980     guint16 val_length;
2981     gchar *val_utf8;
2982   } tags[5] = {
2983     {
2984     GST_TAG_TITLE, 0, NULL}, {
2985     GST_TAG_ARTIST, 0, NULL}, {
2986     GST_TAG_COPYRIGHT, 0, NULL}, {
2987     GST_TAG_DESCRIPTION, 0, NULL}, {
2988     GST_TAG_COMMENT, 0, NULL}
2989   };
2990   GstTagList *taglist;
2991   GValue value = { 0 };
2992   gsize in, out;
2993   gint i = -1;
2995   GST_INFO_OBJECT (demux, "object is a comment");
2997   if (size < (2 + 2 + 2 + 2 + 2))
2998     goto not_enough_data;
3000   tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3001   tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3002   tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3003   tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3004   tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3006   GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3007       "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3008       tags[2].val_length, tags[3].val_length, tags[4].val_length);
3010   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3011     if (size < tags[i].val_length)
3012       goto not_enough_data;
3014     /* might be just '/0', '/0'... */
3015     if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3016       /* convert to UTF-8 */
3017       tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3018           "UTF-8", "UTF-16LE", &in, &out, NULL);
3019     }
3020     gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3021   }
3023   /* parse metadata into taglist */
3024   taglist = gst_tag_list_new ();
3025   g_value_init (&value, G_TYPE_STRING);
3026   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3027     if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3028       g_value_set_string (&value, tags[i].val_utf8);
3029       gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3030           tags[i].gst_tag, &value, NULL);
3031     }
3032   }
3033   g_value_unset (&value);
3035   gst_asf_demux_add_global_tags (demux, taglist);
3037   for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3038     g_free (tags[i].val_utf8);
3040   return GST_FLOW_OK;
3042 not_enough_data:
3043   {
3044     GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3045         "comment tag section %d, skipping comment object", i);
3046     for (i = 0; i < G_N_ELEMENTS (tags); i++)
3047       g_free (tags[i].val_utf8);
3048     return GST_FLOW_OK;         /* not really fatal */
3049   }
3052 static GstFlowReturn
3053 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3054     guint64 size)
3056   guint16 num_streams, i;
3057   AsfStream *stream;
3059   if (size < 2)
3060     goto not_enough_data;
3062   num_streams = gst_asf_demux_get_uint16 (&data, &size);
3064   GST_INFO ("object is a bitrate properties object with %u streams",
3065       num_streams);
3067   if (size < (num_streams * (2 + 4)))
3068     goto not_enough_data;
3070   for (i = 0; i < num_streams; ++i) {
3071     guint32 bitrate;
3072     guint16 stream_id;
3074     stream_id = gst_asf_demux_get_uint16 (&data, &size);
3075     bitrate = gst_asf_demux_get_uint32 (&data, &size);
3077     if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3078       GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3079       stream = gst_asf_demux_get_stream (demux, stream_id);
3080       if (stream) {
3081         if (stream->pending_tags == NULL)
3082           stream->pending_tags = gst_tag_list_new ();
3083         gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3084             GST_TAG_BITRATE, bitrate, NULL);
3085       } else {
3086         GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3087       }
3088     } else {
3089       GST_WARNING ("stream id %u is too large", stream_id);
3090     }
3091   }
3093   return GST_FLOW_OK;
3095 not_enough_data:
3096   {
3097     GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3098     return GST_FLOW_OK;         /* not really fatal */
3099   }
3102 static GstFlowReturn
3103 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3104     guint64 size)
3106   GstFlowReturn ret = GST_FLOW_OK;
3107   guint64 hdr_size;
3109   /* Get the rest of the header's header */
3110   if (size < (16 + 2 + 4))
3111     goto not_enough_data;
3113   /* skip GUID and two other bytes */
3114   gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3115   hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3117   GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3119   /* FIXME: does data_size include the rest of the header that we have read? */
3120   if (hdr_size > size)
3121     goto not_enough_data;
3123   while (hdr_size > 0) {
3124     ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3125     if (ret != GST_FLOW_OK)
3126       break;
3127   }
3129   return ret;
3131 not_enough_data:
3132   {
3133     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3134         ("short read parsing extended header object"));
3135     return GST_FLOW_ERROR;
3136   }
3139 static GstFlowReturn
3140 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3141     guint64 size)
3143   guint i;
3145   if (size < 2)
3146     goto not_enough_data;
3148   if (demux->languages) {
3149     GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3150     g_strfreev (demux->languages);
3151     demux->languages = NULL;
3152     demux->num_languages = 0;
3153   }
3155   demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3156   GST_LOG ("%u languages:", demux->num_languages);
3158   demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3159   for (i = 0; i < demux->num_languages; ++i) {
3160     guint8 len, *lang_data = NULL;
3162     if (size < 1)
3163       goto not_enough_data;
3164     len = gst_asf_demux_get_uint8 (&data, &size);
3165     if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3166       gchar *utf8;
3168       utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3169           NULL, NULL);
3171       /* truncate "en-us" etc. to just "en" */
3172       if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3173         utf8[2] = '\0';
3174       }
3175       GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3176       demux->languages[i] = utf8;
3177       g_free (lang_data);
3178     } else {
3179       goto not_enough_data;
3180     }
3181   }
3183   return GST_FLOW_OK;
3185 not_enough_data:
3186   {
3187     GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3188     g_free (demux->languages);
3189     demux->languages = NULL;
3190     return GST_FLOW_OK;         /* not fatal */
3191   }
3194 static GstFlowReturn
3195 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3196     guint64 size)
3198   GstClockTime interval;
3199   guint32 count, i;
3201   if (size < (16 + 8 + 4 + 4))
3202     goto not_enough_data;
3204   /* skip file id */
3205   gst_asf_demux_skip_bytes (16, &data, &size);
3206   interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3207   gst_asf_demux_skip_bytes (4, &data, &size);
3208   count = gst_asf_demux_get_uint32 (&data, &size);
3209   if (count > 0) {
3210     demux->sidx_interval = interval;
3211     demux->sidx_num_entries = count;
3212     g_free (demux->sidx_entries);
3213     demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3215     for (i = 0; i < count; ++i) {
3216       if (G_UNLIKELY (size <= 6))
3217         break;
3218       demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3219       demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3220       GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u  count : %2d",
3221           GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3222           demux->sidx_entries[i].count);
3223     }
3224   } else {
3225     GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3226   }
3228   return GST_FLOW_OK;
3230 not_enough_data:
3231   {
3232     GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3233     return GST_FLOW_OK;         /* not fatal */
3234   }
3237 static GstFlowReturn
3238 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3239     guint8 * data, guint64 size)
3241   ASFGuid guid;
3242   guint16 num, i;
3243   guint8 *mes;
3245   if (size < 16 + 2 + (2 * 2))
3246     goto not_enough_data;
3248   gst_asf_demux_get_guid (&guid, &data, &size);
3249   num = gst_asf_demux_get_uint16 (&data, &size);
3251   if (num < 2) {
3252     GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3253     return GST_FLOW_OK;
3254   }
3256   if (size < (num * sizeof (guint16)))
3257     goto not_enough_data;
3259   /* read mutually exclusive stream numbers */
3260   mes = g_new (guint8, num + 1);
3261   for (i = 0; i < num; ++i) {
3262     mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3263     GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3264   }
3266   /* add terminator so we can easily get the count or know when to stop */
3267   mes[i] = (guint8) - 1;
3269   demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3271   return GST_FLOW_OK;
3273   /* Errors */
3274 not_enough_data:
3275   {
3276     GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3277     return GST_FLOW_OK;         /* not absolutely fatal */
3278   }
3281 static GstFlowReturn
3282 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3283     guint64 size)
3285   AsfStreamExtProps esp;
3286   AsfStream *stream = NULL;
3287   AsfObject stream_obj;
3288   guint16 stream_name_count;
3289   guint16 num_payload_ext;
3290   guint64 len;
3291   guint8 *stream_obj_data = NULL;
3292   guint8 *data_start;
3293   guint obj_size;
3294   guint i, stream_num;
3296   data_start = data;
3297   obj_size = (guint) size;
3299   if (size < 64)
3300     goto not_enough_data;
3302   esp.valid = TRUE;
3303   esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3304   esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3305   esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3306   esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3307   esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3308   esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3309   esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3310   esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3311   esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3312   esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3313   stream_num = gst_asf_demux_get_uint16 (&data, &size);
3314   esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3315   esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3316   stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3317   num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3319   GST_INFO ("start_time             = %" GST_TIME_FORMAT,
3320       GST_TIME_ARGS (esp.start_time));
3321   GST_INFO ("end_time               = %" GST_TIME_FORMAT,
3322       GST_TIME_ARGS (esp.end_time));
3323   GST_INFO ("flags                  = %08x", esp.flags);
3324   GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3325       GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3326   GST_INFO ("stream number          = %u", stream_num);
3327   GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3328       (esp.lang_idx < demux->num_languages) ?
3329       GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3330   GST_INFO ("stream name count      = %u", stream_name_count);
3332   /* read stream names */
3333   for (i = 0; i < stream_name_count; ++i) {
3334     guint16 stream_lang_idx G_GNUC_UNUSED;
3335     gchar *stream_name = NULL;
3337     if (size < 2)
3338       goto not_enough_data;
3339     stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3340     if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3341       goto not_enough_data;
3342     GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3343     g_free (stream_name);       /* TODO: store names in struct */
3344   }
3346   /* read payload extension systems stuff */
3347   GST_LOG ("payload extension systems count = %u", num_payload_ext);
3349   if (num_payload_ext > 0)
3350     esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3351   else
3352     esp.payload_extensions = NULL;
3354   for (i = 0; i < num_payload_ext; ++i) {
3355     AsfPayloadExtension ext;
3356     ASFGuid ext_guid;
3357     guint32 sys_info_len;
3359     if (size < 16 + 2 + 4)
3360       goto not_enough_data;
3362     gst_asf_demux_get_guid (&ext_guid, &data, &size);
3363     ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3364     ext.len = gst_asf_demux_get_uint16 (&data, &size);
3366     sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3367     GST_LOG ("payload systems info len = %u", sys_info_len);
3368     if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3369       goto not_enough_data;
3371     esp.payload_extensions[i] = ext;
3372   }
3374   GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3376   /* there might be an optional STREAM_INFO object here now; if not, we
3377    * should have parsed the corresponding stream info object already (since
3378    * we are parsing the extended stream properties objects delayed) */
3379   if (size == 0) {
3380     stream = gst_asf_demux_get_stream (demux, stream_num);
3381     goto done;
3382   }
3384   /* get size of the stream object */
3385   if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3386     goto not_enough_data;
3388   if (stream_obj.id != ASF_OBJ_STREAM)
3389     goto expected_stream_object;
3391   if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3392       stream_obj.size > (10 * 1024 * 1024))
3393     goto not_enough_data;
3395   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3397   /* process this stream object later after all the other 'normal' ones
3398    * have been processed (since the others are more important/non-hidden) */
3399   len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3400   if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3401     goto not_enough_data;
3403   /* parse stream object */
3404   stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3405   g_free (stream_obj_data);
3407 done:
3409   if (stream) {
3410     stream->ext_props = esp;
3412     /* try to set the framerate */
3413     if (stream->is_video && stream->caps) {
3414       GValue framerate = { 0 };
3415       GstStructure *s;
3416       gint num, denom;
3418       g_value_init (&framerate, GST_TYPE_FRACTION);
3420       num = GST_SECOND / 100;
3421       denom = esp.avg_time_per_frame;
3422       if (denom == 0) {
3423         /* avoid division by 0, assume 25/1 framerate */
3424         denom = GST_SECOND / 2500;
3425       }
3427       gst_value_set_fraction (&framerate, num, denom);
3429       stream->caps = gst_caps_make_writable (stream->caps);
3430       s = gst_caps_get_structure (stream->caps, 0);
3431       gst_structure_set_value (s, "framerate", &framerate);
3432       g_value_unset (&framerate);
3433       GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3434           num, denom, ((gdouble) num) / denom);
3435     }
3437     /* add language info now if we have it */
3438     if (stream->ext_props.lang_idx < demux->num_languages) {
3439       if (stream->pending_tags == NULL)
3440         stream->pending_tags = gst_tag_list_new ();
3441       GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3442           demux->languages[stream->ext_props.lang_idx]);
3443       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3444           GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3445           NULL);
3446     }
3447   } else {
3448     GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3449   }
3451   return GST_FLOW_OK;
3453   /* Errors */
3454 not_enough_data:
3455   {
3456     GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3457     return GST_FLOW_OK;         /* not absolutely fatal */
3458   }
3459 expected_stream_object:
3460   {
3461     GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3462         "object: expected embedded stream object, but got %s object instead!",
3463         gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3464     return GST_FLOW_OK;         /* not absolutely fatal */
3465   }
3468 static const gchar *
3469 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3471   const gchar *nick;
3473   nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3474   if (g_str_has_prefix (nick, "ASF_OBJ_"))
3475     nick += strlen ("ASF_OBJ_");
3477   if (demux->objpath == NULL) {
3478     demux->objpath = g_strdup (nick);
3479   } else {
3480     gchar *newpath;
3482     newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3483     g_free (demux->objpath);
3484     demux->objpath = newpath;
3485   }
3487   return (const gchar *) demux->objpath;
3490 static void
3491 gst_asf_demux_pop_obj (GstASFDemux * demux)
3493   gchar *s;
3495   if ((s = g_strrstr (demux->objpath, "/"))) {
3496     *s = '\0';
3497   } else {
3498     g_free (demux->objpath);
3499     demux->objpath = NULL;
3500   }
3503 static void
3504 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3506   GSList *l;
3507   guint i;
3509   /* Parse the queued extended stream property objects and add the info
3510    * to the existing streams or add the new embedded streams, but without
3511    * activating them yet */
3512   GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3513       g_slist_length (demux->ext_stream_props));
3515   for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3516     GstBuffer *buf = GST_BUFFER (l->data);
3518     GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3519     gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
3520         GST_BUFFER_SIZE (buf));
3521     gst_buffer_unref (buf);
3522   }
3523   g_slist_free (demux->ext_stream_props);
3524   demux->ext_stream_props = NULL;
3527 #if 0
3528 static void
3529 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3531   guint i, j;
3533   for (i = 0; i < demux->num_streams; ++i) {
3534     AsfStream *stream;
3535     gboolean is_hidden;
3536     GSList *x;
3538     stream = &demux->stream[i];
3540     GST_LOG_OBJECT (demux, "checking  stream %2u", stream->id);
3542     if (stream->active) {
3543       GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3544       continue;
3545     }
3547     is_hidden = FALSE;
3548     for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3549       guint8 *mes;
3551       /* check for each mutual exclusion whether it affects this stream */
3552       for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3553         if (*mes == stream->id) {
3554           /* if yes, check if we've already added streams that are mutually
3555            * exclusive with the stream we're about to add */
3556           for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3557             for (j = 0; j < demux->num_streams; ++j) {
3558               /* if the broadcast flag is set, assume the hidden streams aren't
3559                * actually streamed and hide them (or playbin won't work right),
3560                * otherwise assume their data is available */
3561               if (demux->stream[j].id == *mes && demux->broadcast) {
3562                 is_hidden = TRUE;
3563                 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3564                     "mutually exclusive with already existing stream ID %d, "
3565                     "hiding stream", stream->id, demux->stream[j].id);
3566                 goto next;
3567               }
3568             }
3569           }
3570           break;
3571         }
3572       }
3573     }
3575   next:
3577     /* FIXME: we should do stream activation based on preroll data in
3578      * streaming mode too */
3579     if (demux->streaming && !is_hidden)
3580       gst_asf_demux_activate_stream (demux, stream);
3581   }
3583 #endif
3585 static GstFlowReturn
3586 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3587     guint64 * p_size)
3589   GstFlowReturn ret = GST_FLOW_OK;
3590   AsfObject obj;
3591   guint64 obj_data_size;
3593   if (*p_size < ASF_OBJECT_HEADER_SIZE)
3594     return ASF_FLOW_NEED_MORE_DATA;
3596   asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3597   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3599   obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3601   if (*p_size < obj_data_size)
3602     return ASF_FLOW_NEED_MORE_DATA;
3604   gst_asf_demux_push_obj (demux, obj.id);
3606   GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3608   switch (obj.id) {
3609     case ASF_OBJ_STREAM:
3610       gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3611       ret = GST_FLOW_OK;
3612       break;
3613     case ASF_OBJ_FILE:
3614       ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3615       break;
3616     case ASF_OBJ_HEADER:
3617       ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3618       break;
3619     case ASF_OBJ_COMMENT:
3620       ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3621       break;
3622     case ASF_OBJ_HEAD1:
3623       ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3624       break;
3625     case ASF_OBJ_BITRATE_PROPS:
3626       ret =
3627           gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3628           obj_data_size);
3629       break;
3630     case ASF_OBJ_EXT_CONTENT_DESC:
3631       ret =
3632           gst_asf_demux_process_ext_content_desc (demux, *p_data,
3633           obj_data_size);
3634       break;
3635     case ASF_OBJ_METADATA_OBJECT:
3636       ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3637       break;
3638     case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3639       GstBuffer *buf;
3641       /* process these later, we might not have parsed the corresponding
3642        * stream object yet */
3643       GST_LOG ("%s: queued for later parsing", demux->objpath);
3644       buf = gst_buffer_new_and_alloc (obj_data_size);
3645       memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3646       demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3647       ret = GST_FLOW_OK;
3648       break;
3649     }
3650     case ASF_OBJ_LANGUAGE_LIST:
3651       ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3652       break;
3653     case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3654       ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3655           obj_data_size);
3656       break;
3657     case ASF_OBJ_SIMPLE_INDEX:
3658       ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3659       break;
3660     case ASF_OBJ_CONTENT_ENCRYPTION:
3661     case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3662     case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3663     case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
3664       goto error_encrypted;
3665     case ASF_OBJ_CONCEAL_NONE:
3666     case ASF_OBJ_HEAD2:
3667     case ASF_OBJ_UNDEFINED:
3668     case ASF_OBJ_CODEC_COMMENT:
3669     case ASF_OBJ_INDEX:
3670     case ASF_OBJ_PADDING:
3671     case ASF_OBJ_BITRATE_MUTEX:
3672     case ASF_OBJ_COMPATIBILITY:
3673     case ASF_OBJ_INDEX_PLACEHOLDER:
3674     case ASF_OBJ_INDEX_PARAMETERS:
3675     case ASF_OBJ_STREAM_PRIORITIZATION:
3676     case ASF_OBJ_SCRIPT_COMMAND:
3677     default:
3678       /* Unknown/unhandled object, skip it and hope for the best */
3679       GST_INFO ("%s: skipping object", demux->objpath);
3680       ret = GST_FLOW_OK;
3681       break;
3682   }
3684   /* this can't fail, we checked the number of bytes available before */
3685   gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3687   GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3689   gst_asf_demux_pop_obj (demux);
3691   return ret;
3693 /* ERRORS */
3694 error_encrypted:
3695   {
3696     GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3697     return GST_FLOW_ERROR;
3698   }
3701 static void
3702 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3703     GstBuffer ** p_buffer)
3705   GstBuffer *descrambled_buffer;
3706   GstBuffer *scrambled_buffer;
3707   GstBuffer *sub_buffer;
3708   guint offset;
3709   guint off;
3710   guint row;
3711   guint col;
3712   guint idx;
3714   /* descrambled_buffer is initialised in the first iteration */
3715   descrambled_buffer = NULL;
3716   scrambled_buffer = *p_buffer;
3718   if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3719     return;
3721   for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3722       offset += demux->ds_chunk_size) {
3723     off = offset / demux->ds_chunk_size;
3724     row = off / demux->span;
3725     col = off % demux->span;
3726     idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3727     GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3728         col, off, demux->ds_chunk_size);
3729     GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3730         GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3731     GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3732         GST_BUFFER_SIZE (scrambled_buffer));
3733     sub_buffer =
3734         gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3735         demux->ds_chunk_size);
3736     if (!offset) {
3737       descrambled_buffer = sub_buffer;
3738     } else {
3739       descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3740     }
3741   }
3743   gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3744       GST_BUFFER_COPY_TIMESTAMPS);
3746   /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3748   gst_buffer_unref (scrambled_buffer);
3749   *p_buffer = descrambled_buffer;
3752 static gboolean
3753 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3755   GstASFDemux *demux = GST_ASF_DEMUX (element);
3756   gint i;
3758   GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3760   for (i = 0; i < demux->num_streams; ++i) {
3761     gst_event_ref (event);
3762     if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3763       gst_event_unref (event);
3764       return TRUE;
3765     }
3766   }
3768   gst_event_unref (event);
3769   return FALSE;
3772 /* takes ownership of the passed event */
3773 static gboolean
3774 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3776   gboolean ret = TRUE;
3777   gint i;
3779   GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3780       GST_EVENT_TYPE_NAME (event));
3782   for (i = 0; i < demux->num_streams; ++i) {
3783     gst_event_ref (event);
3784     ret &= gst_pad_push_event (demux->stream[i].pad, event);
3785   }
3786   gst_event_unref (event);
3787   return ret;
3790 static const GstQueryType *
3791 gst_asf_demux_get_src_query_types (GstPad * pad)
3793   static const GstQueryType types[] = {
3794     GST_QUERY_POSITION,
3795     GST_QUERY_DURATION,
3796     GST_QUERY_SEEKING,
3797     0
3798   };
3800   return types;
3803 static gboolean
3804 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3806   GstASFDemux *demux;
3807   gboolean res = FALSE;
3809   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3811   GST_DEBUG ("handling %s query",
3812       gst_query_type_get_name (GST_QUERY_TYPE (query)));
3814   switch (GST_QUERY_TYPE (query)) {
3815     case GST_QUERY_DURATION:
3816     {
3817       GstFormat format;
3819       gst_query_parse_duration (query, &format, NULL);
3821       if (format != GST_FORMAT_TIME) {
3822         GST_LOG ("only support duration queries in TIME format");
3823         break;
3824       }
3826       GST_OBJECT_LOCK (demux);
3828       if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3829         GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3830             GST_TIME_ARGS (demux->segment.duration));
3832         gst_query_set_duration (query, GST_FORMAT_TIME,
3833             demux->segment.duration);
3835         res = TRUE;
3836       } else {
3837         GST_LOG ("duration not known yet");
3838       }
3840       GST_OBJECT_UNLOCK (demux);
3841       break;
3842     }
3844     case GST_QUERY_POSITION:{
3845       GstFormat format;
3847       gst_query_parse_position (query, &format, NULL);
3849       if (format != GST_FORMAT_TIME) {
3850         GST_LOG ("only support position queries in TIME format");
3851         break;
3852       }
3854       GST_OBJECT_LOCK (demux);
3856       if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3857         GST_LOG ("returning position: %" GST_TIME_FORMAT,
3858             GST_TIME_ARGS (demux->segment.last_stop));
3860         gst_query_set_position (query, GST_FORMAT_TIME,
3861             demux->segment.last_stop);
3863         res = TRUE;
3864       } else {
3865         GST_LOG ("position not known yet");
3866       }
3868       GST_OBJECT_UNLOCK (demux);
3869       break;
3870     }
3872     case GST_QUERY_SEEKING:{
3873       GstFormat format;
3875       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3876       if (format == GST_FORMAT_TIME) {
3877         gint64 duration;
3879         GST_OBJECT_LOCK (demux);
3880         duration = demux->segment.duration;
3881         GST_OBJECT_UNLOCK (demux);
3883         if (!demux->streaming || !demux->seekable) {
3884           gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3885               duration);
3886           res = TRUE;
3887         } else {
3888           GstFormat fmt;
3889           gboolean seekable;
3891           /* try downstream first in TIME */
3892           res = gst_pad_query_default (pad, query);
3894           gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3895           GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3896               GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3897           /* if no luck, maybe in BYTES */
3898           if (!seekable || fmt != GST_FORMAT_TIME) {
3899             GstQuery *q;
3901             q = gst_query_new_seeking (GST_FORMAT_BYTES);
3902             if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3903               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3904               GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3905                   GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3906               if (fmt != GST_FORMAT_BYTES)
3907                 seekable = FALSE;
3908             }
3909             gst_query_unref (q);
3910             gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3911                 duration);
3912             res = TRUE;
3913           }
3914         }
3915       } else
3916         GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3917       break;
3918     }
3920     case GST_QUERY_LATENCY:
3921     {
3922       gboolean live;
3923       GstClockTime min, max;
3925       /* preroll delay does not matter in non-live pipeline,
3926        * but we might end up in a live (rtsp) one ... */
3928       /* first forward */
3929       res = gst_pad_query_default (pad, query);
3930       if (!res)
3931         break;
3933       gst_query_parse_latency (query, &live, &min, &max);
3935       GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
3936           GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3937           GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3939       GST_OBJECT_LOCK (demux);
3940       if (min != -1)
3941         min += demux->latency;
3942       if (max != -1)
3943         max += demux->latency;
3944       GST_OBJECT_UNLOCK (demux);
3946       gst_query_set_latency (query, live, min, max);
3947       break;
3948     }
3949     default:
3950       res = gst_pad_query_default (pad, query);
3951       break;
3952   }
3954   gst_object_unref (demux);
3955   return res;
3958 static GstStateChangeReturn
3959 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3961   GstASFDemux *demux = GST_ASF_DEMUX (element);
3962   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3964   switch (transition) {
3965     case GST_STATE_CHANGE_NULL_TO_READY:{
3966       gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3967       demux->need_newsegment = TRUE;
3968       demux->segment_running = FALSE;
3969       demux->accurate = FALSE;
3970       demux->adapter = gst_adapter_new ();
3971       demux->metadata = gst_caps_new_empty ();
3972       demux->global_metadata = gst_structure_empty_new ("metadata");
3973       demux->data_size = 0;
3974       demux->data_offset = 0;
3975       demux->index_offset = 0;
3976       demux->base_offset = 0;
3977       break;
3978     }
3979     default:
3980       break;
3981   }
3983   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3984   if (ret == GST_STATE_CHANGE_FAILURE)
3985     return ret;
3987   switch (transition) {
3988     case GST_STATE_CHANGE_PAUSED_TO_READY:
3989     case GST_STATE_CHANGE_READY_TO_NULL:
3990       gst_asf_demux_reset (demux, FALSE);
3991       break;
3992     default:
3993       break;
3994   }
3996   return ret;