]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugins-ugly0-10.git/blob - gst/asfdemux/gstasfdemux.c
asfdemux: Use GST_STR_NULL in a couple of places.
[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);
110 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
112 static void
113 gst_asf_demux_base_init (gpointer g_class)
115   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
116   static GstElementDetails gst_asf_demux_details = {
117     "ASF Demuxer",
118     "Codec/Demuxer",
119     "Demultiplexes ASF Streams",
120     "Owen Fraser-Green <owen@discobabe.net>"
121   };
123   gst_element_class_add_pad_template (element_class,
124       gst_static_pad_template_get (&audio_src_template));
125   gst_element_class_add_pad_template (element_class,
126       gst_static_pad_template_get (&video_src_template));
127   gst_element_class_add_pad_template (element_class,
128       gst_static_pad_template_get (&gst_asf_demux_sink_template));
130   gst_element_class_set_details (element_class, &gst_asf_demux_details);
133 static void
134 gst_asf_demux_class_init (GstASFDemuxClass * klass)
136   GstElementClass *gstelement_class;
138   gstelement_class = (GstElementClass *) klass;
140   gstelement_class->change_state =
141       GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
142   gstelement_class->send_event =
143       GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
146 static void
147 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
149   gst_caps_replace (&stream->caps, NULL);
150   if (stream->pending_tags) {
151     gst_tag_list_free (stream->pending_tags);
152     stream->pending_tags = NULL;
153   }
154   if (stream->pad) {
155     if (stream->active)
156       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
157     else
158       gst_object_unref (stream->pad);
159     stream->pad = NULL;
160   }
161   if (stream->payloads) {
162     g_array_free (stream->payloads, TRUE);
163     stream->payloads = NULL;
164   }
165   if (stream->ext_props.valid) {
166     g_free (stream->ext_props.payload_extensions);
167     stream->ext_props.payload_extensions = NULL;
168   }
171 static void
172 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
174   GST_LOG_OBJECT (demux, "resetting");
176   gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
177   demux->segment_running = FALSE;
178   if (demux->adapter && !chain_reset) {
179     gst_adapter_clear (demux->adapter);
180     g_object_unref (demux->adapter);
181     demux->adapter = NULL;
182   }
183   if (demux->taglist) {
184     gst_tag_list_free (demux->taglist);
185     demux->taglist = NULL;
186   }
187   if (demux->metadata) {
188     gst_caps_unref (demux->metadata);
189     demux->metadata = NULL;
190   }
191   if (demux->global_metadata) {
192     gst_structure_free (demux->global_metadata);
193     demux->global_metadata = NULL;
194   }
196   demux->state = GST_ASF_DEMUX_STATE_HEADER;
197   g_free (demux->objpath);
198   demux->objpath = NULL;
199   g_strfreev (demux->languages);
200   demux->languages = NULL;
201   demux->num_languages = 0;
202   g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
203       NULL);
204   g_slist_free (demux->ext_stream_props);
205   demux->ext_stream_props = NULL;
207   while (demux->old_num_streams > 0) {
208     gst_asf_demux_free_stream (demux,
209         &demux->old_stream[demux->old_num_streams - 1]);
210     --demux->old_num_streams;
211   }
212   memset (demux->old_stream, 0, sizeof (demux->old_stream));
213   demux->old_num_streams = 0;
215   /* when resetting for a new chained asf, we don't want to remove the pads
216    * before adding the new ones */
217   if (chain_reset) {
218     memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
219     demux->old_num_streams = demux->num_streams;
220     demux->num_streams = 0;
221   }
223   while (demux->num_streams > 0) {
224     gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
225     --demux->num_streams;
226   }
227   memset (demux->stream, 0, sizeof (demux->stream));
228   if (!chain_reset) {
229     /* do not remove those for not adding pads with same name */
230     demux->num_audio_streams = 0;
231     demux->num_video_streams = 0;
232   }
233   demux->num_streams = 0;
234   demux->activated_streams = FALSE;
235   demux->first_ts = GST_CLOCK_TIME_NONE;
236   demux->segment_ts = GST_CLOCK_TIME_NONE;
237   demux->in_gap = 0;
238   if (!chain_reset)
239     gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
240   demux->state = GST_ASF_DEMUX_STATE_HEADER;
241   demux->seekable = FALSE;
242   demux->broadcast = FALSE;
243   demux->sidx_interval = 0;
244   demux->sidx_num_entries = 0;
245   g_free (demux->sidx_entries);
246   demux->sidx_entries = NULL;
248   demux->speed_packets = 1;
250   if (chain_reset) {
251     GST_LOG_OBJECT (demux, "Restarting");
252     gst_segment_init (&demux->segment, GST_FORMAT_TIME);
253     demux->need_newsegment = TRUE;
254     demux->segment_running = FALSE;
255     demux->accurate = FALSE;
256     demux->metadata = gst_caps_new_empty ();
257     demux->global_metadata = gst_structure_empty_new ("metadata");
258     demux->data_size = 0;
259     demux->data_offset = 0;
260     demux->index_offset = 0;
261   } else {
262     demux->base_offset = 0;
263   }
266 static void
267 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
269   demux->sinkpad =
270       gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
271   gst_pad_set_chain_function (demux->sinkpad,
272       GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
273   gst_pad_set_event_function (demux->sinkpad,
274       GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
275   gst_pad_set_activate_function (demux->sinkpad,
276       GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
277   gst_pad_set_activatepull_function (demux->sinkpad,
278       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
279   gst_pad_set_activatepush_function (demux->sinkpad,
280       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
281   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
283   /* set initial state */
284   gst_asf_demux_reset (demux, FALSE);
287 static gboolean
288 gst_asf_demux_activate (GstPad * sinkpad)
290   if (gst_pad_check_pull_range (sinkpad)) {
291     return gst_pad_activate_pull (sinkpad, TRUE);
292   } else {
293     return gst_pad_activate_push (sinkpad, TRUE);
294   }
297 static gboolean
298 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
300   GstASFDemux *demux;
302   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
304   demux->state = GST_ASF_DEMUX_STATE_HEADER;
305   demux->streaming = TRUE;
307   return TRUE;
310 static gboolean
311 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
313   GstASFDemux *demux;
315   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
317   if (active) {
318     demux->state = GST_ASF_DEMUX_STATE_HEADER;
319     demux->streaming = FALSE;
321     return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
322         demux);
323   } else {
324     return gst_pad_stop_task (pad);
325   }
329 static gboolean
330 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
332   GstASFDemux *demux;
333   gboolean ret = TRUE;
335   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
337   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
338   switch (GST_EVENT_TYPE (event)) {
339     case GST_EVENT_NEWSEGMENT:{
340       GstFormat newsegment_format;
341       gint64 newsegment_start, stop, time;
342       gdouble rate, arate;
343       gboolean update;
345       gst_event_parse_new_segment_full (event, &update, &rate, &arate,
346           &newsegment_format, &newsegment_start, &stop, &time);
348       if (newsegment_format == GST_FORMAT_BYTES) {
349         if (demux->packet_size && newsegment_start > demux->data_offset)
350           demux->packet = (newsegment_start - demux->data_offset) /
351               demux->packet_size;
352         else
353           demux->packet = 0;
354       } else if (newsegment_format == GST_FORMAT_TIME) {
355         /* do not know packet position, not really a problem */
356         demux->packet = -1;
357       } else {
358         GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
359         gst_event_unref (event);
360         break;
361       }
363       /* record upstream segment for interpolation */
364       if (newsegment_format != demux->in_segment.format)
365         gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
366       gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate,
367           newsegment_format, newsegment_start, stop, time);
369       /* in either case, clear some state and generate newsegment later on */
370       GST_OBJECT_LOCK (demux);
371       demux->segment_ts = GST_CLOCK_TIME_NONE;
372       demux->in_gap = GST_CLOCK_TIME_NONE;
373       demux->need_newsegment = TRUE;
374       gst_asf_demux_reset_stream_state_after_discont (demux);
375       GST_OBJECT_UNLOCK (demux);
377       gst_event_unref (event);
378       break;
379     }
380     case GST_EVENT_EOS:{
381       if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
382         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
383             (_("This stream contains no data.")),
384             ("got eos and didn't receive a complete header object"));
385         break;
386       }
387       GST_OBJECT_LOCK (demux);
388       gst_adapter_clear (demux->adapter);
389       GST_OBJECT_UNLOCK (demux);
390       gst_asf_demux_send_event_unlocked (demux, event);
391       break;
392     }
394     case GST_EVENT_FLUSH_STOP:
395       GST_OBJECT_LOCK (demux);
396       gst_asf_demux_reset_stream_state_after_discont (demux);
397       GST_OBJECT_UNLOCK (demux);
398       gst_asf_demux_send_event_unlocked (demux, event);
399       /* upon activation, latency is no longer introduced, e.g. after seek */
400       if (demux->activated_streams)
401         demux->latency = 0;
402       break;
404     default:
405       ret = gst_pad_event_default (pad, event);
406       break;
407   }
409   gst_object_unref (demux);
410   return ret;
413 static gboolean
414 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
415     GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
417   GstClockTime idx_time;
418   guint idx;
420   if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
421     return FALSE;
423   idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
425   /* FIXME: seek beyond end of file should result in immediate EOS from
426    * streaming thread instead of a failed seek */
427   if (G_UNLIKELY (idx >= demux->sidx_num_entries))
428     return FALSE;
430   *packet = demux->sidx_entries[idx].packet;
431   if (speed)
432     *speed = demux->sidx_entries[idx].count;
434   /* so we get closer to the actual time of the packet ... actually, let's not
435    * do this, since we throw away superfluous payloads before the seek position
436    * anyway; this way, our key unit seek 'snap resolution' is a bit better
437    * (ie. same as index resolution) */
438   /*
439      while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
440      --idx;
441    */
443   idx_time = demux->sidx_interval * idx;
444   if (G_LIKELY (idx_time >= demux->preroll))
445     idx_time -= demux->preroll;
447   GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
448       GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
449       GST_TIME_ARGS (idx_time));
451   if (G_LIKELY (p_idx_time))
452     *p_idx_time = idx_time;
454   return TRUE;
457 static void
458 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
460   guint n;
462   gst_adapter_clear (demux->adapter);
464   GST_DEBUG_OBJECT (demux, "reset stream state");
466   for (n = 0; n < demux->num_streams; n++) {
467     demux->stream[n].discont = TRUE;
468     demux->stream[n].last_flow = GST_FLOW_OK;
470     while (demux->stream[n].payloads->len > 0) {
471       AsfPayload *payload;
472       guint last;
474       last = demux->stream[n].payloads->len - 1;
475       payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
476       gst_buffer_replace (&payload->buf, NULL);
477       g_array_remove_index (demux->stream[n].payloads, last);
478     }
479   }
482 static void
483 gst_asf_demux_mark_discont (GstASFDemux * demux)
485   guint n;
487   GST_DEBUG_OBJECT (demux, "Mark stream discont");
489   for (n = 0; n < demux->num_streams; n++)
490     demux->stream[n].discont = TRUE;
493 /* do a seek in push based mode */
494 static gboolean
495 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
497   gdouble rate;
498   GstFormat format;
499   GstSeekFlags flags;
500   GstSeekType cur_type, stop_type;
501   gint64 cur, stop;
502   guint packet;
503   gboolean res;
505   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
506       &stop_type, &stop);
508   stop_type = GST_SEEK_TYPE_NONE;
509   stop = -1;
511   GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
513   /* determine packet, by index or by estimation */
514   if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
515     packet = (guint) gst_util_uint64_scale (demux->num_packets,
516         cur, demux->play_time);
517   }
519   if (packet > demux->num_packets) {
520     GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
521         "seek aborted.");
522     return FALSE;
523   }
525   GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
527   cur = demux->data_offset + (packet * demux->packet_size);
529   GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
530       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
531   /* BYTE seek event */
532   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
533       stop_type, stop);
534   res = gst_pad_push_event (demux->sinkpad, event);
536   return res;
539 static gboolean
540 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
542   GstClockTime idx_time;
543   GstSegment segment;
544   GstSeekFlags flags;
545   GstSeekType cur_type, stop_type;
546   GstFormat format;
547   gboolean only_need_update;
548   gboolean keyunit_sync;
549   gboolean flush;
550   gdouble rate;
551   gint64 cur, stop;
552   gint64 seek_time;
553   guint packet, speed_count = 1;
555   if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
556           demux->num_packets == 0 || demux->play_time == 0)) {
557     GST_LOG_OBJECT (demux, "stream is not seekable");
558     return FALSE;
559   }
561   if (G_UNLIKELY (!demux->activated_streams)) {
562     GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
563     return FALSE;
564   }
566   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
567       &stop_type, &stop);
569   if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
570     GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
571     return FALSE;
572   }
574   if (G_UNLIKELY (rate <= 0.0)) {
575     GST_LOG_OBJECT (demux, "backward playback is not supported yet");
576     return FALSE;
577   }
579   flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
580   demux->accurate =
581       ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
582   keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
584   if (G_UNLIKELY (demux->streaming)) {
585     /* support it safely needs more segment handling, e.g. closing etc */
586     if (!flush) {
587       GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
588       return FALSE;
589     }
590     /* we can (re)construct the start later on, but not the end */
591     if (stop_type != GST_SEEK_TYPE_NONE) {
592       GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
593       return FALSE;
594     }
595     gst_event_ref (event);
596     /* upstream might handle TIME seek, e.g. mms or rtsp,
597      * or not, e.g. http, then we give it a hand */
598     if (!gst_pad_push_event (demux->sinkpad, event))
599       return gst_asf_demux_handle_seek_push (demux, event);
600     else
601       return TRUE;
602   }
604   /* unlock the streaming thread */
605   if (G_LIKELY (flush)) {
606     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
607     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
608   } else {
609     gst_pad_pause_task (demux->sinkpad);
610   }
612   /* grab the stream lock so that streaming cannot continue, for
613    * non flushing seeks when the element is in PAUSED this could block
614    * forever */
615   GST_PAD_STREAM_LOCK (demux->sinkpad);
617   /* we now can stop flushing, since we have the stream lock now */
618   gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
620   if (G_LIKELY (flush))
621     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
623   /* operating on copy of segment until we know the seek worked */
624   segment = demux->segment;
626   if (G_UNLIKELY (demux->segment_running && !flush)) {
627     GstEvent *newseg;
629     /* create the segment event to close the current segment */
630     newseg = gst_event_new_new_segment (TRUE, segment.rate,
631         GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
633     gst_asf_demux_send_event_unlocked (demux, newseg);
634   }
636   gst_segment_set_seek (&segment, rate, format, flags, cur_type,
637       cur, stop_type, stop, &only_need_update);
639   GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
640       "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
642   seek_time = segment.start;
644   /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
645    * real start of data and segment_start to indexed time for key unit seek*/
646   if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
647               &idx_time, &speed_count))) {
648     /* First try to query our source to see if it can convert for us. This is
649        the case when our source is an mms stream, notice that in this case
650        gstmms will do a time based seek to get the byte offset, this is not a
651        problem as the seek to this offset needs to happen anway. */
652     gint64 offset;
653     GstFormat dest_format = GST_FORMAT_BYTES;
655     if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
656             &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
657       packet = (offset - demux->data_offset) / demux->packet_size;
658       GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
659           " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
660           G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
661           GST_TIME_ARGS (seek_time), offset, demux->data_offset,
662           demux->packet_size, packet);
663     } else {
664       /* Hackety hack, this sucks. We just seek to an earlier position
665        *  and let the sinks throw away the stuff before the segment start */
666       if (flush && (demux->accurate || keyunit_sync)) {
667         seek_time -= 5 * GST_SECOND;
668         if (seek_time < 0)
669           seek_time = 0;
670       }
672       packet = (guint) gst_util_uint64_scale (demux->num_packets,
673           seek_time, demux->play_time);
675       if (packet > demux->num_packets)
676         packet = demux->num_packets;
677     }
678   } else {
679     if (G_LIKELY (keyunit_sync)) {
680       GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
681           GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
682           GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
683       segment.start = idx_time;
684       segment.last_stop = idx_time;
685       segment.time = idx_time;
686     }
687   }
689   GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
691   GST_OBJECT_LOCK (demux);
692   demux->segment = segment;
693   demux->packet = packet;
694   demux->need_newsegment = TRUE;
695   demux->speed_packets = speed_count;
696   gst_asf_demux_reset_stream_state_after_discont (demux);
697   GST_OBJECT_UNLOCK (demux);
699   /* restart our task since it might have been stopped when we did the flush */
700   gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
701       demux);
703   /* streaming can continue now */
704   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
706   return TRUE;
709 static gboolean
710 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
712   GstASFDemux *demux;
713   gboolean ret;
715   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
717   switch (GST_EVENT_TYPE (event)) {
718     case GST_EVENT_SEEK:
719       GST_LOG_OBJECT (pad, "seek event");
720       ret = gst_asf_demux_handle_seek_event (demux, event);
721       gst_event_unref (event);
722       break;
723     case GST_EVENT_QOS:
724     case GST_EVENT_NAVIGATION:
725       /* just drop these two silently */
726       gst_event_unref (event);
727       ret = FALSE;
728       break;
729     default:
730       GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
731       ret = gst_pad_event_default (pad, event);
732       break;
733   }
735   gst_object_unref (demux);
736   return ret;
739 static inline guint32
740 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
742   guint32 ret;
744   ret = gst_asf_identify_guid (guids, guid);
746   GST_LOG ("%s  0x%08x-0x%08x-0x%08x-0x%08x",
747       gst_asf_get_guid_nick (guids, ret),
748       guid->v1, guid->v2, guid->v3, guid->v4);
750   return ret;
753 typedef struct
755   AsfObjectID id;
756   guint64 size;
757 } AsfObject;
760 /* expect is true when the user is expeting an object,
761  * when false, it will give no warnings if the object
762  * is not identified
763  */
764 static gboolean
765 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
766     guint data_len, AsfObject * object, gboolean expect)
768   ASFGuid guid;
770   if (data_len < ASF_OBJECT_HEADER_SIZE)
771     return FALSE;
773   guid.v1 = GST_READ_UINT32_LE (data + 0);
774   guid.v2 = GST_READ_UINT32_LE (data + 4);
775   guid.v3 = GST_READ_UINT32_LE (data + 8);
776   guid.v4 = GST_READ_UINT32_LE (data + 12);
778   object->size = GST_READ_UINT64_LE (data + 16);
780   /* FIXME: make asf_demux_identify_object_guid() */
781   object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
782   if (object->id == ASF_OBJ_UNDEFINED && expect) {
783     GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
784         guid.v1, guid.v2, guid.v3, guid.v4);
785   }
787   return TRUE;
790 static void
791 gst_asf_demux_release_old_pads (GstASFDemux * demux)
793   GST_DEBUG_OBJECT (demux, "Releasing old pads");
795   while (demux->old_num_streams > 0) {
796     gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
797         gst_event_new_eos ());
798     gst_asf_demux_free_stream (demux,
799         &demux->old_stream[demux->old_num_streams - 1]);
800     --demux->old_num_streams;
801   }
802   memset (demux->old_stream, 0, sizeof (demux->old_stream));
803   demux->old_num_streams = 0;
806 static GstFlowReturn
807 gst_asf_demux_chain_headers (GstASFDemux * demux)
809   GstFlowReturn flow;
810   AsfObject obj;
811   guint8 *header_data, *data = NULL;
812   const guint8 *cdata = NULL;
813   guint64 header_size;
815   cdata = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
816   if (cdata == NULL)
817     goto need_more_data;
819   asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
820   if (obj.id != ASF_OBJ_HEADER)
821     goto wrong_type;
823   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
825   /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
826   if (gst_adapter_available (demux->adapter) < obj.size + 50)
827     goto need_more_data;
829   data = gst_adapter_take (demux->adapter, obj.size + 50);
831   header_data = data;
832   header_size = obj.size;
833   flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
834   if (flow != GST_FLOW_OK)
835     goto parse_failed;
837   /* calculate where the packet data starts */
838   demux->data_offset = obj.size + 50;
840   /* now parse the beginning of the ASF_OBJ_DATA object */
841   if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
842     goto wrong_type;
844   if (demux->num_streams == 0)
845     goto no_streams;
847   g_free (data);
848   return GST_FLOW_OK;
850 /* NON-FATAL */
851 need_more_data:
852   {
853     GST_LOG_OBJECT (demux, "not enough data in adapter yet");
854     return GST_FLOW_OK;
855   }
857 /* ERRORS */
858 wrong_type:
859   {
860     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
861         ("This doesn't seem to be an ASF file"));
862     g_free (data);
863     return GST_FLOW_ERROR;
864   }
865 no_streams:
866 parse_failed:
867   {
868     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
869         ("header parsing failed, or no streams found, flow = %s",
870             gst_flow_get_name (flow)));
871     g_free (data);
872     return GST_FLOW_ERROR;
873   }
876 static GstFlowReturn
877 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux)
879   int i;
880   GST_DEBUG_OBJECT (demux, "Aggregating");
882   for (i = 0; i < demux->num_streams; i++) {
883     if (demux->stream[i].active) {
884       GstFlowReturn flowret = demux->stream[i].last_flow;
885       GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
886           gst_flow_get_name (flowret));
887       if (flowret != GST_FLOW_NOT_LINKED)
888         return flowret;
889     }
890   }
892   /* If we got here, then all our active streams are not linked */
893   return GST_FLOW_NOT_LINKED;
896 static gboolean
897 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
898     GstBuffer ** p_buf, GstFlowReturn * p_flow)
900   GstFlowReturn flow;
902   GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
903       offset, size);
905   flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
907   if (G_LIKELY (p_flow))
908     *p_flow = flow;
910   if (G_UNLIKELY (flow != GST_FLOW_OK)) {
911     GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
912         "+%u", gst_flow_get_name (flow), offset, size);
913     *p_buf = NULL;
914     return FALSE;
915   }
917   g_assert (*p_buf != NULL);
919   if (G_UNLIKELY (GST_BUFFER_SIZE (*p_buf) < size)) {
920     GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
921         "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
922     gst_buffer_unref (*p_buf);
923     if (G_LIKELY (p_flow))
924       *p_flow = GST_FLOW_UNEXPECTED;
925     *p_buf = NULL;
926     return FALSE;
927   }
929   return TRUE;
932 static void
933 gst_asf_demux_pull_indices (GstASFDemux * demux)
935   GstBuffer *buf = NULL;
936   guint64 offset;
937   guint num_read = 0;
939   offset = demux->index_offset;
941   if (G_UNLIKELY (offset == 0)) {
942     GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
943     return;
944   }
946   while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
947     GstFlowReturn flow;
948     AsfObject obj;
950     asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
951     gst_buffer_replace (&buf, NULL);
953     /* check for sanity */
954     if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
955       GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
956       break;
957     }
959     if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
960                 NULL)))
961       break;
963     GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
964         ", size %u", offset, (guint) obj.size);
966     offset += obj.size;         /* increase before _process_object changes it */
968     flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
969     gst_buffer_replace (&buf, NULL);
971     if (G_UNLIKELY (flow != GST_FLOW_OK))
972       break;
974     ++num_read;
975   }
976   GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
979 static gboolean
980 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
982   AsfObject obj;
984   asf_demux_peek_object (demux, data, 50, &obj, TRUE);
985   if (obj.id != ASF_OBJ_DATA) {
986     GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
987     return FALSE;
988   }
990   demux->state = GST_ASF_DEMUX_STATE_DATA;
992   if (!demux->broadcast && obj.size > 50) {
993     demux->data_size = obj.size - 50;
994     /* CHECKME: for at least one file this is off by +158 bytes?! */
995     demux->index_offset = demux->data_offset + demux->data_size;
996   } else {
997     demux->data_size = 0;
998     demux->index_offset = 0;
999   }
1001   demux->packet = 0;
1003   if (!demux->broadcast) {
1004     /* skip object header (24 bytes) and file GUID (16 bytes) */
1005     demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1006   } else {
1007     demux->num_packets = 0;
1008   }
1010   if (demux->num_packets == 0)
1011     demux->seekable = FALSE;
1013   /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1014   if (demux->data_size == 0 && demux->num_packets > 0) {
1015     demux->data_size = demux->num_packets * demux->packet_size;
1016     demux->index_offset = demux->data_offset + demux->data_size;
1017   }
1019   /* process pending stream objects and create pads for those */
1020   gst_asf_demux_process_queued_extended_stream_objects (demux);
1022   GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1023       "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1024       ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1025       demux->data_offset, demux->data_size, demux->index_offset);
1027   return TRUE;
1030 static gboolean
1031 gst_asf_demux_pull_headers (GstASFDemux * demux)
1033   GstFlowReturn flow;
1034   AsfObject obj;
1035   GstBuffer *buf = NULL;
1036   guint64 size;
1038   GST_LOG_OBJECT (demux, "reading headers");
1040   /* pull HEADER object header, so we know its size */
1041   if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1042     goto read_failed;
1044   asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
1045   gst_buffer_replace (&buf, NULL);
1047   if (obj.id != ASF_OBJ_HEADER)
1048     goto wrong_type;
1050   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1052   /* pull HEADER object */
1053   if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1054           NULL))
1055     goto read_failed;
1057   size = obj.size;              /* don't want obj.size changed */
1058   flow = gst_asf_demux_process_object (demux, &buf->data, &size);
1059   gst_buffer_replace (&buf, NULL);
1061   if (flow != GST_FLOW_OK) {
1062     GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1063     goto parse_failed;
1064   }
1066   /* calculate where the packet data starts */
1067   demux->data_offset = demux->base_offset + obj.size + 50;
1069   /* now pull beginning of DATA object before packet data */
1070   if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1071           NULL))
1072     goto read_failed;
1074   if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
1075     goto wrong_type;
1077   if (demux->num_streams == 0)
1078     goto no_streams;
1080   gst_buffer_replace (&buf, NULL);
1081   return TRUE;
1083 /* ERRORS */
1084 wrong_type:
1085   {
1086     gst_buffer_replace (&buf, NULL);
1087     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1088         ("This doesn't seem to be an ASF file"));
1089     return FALSE;
1090   }
1091 no_streams:
1092 read_failed:
1093 parse_failed:
1094   {
1095     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1096     return FALSE;
1097   }
1100 static gboolean
1101 all_streams_prerolled (GstASFDemux * demux)
1103   GstClockTime preroll_time;
1104   guint i, num_no_data = 0;
1106   preroll_time = demux->preroll;
1108   /* returns TRUE as long as there isn't a stream which (a) has data queued
1109    * and (b) the timestamp of last piece of data queued is < demux->preroll
1110    * AND there is at least one other stream with data queued */
1111   for (i = 0; i < demux->num_streams; ++i) {
1112     AsfPayload *last_payload;
1113     AsfStream *stream;
1114     guint last_idx;
1116     stream = &demux->stream[i];
1117     if (G_UNLIKELY (stream->payloads->len == 0)) {
1118       ++num_no_data;
1119       GST_LOG_OBJECT (stream->pad, "no data queued");
1120       continue;
1121     }
1123     last_idx = stream->payloads->len - 1;
1124     last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1126     GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1127         GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1128         GST_TIME_ARGS (preroll_time));
1129     if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1130       GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1131       return FALSE;
1132     }
1133   }
1135   if (G_UNLIKELY (num_no_data == demux->num_streams))
1136     return FALSE;
1138   return TRUE;
1141 #if 0
1142 static gboolean
1143 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1144     AsfStream * stream)
1146   GSList *l;
1148   for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1149     guint8 *mes;
1151     /* check for each mutual exclusion group whether it affects this stream */
1152     for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1153       if (*mes == stream->id) {
1154         /* we are in this group; let's check if we've already activated streams
1155          * that are in the same group (and hence mutually exclusive to this
1156          * one) */
1157         for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1158           guint i;
1160           for (i = 0; i < demux->num_streams; ++i) {
1161             if (demux->stream[i].id == *mes && demux->stream[i].active) {
1162               GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1163                   "to already active stream with ID %d", stream->id,
1164                   demux->stream[i].id);
1165               return TRUE;
1166             }
1167           }
1168         }
1169         /* we can only be in this group once, let's break out and move on to
1170          * the next mutual exclusion group */
1171         break;
1172       }
1173     }
1174   }
1176   return FALSE;
1178 #endif
1180 static gboolean
1181 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1183   guint i;
1185   if (demux->activated_streams)
1186     return TRUE;
1188   if (!all_streams_prerolled (demux) && !force) {
1189     GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1190     return FALSE;
1191   }
1193   for (i = 0; i < demux->num_streams; ++i) {
1194     AsfStream *stream = &demux->stream[i];
1196     if (stream->payloads->len > 0) {
1197       /* we don't check mutual exclusion stuff here; either we have data for
1198        * a stream, then we active it, or we don't, then we'll ignore it */
1199       GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1200       gst_asf_demux_activate_stream (demux, stream);
1201     } else {
1202       GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1203     }
1204   }
1206   gst_asf_demux_release_old_pads (demux);
1208   demux->activated_streams = TRUE;
1209   GST_LOG_OBJECT (demux, "signalling no more pads");
1210   gst_element_no_more_pads (GST_ELEMENT (demux));
1211   return TRUE;
1214 /* returns the stream that has a complete payload with the lowest timestamp
1215  * queued, or NULL (we push things by timestamp because during the internal
1216  * prerolling we might accumulate more data then the external queues can take,
1217  * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1218 static AsfStream *
1219 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1221   AsfPayload *best_payload = NULL;
1222   AsfStream *best_stream = NULL;
1223   guint i;
1225   for (i = 0; i < demux->num_streams; ++i) {
1226     AsfStream *stream;
1228     stream = &demux->stream[i];
1230     /* Don't push any data until we have at least one payload that falls within
1231      * the current segment. This way we can remove out-of-segment payloads that
1232      * don't need to be decoded after a seek, sending only data from the
1233      * keyframe directly before our segment start */
1234     if (stream->payloads->len > 0) {
1235       AsfPayload *payload;
1236       guint last_idx;
1238       last_idx = stream->payloads->len - 1;
1239       payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1240       if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1241               (payload->ts < demux->segment.start))) {
1242         if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1243           GST_DEBUG_OBJECT (stream->pad,
1244               "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1245               GST_TIME_ARGS (payload->ts));
1246           demux->segment.start = payload->ts;
1247           demux->segment.time = payload->ts;
1248         } else {
1249           GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1250               GST_TIME_FORMAT " which is before our segment start %"
1251               GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1252               GST_TIME_ARGS (demux->segment.start));
1253           continue;
1254         }
1255       }
1257       /* Now see if there's a complete payload queued for this stream */
1259       payload = &g_array_index (stream->payloads, AsfPayload, 0);
1260       if (!gst_asf_payload_is_complete (payload))
1261         continue;
1263       /* ... and whether its timestamp is lower than the current best */
1264       if (best_stream == NULL || best_payload->ts > payload->ts) {
1265         best_stream = stream;
1266         best_payload = payload;
1267       }
1268     }
1269   }
1271   return best_stream;
1274 static GstFlowReturn
1275 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1277   AsfStream *stream;
1279   if (G_UNLIKELY (!demux->activated_streams)) {
1280     if (!gst_asf_demux_check_activate_streams (demux, force))
1281       return GST_FLOW_OK;
1282     /* streams are now activated */
1283   }
1285   /* wait until we had a chance to "lock on" some payload's timestamp */
1286   if (G_UNLIKELY (demux->need_newsegment
1287           && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1288     return GST_FLOW_OK;
1290   while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1291     AsfPayload *payload;
1293     payload = &g_array_index (stream->payloads, AsfPayload, 0);
1295     /* do we need to send a newsegment event */
1296     if ((G_UNLIKELY (demux->need_newsegment))) {
1298       /* safe default if insufficient upstream info */
1299       if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1300         demux->in_gap = 0;
1302       if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1303           demux->segment.duration > 0) {
1304         /* slight HACK; prevent clipping of last bit */
1305         demux->segment.stop = demux->segment.duration + demux->in_gap;
1306       }
1308       /* FIXME : only if ACCURATE ! */
1309       if (G_LIKELY (!demux->accurate
1310               && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1311         GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1312             GST_TIME_ARGS (payload->ts));
1313         demux->segment.start = payload->ts;
1314         demux->segment.time = payload->ts;
1315       }
1317       GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1318           &demux->segment);
1320       /* note: we fix up all timestamps to start from 0, so this should be ok */
1321       gst_asf_demux_send_event_unlocked (demux,
1322           gst_event_new_new_segment (FALSE, demux->segment.rate,
1323               GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1324               demux->segment.start));
1326       /* now post any global tags we may have found */
1327       if (demux->taglist == NULL)
1328         demux->taglist = gst_tag_list_new ();
1330       gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1331           GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1333       GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1334       gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
1335       demux->taglist = NULL;
1337       demux->need_newsegment = FALSE;
1338       demux->segment_running = TRUE;
1339     }
1341     /* Do we have tags pending for this stream? */
1342     if (G_UNLIKELY (stream->pending_tags)) {
1343       GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1344       gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1345           stream->pending_tags);
1346       stream->pending_tags = NULL;
1347     }
1349     /* We have the whole packet now so we should push the packet to
1350      * the src pad now. First though we should check if we need to do
1351      * descrambling */
1352     if (G_UNLIKELY (demux->span > 1)) {
1353       gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1354     }
1356     payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1358     if (G_LIKELY (!payload->keyframe)) {
1359       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1360     }
1362     if (G_UNLIKELY (stream->discont)) {
1363       GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1364       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1365       stream->discont = FALSE;
1366     }
1368     if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1369             (payload->par_x != stream->par_x) &&
1370             (payload->par_y != stream->par_y))) {
1371       GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1372           stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1373       stream->par_x = payload->par_x;
1374       stream->par_y = payload->par_y;
1375       gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1376           GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1377       gst_pad_set_caps (stream->pad, stream->caps);
1378     }
1380     if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1381       GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1382           payload->interlaced);
1383       stream->interlaced = payload->interlaced;
1384       gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
1385           stream->interlaced, NULL);
1386     }
1388     gst_buffer_set_caps (payload->buf, stream->caps);
1390     /* (sort of) interpolate timestamps using upstream "frame of reference",
1391      * typically useful for live src, but might (unavoidably) mess with
1392      * position reporting if a live src is playing not so live content
1393      * (e.g. rtspsrc taking some time to fall back to tcp) */
1394     GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1395     if (payload->duration == GST_CLOCK_TIME_NONE)
1396       GST_BUFFER_DURATION (payload->buf) =
1397           stream->ext_props.avg_time_per_frame * 100;
1398     else
1399       GST_BUFFER_DURATION (payload->buf) = payload->duration;
1401     /* FIXME: we should really set durations on buffers if we can */
1403     GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1404         ", dur=%" GST_TIME_FORMAT " size=%u",
1405         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1406         GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1407         GST_BUFFER_SIZE (payload->buf));
1409     stream->last_flow = gst_pad_push (stream->pad, payload->buf);
1410     payload->buf = NULL;
1411     g_array_remove_index (stream->payloads, 0);
1412   }
1414   return gst_asf_demux_aggregate_flow_return (demux);
1417 static gboolean
1418 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1420   AsfObject obj;
1421   g_assert (buf != NULL);
1423   GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1425   /* we return false on buffer too small */
1426   if (GST_BUFFER_SIZE (buf) < ASF_OBJECT_HEADER_SIZE)
1427     return FALSE;
1429   /* check if it is a header */
1430   asf_demux_peek_object (demux, GST_BUFFER_DATA (buf),
1431       ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1432   if (obj.id == ASF_OBJ_HEADER) {
1433     return TRUE;
1434   }
1435   return FALSE;
1438 static gboolean
1439 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1441   guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1442   GstFlowReturn ret = GST_FLOW_OK;
1443   GstBuffer *buf = NULL;
1444   gboolean header = FALSE;
1446   /* TODO maybe we should skip index objects after the data and look
1447    * further for a new header */
1448   if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1449     g_assert (buf != NULL);
1450     /* check if it is a header */
1451     if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1452       GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1453       demux->base_offset = off;
1454       header = TRUE;
1455     }
1457     gst_buffer_unref (buf);
1458   }
1460   return header;
1463 static void
1464 gst_asf_demux_loop (GstASFDemux * demux)
1466   GstFlowReturn flow = GST_FLOW_OK;
1467   GstBuffer *buf = NULL;
1468   guint64 off;
1470   if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1471     if (!gst_asf_demux_pull_headers (demux)) {
1472       flow = GST_FLOW_ERROR;
1473       goto pause;
1474     }
1476     gst_asf_demux_pull_indices (demux);
1477   }
1479   g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1481   if (G_UNLIKELY (demux->num_packets != 0
1482           && demux->packet >= demux->num_packets))
1483     goto eos;
1485   GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1486       (guint) demux->num_packets);
1488   off = demux->data_offset + (demux->packet * demux->packet_size);
1490   if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1491               demux->packet_size * demux->speed_packets, &buf, &flow))) {
1492     GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1493     if (flow == GST_FLOW_UNEXPECTED)
1494       goto eos;
1495     else if (!GST_FLOW_IS_FATAL (flow)) {
1496       GST_DEBUG_OBJECT (demux, "Not fatal");
1497       goto pause;
1498     } else
1499       goto read_failed;
1500   }
1502   if (G_LIKELY (demux->speed_packets == 1)) {
1503     /* FIXME: maybe we should just skip broken packets and error out only
1504      * after a few broken packets in a row? */
1505     if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1506       /* when we don't know when the data object ends, we should check
1507        * for a chained asf */
1508       if (demux->num_packets == 0) {
1509         if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1510           GST_INFO_OBJECT (demux, "Chained asf found");
1511           demux->base_offset = off;
1512           gst_asf_demux_reset (demux, TRUE);
1513           gst_buffer_unref (buf);
1514           return;
1515         }
1516       }
1517       goto parse_error;
1518     }
1520     flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1522     ++demux->packet;
1524   } else {
1525     guint n;
1526     for (n = 0; n < demux->speed_packets; n++) {
1527       GstBuffer *sub;
1529       sub =
1530           gst_buffer_create_sub (buf, n * demux->packet_size,
1531           demux->packet_size);
1532       /* FIXME: maybe we should just skip broken packets and error out only
1533        * after a few broken packets in a row? */
1534       if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub))) {
1535         /* when we don't know when the data object ends, we should check
1536          * for a chained asf */
1537         if (demux->num_packets == 0) {
1538           if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1539             GST_INFO_OBJECT (demux, "Chained asf found");
1540             demux->base_offset = off + n * demux->packet_size;
1541             gst_asf_demux_reset (demux, TRUE);
1542             gst_buffer_unref (sub);
1543             gst_buffer_unref (buf);
1544             return;
1545           }
1546         }
1547         goto parse_error;
1548       }
1550       gst_buffer_unref (sub);
1552       flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1554       ++demux->packet;
1556     }
1558     /* reset speed pull */
1559     demux->speed_packets = 1;
1560   }
1562   gst_buffer_unref (buf);
1564   if (G_UNLIKELY (demux->num_packets > 0
1565           && demux->packet >= demux->num_packets)) {
1566     GST_LOG_OBJECT (demux, "reached EOS");
1567     goto eos;
1568   }
1570   if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1571     GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1572     goto pause;
1573   }
1575   /* check if we're at the end of the configured segment */
1576   /* FIXME: check if segment end reached etc. */
1578   return;
1580 eos:
1581   {
1582     /* if we haven't activated our streams yet, this might be because we have
1583      * less data queued than required for preroll; force stream activation and
1584      * send any pending payloads before sending EOS */
1585     if (!demux->activated_streams)
1586       gst_asf_demux_push_complete_payloads (demux, TRUE);
1588     /* we want to push an eos or post a segment-done in any case */
1589     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1590       gint64 stop;
1592       /* for segment playback we need to post when (in stream time)
1593        * we stopped, this is either stop (when set) or the duration. */
1594       if ((stop = demux->segment.stop) == -1)
1595         stop = demux->segment.duration;
1597       GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1598       gst_element_post_message (GST_ELEMENT_CAST (demux),
1599           gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1600               stop));
1601     } else if (flow != GST_FLOW_UNEXPECTED) {
1602       /* check if we have a chained asf, in case, we don't eos yet */
1603       if (gst_asf_demux_check_chained_asf (demux)) {
1604         GST_INFO_OBJECT (demux, "Chained ASF starting");
1605         gst_asf_demux_reset (demux, TRUE);
1606         return;
1607       }
1608       /* normal playback, send EOS to all linked pads */
1609       GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1610       gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1611     }
1612     /* ... and fall through to pause */
1613     GST_DEBUG_OBJECT (demux, "EOSing");
1614   }
1615 pause:
1616   {
1617     GST_DEBUG_OBJECT (demux, "pausing task");
1618     demux->segment_running = FALSE;
1619     gst_pad_pause_task (demux->sinkpad);
1621     /* For the error cases (not EOS) */
1622     if (GST_FLOW_IS_FATAL (flow) || flow == GST_FLOW_NOT_LINKED) {
1623       /* Post an error. Hopefully something else already has, but if not... */
1624       GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1625           (_("Internal data stream error.")),
1626           ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1627     }
1628     return;
1629   }
1631 /* ERRORS */
1632 read_failed:
1633   {
1634     GST_DEBUG_OBJECT (demux, "Read failed, doh");
1635     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1636     flow = GST_FLOW_UNEXPECTED;
1637     goto pause;
1638   }
1639 parse_error:
1640   {
1641     gst_buffer_unref (buf);
1642     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1643         ("Error parsing ASF packet %u", (guint) demux->packet));
1644     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1645     flow = GST_FLOW_ERROR;
1646     goto pause;
1647   }
1650 #define GST_ASF_DEMUX_CHECK_HEADER_YES       0
1651 #define GST_ASF_DEMUX_CHECK_HEADER_NO        1
1652 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1654 static gint
1655 gst_asf_demux_check_header (GstASFDemux * demux)
1657   AsfObject obj;
1658   guint8 *cdata = (guint8 *) gst_adapter_peek (demux->adapter,
1659       ASF_OBJECT_HEADER_SIZE);
1660   if (cdata == NULL)            /* need more data */
1661     return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1663   asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1664   if (obj.id != ASF_OBJ_HEADER) {
1665     return GST_ASF_DEMUX_CHECK_HEADER_NO;
1666   } else {
1667     return GST_ASF_DEMUX_CHECK_HEADER_YES;
1668   }
1671 static GstFlowReturn
1672 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1674   GstFlowReturn ret = GST_FLOW_OK;
1675   GstASFDemux *demux;
1677   demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1679   GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%"
1680       GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
1681       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1683   if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1684     GST_DEBUG_OBJECT (demux, "received DISCONT");
1685     gst_asf_demux_mark_discont (demux);
1686   }
1688   if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1689               GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1690     demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1691     GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1692         ", interpolation gap: %" GST_TIME_FORMAT,
1693         GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1694   }
1696   gst_adapter_push (demux->adapter, buf);
1698   switch (demux->state) {
1699     case GST_ASF_DEMUX_STATE_INDEX:{
1700       gint result = gst_asf_demux_check_header (demux);
1701       if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA)       /* need more data */
1702         break;
1704       if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1705         /* we don't care about this, probably an index */
1706         /* TODO maybe would be smarter to skip all the indices
1707          * until we got a new header or EOS to decide */
1708         GST_LOG_OBJECT (demux, "Received index object, its EOS");
1709         goto eos;
1710       } else {
1711         GST_INFO_OBJECT (demux, "Chained asf starting");
1712         /* cleanup and get ready for a chained asf */
1713         gst_asf_demux_reset (demux, TRUE);
1714         /* fall through */
1715       }
1716     }
1717     case GST_ASF_DEMUX_STATE_HEADER:{
1718       ret = gst_asf_demux_chain_headers (demux);
1719       if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1720         break;
1721       /* otherwise fall through */
1722     }
1723     case GST_ASF_DEMUX_STATE_DATA:
1724     {
1725       guint64 data_size;
1727       data_size = demux->packet_size;
1729       while (gst_adapter_available (demux->adapter) >= data_size) {
1730         GstBuffer *buf;
1732         /* we don't know the length of the stream
1733          * check for a chained asf everytime */
1734         if (demux->num_packets == 0) {
1735           gint result = gst_asf_demux_check_header (demux);
1737           if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1738             GST_INFO_OBJECT (demux, "Chained asf starting");
1739             /* cleanup and get ready for a chained asf */
1740             gst_asf_demux_reset (demux, TRUE);
1741             break;
1742           }
1743         } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1744                 && demux->packet >= demux->num_packets)) {
1745           /* do not overshoot data section when streaming */
1746           break;
1747         }
1749         buf = gst_adapter_take_buffer (demux->adapter, data_size);
1751         /* FIXME: maybe we should just skip broken packets and error out only
1752          * after a few broken packets in a row? */
1753         if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1754           GST_WARNING_OBJECT (demux, "Parse error");
1755         }
1757         gst_buffer_unref (buf);
1759         ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1761         if (demux->packet >= 0)
1762           ++demux->packet;
1763       }
1764       if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1765               && demux->packet >= demux->num_packets)) {
1766         demux->state = GST_ASF_DEMUX_STATE_INDEX;
1767       }
1768       break;
1769     }
1770     default:
1771       g_assert_not_reached ();
1772   }
1774 done:
1775   if (ret != GST_FLOW_OK)
1776     GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1778   return ret;
1780 eos:
1781   {
1782     GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1783     ret = GST_FLOW_UNEXPECTED;
1784     goto done;
1785   }
1788 static inline gboolean
1789 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1791   if (*p_size < num_bytes)
1792     return FALSE;
1794   *p_data += num_bytes;
1795   *p_size -= num_bytes;
1796   return TRUE;
1799 static inline guint8
1800 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1802   guint8 ret;
1804   g_assert (*p_size >= 1);
1805   ret = GST_READ_UINT8 (*p_data);
1806   *p_data += sizeof (guint8);
1807   *p_size -= sizeof (guint8);
1808   return ret;
1811 static inline guint16
1812 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1814   guint16 ret;
1816   g_assert (*p_size >= 2);
1817   ret = GST_READ_UINT16_LE (*p_data);
1818   *p_data += sizeof (guint16);
1819   *p_size -= sizeof (guint16);
1820   return ret;
1823 static inline guint32
1824 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1826   guint32 ret;
1828   g_assert (*p_size >= 4);
1829   ret = GST_READ_UINT32_LE (*p_data);
1830   *p_data += sizeof (guint32);
1831   *p_size -= sizeof (guint32);
1832   return ret;
1835 static inline guint64
1836 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1838   guint64 ret;
1840   g_assert (*p_size >= 8);
1841   ret = GST_READ_UINT64_LE (*p_data);
1842   *p_data += sizeof (guint64);
1843   *p_size -= sizeof (guint64);
1844   return ret;
1847 static inline guint32
1848 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1850   switch (type) {
1851     case 0:
1852       return 0;
1854     case 1:
1855       g_assert (*p_size >= 1);
1856       return gst_asf_demux_get_uint8 (p_data, p_size);
1858     case 2:
1859       g_assert (*p_size >= 2);
1860       return gst_asf_demux_get_uint16 (p_data, p_size);
1862     case 3:
1863       g_assert (*p_size >= 4);
1864       return gst_asf_demux_get_uint32 (p_data, p_size);
1866     default:
1867       break;
1868   }
1870   g_assert_not_reached ();
1873 static gboolean
1874 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1875     guint8 ** p_data, guint64 * p_size)
1877   *p_buf = NULL;
1879   if (*p_size < num_bytes_to_read)
1880     return FALSE;
1882   *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1883   memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1884   *p_data += num_bytes_to_read;
1885   *p_size -= num_bytes_to_read;
1886   return TRUE;
1889 static gboolean
1890 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1891     guint8 ** p_data, guint64 * p_size)
1893   *p_buf = NULL;
1895   if (*p_size < num_bytes_to_read)
1896     return FALSE;
1898   *p_buf = g_memdup (*p_data, num_bytes_to_read);
1899   *p_data += num_bytes_to_read;
1900   *p_size -= num_bytes_to_read;
1901   return TRUE;
1904 static gboolean
1905 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1906     guint8 ** p_data, guint64 * p_size)
1908   guint16 s_length;
1909   guint8 *s;
1911   *p_str = NULL;
1913   if (*p_size < 2)
1914     return FALSE;
1916   s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1918   if (p_strlen)
1919     *p_strlen = s_length;
1921   if (s_length == 0) {
1922     GST_WARNING ("zero-length string");
1923     *p_str = g_strdup ("");
1924     return TRUE;
1925   }
1927   if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1928     return FALSE;
1930   g_assert (s != NULL);
1932   /* just because They don't exist doesn't
1933    * mean They are not out to get you ... */
1934   if (s[s_length - 1] != '\0') {
1935     s = g_realloc (s, s_length + 1);
1936     s[s_length] = '\0';
1937   }
1939   *p_str = (gchar *) s;
1940   return TRUE;
1944 static void
1945 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
1947   g_assert (*p_size >= 4 * sizeof (guint32));
1949   guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
1950   guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
1951   guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
1952   guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
1955 static gboolean
1956 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
1957     guint64 * p_size)
1959   if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
1960     return FALSE;
1962   /* WAVEFORMATEX Structure */
1963   audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
1964   audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
1965   audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1966   audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1967   audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
1968   audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
1969   /* Codec specific data size */
1970   audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
1971   return TRUE;
1974 static gboolean
1975 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
1976     guint64 * p_size)
1978   if (*p_size < (4 + 4 + 1 + 2))
1979     return FALSE;
1981   video->width = gst_asf_demux_get_uint32 (p_data, p_size);
1982   video->height = gst_asf_demux_get_uint32 (p_data, p_size);
1983   video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
1984   video->size = gst_asf_demux_get_uint16 (p_data, p_size);
1985   return TRUE;
1988 static gboolean
1989 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
1990     guint8 ** p_data, guint64 * p_size)
1992   if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
1993     return FALSE;
1995   fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
1996   fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
1997   fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
1998   fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
1999   fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2000   fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2001   fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2002   fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2003   fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2004   fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2005   fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2006   return TRUE;
2009 AsfStream *
2010 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2012   guint i;
2014   for (i = 0; i < demux->num_streams; i++) {
2015     if (demux->stream[i].id == id)
2016       return &demux->stream[i];
2017   }
2019   GST_WARNING ("Segment found for undefined stream: (%d)", id);
2020   return NULL;
2023 static void
2024 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2025     GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2027   AsfStream *stream;
2029   gst_pad_use_fixed_caps (src_pad);
2030   gst_pad_set_caps (src_pad, caps);
2032   gst_pad_set_event_function (src_pad,
2033       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2034   gst_pad_set_query_type_function (src_pad,
2035       GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
2036   gst_pad_set_query_function (src_pad,
2037       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2039   stream = &demux->stream[demux->num_streams];
2040   stream->caps = caps;
2041   stream->pad = src_pad;
2042   stream->id = id;
2043   stream->fps_known = !is_video;        /* bit hacky for audio */
2044   stream->is_video = is_video;
2045   stream->pending_tags = tags;
2046   stream->discont = TRUE;
2047   if (is_video) {
2048     GstStructure *st;
2049     gint par_x, par_y;
2050     st = gst_caps_get_structure (caps, 0);
2051     if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2052         par_x > 0 && par_y > 0) {
2053       GST_DEBUG ("PAR %d/%d", par_x, par_y);
2054       stream->par_x = par_x;
2055       stream->par_y = par_y;
2056     }
2057   }
2059   stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2061   GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2062       GST_PAD_NAME (src_pad), demux->num_streams, caps);
2064   ++demux->num_streams;
2066   stream->active = FALSE;
2069 static void
2070 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2071     asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2073   GstTagList *tags = NULL;
2074   GstBuffer *extradata = NULL;
2075   GstPad *src_pad;
2076   GstCaps *caps;
2077   guint16 size_left = 0;
2078   gchar *codec_name = NULL;
2079   gchar *name = NULL;
2081   size_left = audio->size;
2083   /* Create the audio pad */
2084   name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
2086   src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2087   g_free (name);
2089   /* Swallow up any left over data and set up the 
2090    * standard properties from the header info */
2091   if (size_left) {
2092     GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2093         "codec specific data", size_left);
2095     g_assert (size_left <= *p_size);
2096     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2097   }
2099   /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2100    * additional two bytes indicating extradata. */
2101   caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2102       (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
2104   if (caps == NULL) {
2105     caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2106         G_TYPE_INT, (gint) audio->codec_tag, NULL);
2107   }
2109   /* Informing about that audio format we just added */
2110   if (codec_name) {
2111     tags = gst_tag_list_new ();
2112     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
2113         codec_name, NULL);
2114     g_free (codec_name);
2115   }
2117   if (extradata)
2118     gst_buffer_unref (extradata);
2120   GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2121       GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2122       audio->codec_tag, tags);
2124   ++demux->num_audio_streams;
2126   gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2129 static void
2130 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2131     asf_stream_video_format * video, guint16 id,
2132     guint8 ** p_data, guint64 * p_size)
2134   GstTagList *tags = NULL;
2135   GstBuffer *extradata = NULL;
2136   GstPad *src_pad;
2137   GstCaps *caps;
2138   gchar *name = NULL;
2139   gchar *codec_name = NULL;
2140   gint size_left = video->size - 40;
2142   /* Create the video pad */
2143   name = g_strdup_printf ("video_%02d", demux->num_video_streams);
2144   src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2145   g_free (name);
2147   /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2148   if (size_left) {
2149     GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2150     g_assert (size_left <= *p_size);
2151     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2152   }
2154   GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2156   /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2157   caps = gst_riff_create_video_caps (video->tag, NULL,
2158       (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2160   if (caps == NULL) {
2161     caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2162         GST_TYPE_FOURCC, video->tag, NULL);
2163   } else {
2164     GstStructure *s;
2165     gint ax, ay;
2167     s = gst_asf_demux_get_metadata_for_stream (demux, id);
2168     if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2169         gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2170       gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2171           ax, ay, NULL);
2173     } else {
2174       guint ax, ay;
2175       /* retry with the global metadata */
2176       GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2177           demux->global_metadata);
2178       s = demux->global_metadata;
2179       if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2180           gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2181         GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2182         if (ax > 0 && ay > 0)
2183           gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2184               ax, ay, NULL);
2185       }
2186     }
2187     s = gst_caps_get_structure (caps, 0);
2188     gst_structure_remove_field (s, "framerate");
2189   }
2191   /* add fourcc format to caps, some proprietary decoders seem to need it */
2192   gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
2194   if (codec_name) {
2195     tags = gst_tag_list_new ();
2196     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
2197         codec_name, NULL);
2198     g_free (codec_name);
2199   }
2201   if (extradata)
2202     gst_buffer_unref (extradata);
2204   GST_INFO ("Adding video stream #%u, id %u, codec %"
2205       GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2206       GST_FOURCC_ARGS (video->tag), video->tag);
2208   ++demux->num_video_streams;
2210   gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2213 static void
2214 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2216   if (!stream->active) {
2217     GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2218         GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2219     gst_pad_set_active (stream->pad, TRUE);
2220     gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2221     stream->active = TRUE;
2222   }
2225 static AsfStream *
2226 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2227     guint64 size)
2229   AsfCorrectionType correction_type;
2230   AsfStreamType stream_type;
2231   GstClockTime time_offset;
2232   gboolean is_encrypted;
2233   guint16 stream_id;
2234   guint16 flags;
2235   ASFGuid guid;
2236   guint stream_specific_size;
2237   guint type_specific_size;
2238   guint unknown;
2240   /* Get the rest of the header's header */
2241   if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2242     goto not_enough_data;
2244   gst_asf_demux_get_guid (&guid, &data, &size);
2245   stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2247   gst_asf_demux_get_guid (&guid, &data, &size);
2248   correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2250   time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2252   type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2253   stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2255   flags = gst_asf_demux_get_uint16 (&data, &size);
2256   stream_id = flags & 0x7f;
2257   is_encrypted = !!((flags & 0x8000) << 15);
2258   unknown = gst_asf_demux_get_uint32 (&data, &size);
2260   GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2261       stream_id, GST_TIME_ARGS (time_offset));
2263   switch (stream_type) {
2264     case ASF_STREAM_AUDIO:{
2265       asf_stream_audio audio_object;
2267       if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2268         goto not_enough_data;
2270       GST_INFO ("Object is an audio stream with %u bytes of additional data",
2271           audio_object.size);
2273       gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2274           &data, &size);
2276       switch (correction_type) {
2277         case ASF_CORRECTION_ON:{
2278           guint span, packet_size, chunk_size, data_size, silence_data;
2280           GST_INFO ("Using error correction");
2282           if (size < (1 + 2 + 2 + 2 + 1))
2283             goto not_enough_data;
2285           span = gst_asf_demux_get_uint8 (&data, &size);
2286           packet_size = gst_asf_demux_get_uint16 (&data, &size);
2287           chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2288           data_size = gst_asf_demux_get_uint16 (&data, &size);
2289           silence_data = gst_asf_demux_get_uint8 (&data, &size);
2291           /* FIXME: shouldn't this be per-stream? */
2292           demux->span = span;
2294           GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2295               packet_size, chunk_size, data_size, span, silence_data);
2297           if (demux->span > 1) {
2298             if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2299               /* Disable descrambling */
2300               demux->span = 0;
2301             } else {
2302               /* FIXME: this else branch was added for
2303                * weird_al_yankovic - the saga begins.asf */
2304               demux->ds_packet_size = packet_size;
2305               demux->ds_chunk_size = chunk_size;
2306             }
2307           } else {
2308             /* Descambling is enabled */
2309             demux->ds_packet_size = packet_size;
2310             demux->ds_chunk_size = chunk_size;
2311           }
2312 #if 0
2313           /* Now skip the rest of the silence data */
2314           if (data_size > 1)
2315             gst_bytestream_flush (demux->bs, data_size - 1);
2316 #else
2317           /* FIXME: CHECKME. And why -1? */
2318           if (data_size > 1) {
2319             if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2320               goto not_enough_data;
2321             }
2322           }
2323 #endif
2324           break;
2325         }
2326         case ASF_CORRECTION_OFF:{
2327           GST_INFO ("Error correction off");
2328           if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2329             goto not_enough_data;
2330           break;
2331         }
2332         default:
2333           GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2334               ("Audio stream using unknown error correction"));
2335           return NULL;
2336       }
2338       break;
2339     }
2341     case ASF_STREAM_VIDEO:{
2342       asf_stream_video_format video_format_object;
2343       asf_stream_video video_object;
2344       guint16 vsize;
2346       if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2347         goto not_enough_data;
2349       vsize = video_object.size - 40;   /* Byte order gets offset by single byte */
2351       GST_INFO ("object is a video stream with %u bytes of "
2352           "additional data", vsize);
2354       if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2355               &data, &size)) {
2356         goto not_enough_data;
2357       }
2359       gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2360           &data, &size);
2362       break;
2363     }
2365     default:
2366       GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2367           stream_id);
2368       break;
2369   }
2371   return gst_asf_demux_get_stream (demux, stream_id);
2373 not_enough_data:
2374   {
2375     GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2376     /* we'll error out later if we found no streams */
2377     return NULL;
2378   }
2381 static const gchar *
2382 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2384   const struct
2385   {
2386     const gchar *asf_name;
2387     const gchar *gst_name;
2388   } tags[] = {
2389     {
2390     "WM/Genre", GST_TAG_GENRE}, {
2391     "WM/AlbumTitle", GST_TAG_ALBUM}, {
2392     "WM/AlbumArtist", GST_TAG_ARTIST}, {
2393     "WM/Picture", GST_TAG_IMAGE}, {
2394     "WM/Track", GST_TAG_TRACK_NUMBER}, {
2395     "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2396     "WM/Year", GST_TAG_DATE}
2397     /* { "WM/Composer", GST_TAG_COMPOSER } */
2398   };
2399   gsize out;
2400   guint i;
2402   if (name_utf8 == NULL) {
2403     GST_WARNING ("Failed to convert name to UTF8, skipping");
2404     return NULL;
2405   }
2407   out = strlen (name_utf8);
2409   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2410     if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2411       GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2412       return tags[i].gst_name;
2413     }
2414   }
2416   return NULL;
2419 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2420 static void
2421 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2423   GstTagList *t;
2425   GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2427   if (taglist == NULL)
2428     return;
2430   if (gst_tag_list_is_empty (taglist)) {
2431     gst_tag_list_free (taglist);
2432     return;
2433   }
2435   t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2436   if (demux->taglist)
2437     gst_tag_list_free (demux->taglist);
2438   gst_tag_list_free (taglist);
2439   demux->taglist = t;
2440   GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2443 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING  0
2444 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY      1
2445 #define ASF_DEMUX_DATA_TYPE_DWORD           3
2447 static void
2448 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2449     guint tag_data_len)
2451   GstByteReader r;
2452   const guint8 *img_data = NULL;
2453   guint32 img_data_len = 0;
2454   guint8 pic_type = 0;
2456   gst_byte_reader_init (&r, tag_data, tag_data_len);
2458   /* skip mime type string (we don't trust it and do our own typefinding),
2459    * and also skip the description string, since we don't use it */
2460   if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2461       !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2462       !gst_byte_reader_skip_string_utf16 (&r) ||
2463       !gst_byte_reader_skip_string_utf16 (&r) ||
2464       !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2465     goto not_enough_data;
2466   }
2469   if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2470     GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2472   return;
2474 not_enough_data:
2475   {
2476     GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2477     GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2478     return;
2479   }
2482 /* Extended Content Description Object */
2483 static GstFlowReturn
2484 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2485     guint64 size)
2487   /* Other known (and unused) 'text/unicode' metadata available :
2488    *
2489    *   WM/Lyrics =
2490    *   WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2491    *   WMFSDKVersion = 9.00.00.2980
2492    *   WMFSDKNeeded = 0.0.0.0000
2493    *   WM/UniqueFileIdentifier = AMGa_id=R    15334;AMGp_id=P     5149;AMGt_id=T  2324984
2494    *   WM/Publisher = 4AD
2495    *   WM/Provider = AMG
2496    *   WM/ProviderRating = 8
2497    *   WM/ProviderStyle = Rock (similar to WM/Genre)
2498    *   WM/GenreID (similar to WM/Genre)
2499    *   WM/TrackNumber (same as WM/Track but as a string)
2500    *
2501    * Other known (and unused) 'non-text' metadata available :
2502    *
2503    *   WM/EncodingTime
2504    *   WM/MCDI
2505    *   IsVBR
2506    *
2507    * We might want to read WM/TrackNumber and use atoi() if we don't have
2508    * WM/Track
2509    */
2511   GstTagList *taglist;
2512   guint16 blockcount, i;
2514   GST_INFO_OBJECT (demux, "object is an extended content description");
2516   taglist = gst_tag_list_new ();
2518   /* Content Descriptor Count */
2519   if (size < 2)
2520     goto not_enough_data;
2522   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2524   for (i = 1; i <= blockcount; ++i) {
2525     const gchar *gst_tag_name;
2526     guint16 datatype;
2527     guint16 value_len;
2528     guint16 name_len;
2529     GValue tag_value = { 0, };
2530     gsize in, out;
2531     gchar *name;
2532     gchar *name_utf8 = NULL;
2533     gchar *value;
2535     /* Descriptor */
2536     if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2537       goto not_enough_data;
2539     if (size < 2) {
2540       g_free (name);
2541       goto not_enough_data;
2542     }
2543     /* Descriptor Value Data Type */
2544     datatype = gst_asf_demux_get_uint16 (&data, &size);
2546     /* Descriptor Value (not really a string, but same thing reading-wise) */
2547     if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2548       g_free (name);
2549       goto not_enough_data;
2550     }
2552     name_utf8 =
2553         g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2555     if (name_utf8 != NULL) {
2556       GST_DEBUG ("Found tag/metadata %s", name_utf8);
2558       gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2559       GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2561       switch (datatype) {
2562         case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2563           gchar *value_utf8;
2565           value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2566               &in, &out, NULL);
2568           /* get rid of tags with empty value */
2569           if (value_utf8 != NULL && *value_utf8 != '\0') {
2570             GST_DEBUG ("string value %s", value_utf8);
2572             value_utf8[out] = '\0';
2574             if (gst_tag_name != NULL) {
2575               if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2576                 guint year = atoi (value_utf8);
2578                 if (year > 0) {
2579                   GDate *date = g_date_new_dmy (1, 1, year);
2581                   g_value_init (&tag_value, GST_TYPE_DATE);
2582                   gst_value_set_date (&tag_value, date);
2583                   g_date_free (date);
2584                 }
2585               } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2586                 guint id3v1_genre_id;
2587                 const gchar *genre_str;
2589                 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2590                     ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2591                   GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2592                   g_free (value_utf8);
2593                   value_utf8 = g_strdup (genre_str);
2594                 }
2595               } else {
2596                 GType tag_type;
2598                 /* convert tag from string to other type if required */
2599                 tag_type = gst_tag_get_type (gst_tag_name);
2600                 g_value_init (&tag_value, tag_type);
2601                 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2602                   GValue from_val = { 0, };
2604                   g_value_init (&from_val, G_TYPE_STRING);
2605                   g_value_set_string (&from_val, value_utf8);
2606                   if (!g_value_transform (&from_val, &tag_value)) {
2607                     GST_WARNING_OBJECT (demux,
2608                         "Could not transform string tag to " "%s tag type %s",
2609                         gst_tag_name, g_type_name (tag_type));
2610                     g_value_unset (&tag_value);
2611                   }
2612                   g_value_unset (&from_val);
2613                 }
2614               }
2615             } else {
2616               /* metadata ! */
2617               GST_DEBUG ("Setting metadata");
2618               g_value_init (&tag_value, G_TYPE_STRING);
2619               g_value_set_string (&tag_value, value_utf8);
2620             }
2621           } else if (value_utf8 == NULL) {
2622             GST_WARNING ("Failed to convert string value to UTF8, skipping");
2623           } else {
2624             GST_DEBUG ("Skipping empty string value for %s",
2625                 GST_STR_NULL (gst_tag_name));
2626           }
2627           g_free (value_utf8);
2628           break;
2629         }
2630         case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2631           if (gst_tag_name) {
2632             if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2633               GST_FIXME ("Unhandled byte array tag %s",
2634                   GST_STR_NULL (gst_tag_name));
2635               break;
2636             } else {
2637               asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2638                   value_len);
2639             }
2640           }
2641           break;
2642         }
2643         case ASF_DEMUX_DATA_TYPE_DWORD:{
2644           guint uint_val = GST_READ_UINT32_LE (value);
2646           /* this is the track number */
2647           g_value_init (&tag_value, G_TYPE_UINT);
2649           /* WM/Track counts from 0 */
2650           if (!strcmp (name_utf8, "WM/Track"))
2651             ++uint_val;
2653           g_value_set_uint (&tag_value, uint_val);
2654           break;
2655         }
2656         default:{
2657           GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2658           break;
2659         }
2660       }
2662       if (G_IS_VALUE (&tag_value)) {
2663         if (gst_tag_name) {
2664           GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2666           /* WM/TrackNumber is more reliable than WM/Track, since the latter
2667            * is supposed to have a 0 base but is often wrongly written to start
2668            * from 1 as well, so prefer WM/TrackNumber when we have it: either
2669            * replace the value added earlier from WM/Track or put it first in
2670            * the list, so that it will get picked up by _get_uint() */
2671           if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2672             merge_mode = GST_TAG_MERGE_REPLACE;
2674           gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2675               &tag_value, NULL);
2676         } else {
2677           GST_DEBUG ("Setting global metadata %s", name_utf8);
2678           gst_structure_set_value (demux->global_metadata, name_utf8,
2679               &tag_value);
2680         }
2682         g_value_unset (&tag_value);
2683       }
2684     }
2686     g_free (name);
2687     g_free (value);
2688     g_free (name_utf8);
2689   }
2691   gst_asf_demux_add_global_tags (demux, taglist);
2693   return GST_FLOW_OK;
2695   /* Errors */
2696 not_enough_data:
2697   {
2698     GST_WARNING ("Unexpected end of data parsing ext content desc object");
2699     gst_tag_list_free (taglist);
2700     return GST_FLOW_OK;         /* not really fatal */
2701   }
2704 static GstStructure *
2705 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2707   gchar sname[32];
2708   guint i;
2710   g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2712   for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2713     GstStructure *s;
2715     s = gst_caps_get_structure (demux->metadata, i);
2716     if (gst_structure_has_name (s, sname))
2717       return s;
2718   }
2720   gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2722   /* try lookup again; demux->metadata took ownership of the structure, so we
2723    * can't really make any assumptions about what happened to it, so we can't
2724    * just return it directly after appending it */
2725   return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2728 static GstFlowReturn
2729 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2730     guint64 size)
2732   guint16 blockcount, i;
2734   GST_INFO_OBJECT (demux, "object is a metadata object");
2736   /* Content Descriptor Count */
2737   if (size < 2)
2738     goto not_enough_data;
2740   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2742   for (i = 0; i < blockcount; ++i) {
2743     GstStructure *s;
2744     guint16 lang_idx, stream_num, name_len, data_type;
2745     guint32 data_len, ival;
2746     gchar *name_utf8;
2748     if (size < (2 + 2 + 2 + 2 + 4))
2749       goto not_enough_data;
2751     lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2752     stream_num = gst_asf_demux_get_uint16 (&data, &size);
2753     name_len = gst_asf_demux_get_uint16 (&data, &size);
2754     data_type = gst_asf_demux_get_uint16 (&data, &size);
2755     data_len = gst_asf_demux_get_uint32 (&data, &size);
2757     if (size < name_len + data_len)
2758       goto not_enough_data;
2760     /* convert name to UTF-8 */
2761     name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2762         NULL, NULL, NULL);
2763     gst_asf_demux_skip_bytes (name_len, &data, &size);
2765     if (name_utf8 == NULL) {
2766       GST_WARNING ("Failed to convert value name to UTF8, skipping");
2767       gst_asf_demux_skip_bytes (data_len, &data, &size);
2768       continue;
2769     }
2771     if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2772       gst_asf_demux_skip_bytes (data_len, &data, &size);
2773       g_free (name_utf8);
2774       continue;
2775     }
2777     /* read DWORD */
2778     if (size < 4) {
2779       g_free (name_utf8);
2780       goto not_enough_data;
2781     }
2783     ival = gst_asf_demux_get_uint32 (&data, &size);
2785     /* skip anything else there may be, just in case */
2786     gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2788     s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2789     gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2790     g_free (name_utf8);
2791   }
2793   GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2794   return GST_FLOW_OK;
2796   /* Errors */
2797 not_enough_data:
2798   {
2799     GST_WARNING ("Unexpected end of data parsing metadata object");
2800     return GST_FLOW_OK;         /* not really fatal */
2801   }
2804 static GstFlowReturn
2805 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2807   GstFlowReturn ret = GST_FLOW_OK;
2808   guint32 i, num_objects;
2809   guint8 unknown;
2811   /* Get the rest of the header's header */
2812   if (size < (4 + 1 + 1))
2813     goto not_enough_data;
2815   num_objects = gst_asf_demux_get_uint32 (&data, &size);
2816   unknown = gst_asf_demux_get_uint8 (&data, &size);
2817   unknown = gst_asf_demux_get_uint8 (&data, &size);
2819   GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2821   /* Loop through the header's objects, processing those */
2822   for (i = 0; i < num_objects; ++i) {
2823     GST_INFO_OBJECT (demux, "reading header part %u", i);
2824     ret = gst_asf_demux_process_object (demux, &data, &size);
2825     if (ret != GST_FLOW_OK) {
2826       GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2827       break;
2828     }
2829   }
2831   return ret;
2833 not_enough_data:
2834   {
2835     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2836         ("short read parsing HEADER object"));
2837     return GST_FLOW_ERROR;
2838   }
2841 static GstFlowReturn
2842 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2844   guint64 file_size, creation_time, packets_count;
2845   guint64 play_time, send_time, preroll;
2846   guint32 flags, min_pktsize, max_pktsize, min_bitrate;
2848   if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2849     goto not_enough_data;
2851   gst_asf_demux_skip_bytes (16, &data, &size);  /* skip GUID */
2852   file_size = gst_asf_demux_get_uint64 (&data, &size);
2853   creation_time = gst_asf_demux_get_uint64 (&data, &size);
2854   packets_count = gst_asf_demux_get_uint64 (&data, &size);
2855   play_time = gst_asf_demux_get_uint64 (&data, &size);
2856   send_time = gst_asf_demux_get_uint64 (&data, &size);
2857   preroll = gst_asf_demux_get_uint64 (&data, &size);
2858   flags = gst_asf_demux_get_uint32 (&data, &size);
2859   min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2860   max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2861   min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2863   demux->broadcast = !!(flags & 0x01);
2864   demux->seekable = !!(flags & 0x02);
2866   GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2867   GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2868   GST_DEBUG_OBJECT (demux, "flags::seekable  = %d", demux->seekable);
2870   if (demux->broadcast) {
2871     /* these fields are invalid if the broadcast flag is set */
2872     play_time = 0;
2873     file_size = 0;
2874   }
2876   if (min_pktsize != max_pktsize)
2877     goto non_fixed_packet_size;
2879   demux->packet_size = max_pktsize;
2881   /* FIXME: do we need send_time as well? what is it? */
2882   if ((play_time * 100) >= (preroll * GST_MSECOND))
2883     demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2884   else
2885     demux->play_time = 0;
2887   demux->preroll = preroll * GST_MSECOND;
2889   /* initial latency */
2890   demux->latency = demux->preroll;
2892   if (demux->play_time == 0)
2893     demux->seekable = FALSE;
2895   GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2896       GST_TIME_ARGS (demux->play_time));
2897   GST_DEBUG_OBJECT (demux, "preroll   %" GST_TIME_FORMAT,
2898       GST_TIME_ARGS (demux->preroll));
2900   if (demux->play_time > 0) {
2901     gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2902         demux->play_time);
2903   }
2905   GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2906       packets_count);
2907   GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2909   return GST_FLOW_OK;
2911 /* ERRORS */
2912 non_fixed_packet_size:
2913   {
2914     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2915         ("packet size must be fixed"));
2916     return GST_FLOW_ERROR;
2917   }
2918 not_enough_data:
2919   {
2920     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2921         ("short read parsing FILE object"));
2922     return GST_FLOW_ERROR;
2923   }
2926 /* Content Description Object */
2927 static GstFlowReturn
2928 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2930   struct
2931   {
2932     const gchar *gst_tag;
2933     guint16 val_length;
2934     gchar *val_utf8;
2935   } tags[5] = {
2936     {
2937     GST_TAG_TITLE, 0, NULL}, {
2938     GST_TAG_ARTIST, 0, NULL}, {
2939     GST_TAG_COPYRIGHT, 0, NULL}, {
2940     GST_TAG_DESCRIPTION, 0, NULL}, {
2941     GST_TAG_COMMENT, 0, NULL}
2942   };
2943   GstTagList *taglist;
2944   GValue value = { 0 };
2945   gsize in, out;
2946   gint i = -1;
2948   GST_INFO_OBJECT (demux, "object is a comment");
2950   if (size < (2 + 2 + 2 + 2 + 2))
2951     goto not_enough_data;
2953   tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
2954   tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
2955   tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
2956   tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
2957   tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
2959   GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
2960       "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
2961       tags[2].val_length, tags[3].val_length, tags[4].val_length);
2963   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2964     if (size < tags[i].val_length)
2965       goto not_enough_data;
2967     /* might be just '/0', '/0'... */
2968     if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
2969       /* convert to UTF-8 */
2970       tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
2971           "UTF-8", "UTF-16LE", &in, &out, NULL);
2972     }
2973     gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
2974   }
2976   /* parse metadata into taglist */
2977   taglist = gst_tag_list_new ();
2978   g_value_init (&value, G_TYPE_STRING);
2979   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2980     if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
2981       g_value_set_string (&value, tags[i].val_utf8);
2982       gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2983           tags[i].gst_tag, &value, NULL);
2984     }
2985   }
2986   g_value_unset (&value);
2988   gst_asf_demux_add_global_tags (demux, taglist);
2990   for (i = 0; i < G_N_ELEMENTS (tags); ++i)
2991     g_free (tags[i].val_utf8);
2993   return GST_FLOW_OK;
2995 not_enough_data:
2996   {
2997     GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
2998         "comment tag section %d, skipping comment object", i);
2999     for (i = 0; i < G_N_ELEMENTS (tags); i++)
3000       g_free (tags[i].val_utf8);
3001     return GST_FLOW_OK;         /* not really fatal */
3002   }
3005 static GstFlowReturn
3006 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3007     guint64 size)
3009   guint16 num_streams, i;
3010   AsfStream *stream;
3012   if (size < 2)
3013     goto not_enough_data;
3015   num_streams = gst_asf_demux_get_uint16 (&data, &size);
3017   GST_INFO ("object is a bitrate properties object with %u streams",
3018       num_streams);
3020   if (size < (num_streams * (2 + 4)))
3021     goto not_enough_data;
3023   for (i = 0; i < num_streams; ++i) {
3024     guint32 bitrate;
3025     guint16 stream_id;
3027     stream_id = gst_asf_demux_get_uint16 (&data, &size);
3028     bitrate = gst_asf_demux_get_uint32 (&data, &size);
3030     if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3031       GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3032       stream = gst_asf_demux_get_stream (demux, stream_id);
3033       if (stream) {
3034         if (stream->pending_tags == NULL)
3035           stream->pending_tags = gst_tag_list_new ();
3036         gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3037             GST_TAG_BITRATE, bitrate, NULL);
3038       } else {
3039         GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3040       }
3041     } else {
3042       GST_WARNING ("stream id %u is too large", stream_id);
3043     }
3044   }
3046   return GST_FLOW_OK;
3048 not_enough_data:
3049   {
3050     GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3051     return GST_FLOW_OK;         /* not really fatal */
3052   }
3055 static GstFlowReturn
3056 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3057     guint64 size)
3059   GstFlowReturn ret = GST_FLOW_OK;
3060   guint64 hdr_size;
3062   /* Get the rest of the header's header */
3063   if (size < (16 + 2 + 4))
3064     goto not_enough_data;
3066   /* skip GUID and two other bytes */
3067   gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3068   hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3070   GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3072   /* FIXME: does data_size include the rest of the header that we have read? */
3073   if (hdr_size > size)
3074     goto not_enough_data;
3076   while (hdr_size > 0) {
3077     ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3078     if (ret != GST_FLOW_OK)
3079       break;
3080   }
3082   return ret;
3084 not_enough_data:
3085   {
3086     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3087         ("short read parsing extended header object"));
3088     return GST_FLOW_ERROR;
3089   }
3092 static GstFlowReturn
3093 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3094     guint64 size)
3096   guint i;
3098   if (size < 2)
3099     goto not_enough_data;
3101   if (demux->languages) {
3102     GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3103     g_strfreev (demux->languages);
3104     demux->languages = NULL;
3105     demux->num_languages = 0;
3106   }
3108   demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3109   GST_LOG ("%u languages:", demux->num_languages);
3111   demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3112   for (i = 0; i < demux->num_languages; ++i) {
3113     guint8 len, *lang_data = NULL;
3115     if (size < 1)
3116       goto not_enough_data;
3117     len = gst_asf_demux_get_uint8 (&data, &size);
3118     if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3119       gchar *utf8;
3121       utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3122           NULL, NULL);
3124       /* truncate "en-us" etc. to just "en" */
3125       if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3126         utf8[2] = '\0';
3127       }
3128       GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3129       demux->languages[i] = utf8;
3130       g_free (lang_data);
3131     } else {
3132       goto not_enough_data;
3133     }
3134   }
3136   return GST_FLOW_OK;
3138 not_enough_data:
3139   {
3140     GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3141     g_free (demux->languages);
3142     demux->languages = NULL;
3143     return GST_FLOW_OK;         /* not fatal */
3144   }
3147 static GstFlowReturn
3148 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3149     guint64 size)
3151   GstClockTime interval;
3152   guint32 x, count, i;
3154   if (size < (16 + 8 + 4 + 4))
3155     goto not_enough_data;
3157   /* skip file id */
3158   gst_asf_demux_skip_bytes (16, &data, &size);
3159   interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3160   x = gst_asf_demux_get_uint32 (&data, &size);
3161   count = gst_asf_demux_get_uint32 (&data, &size);
3162   if (count > 0) {
3163     demux->sidx_interval = interval;
3164     demux->sidx_num_entries = count;
3165     g_free (demux->sidx_entries);
3166     demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3168     for (i = 0; i < count; ++i) {
3169       if (G_UNLIKELY (size <= 6))
3170         break;
3171       demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3172       demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3173       GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u  count : %2d",
3174           GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3175           demux->sidx_entries[i].count);
3176     }
3177   } else {
3178     GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3179   }
3181   return GST_FLOW_OK;
3183 not_enough_data:
3184   {
3185     GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3186     return GST_FLOW_OK;         /* not fatal */
3187   }
3190 static GstFlowReturn
3191 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3192     guint8 * data, guint64 size)
3194   ASFGuid guid;
3195   guint16 num, i;
3196   guint8 *mes;
3198   if (size < 16 + 2 + (2 * 2))
3199     goto not_enough_data;
3201   gst_asf_demux_get_guid (&guid, &data, &size);
3202   num = gst_asf_demux_get_uint16 (&data, &size);
3204   if (num < 2) {
3205     GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3206     return GST_FLOW_OK;
3207   }
3209   if (size < (num * sizeof (guint16)))
3210     goto not_enough_data;
3212   /* read mutually exclusive stream numbers */
3213   mes = g_new (guint8, num + 1);
3214   for (i = 0; i < num; ++i) {
3215     mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3216     GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3217   }
3219   /* add terminator so we can easily get the count or know when to stop */
3220   mes[i] = (guint8) - 1;
3222   demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3224   return GST_FLOW_OK;
3226   /* Errors */
3227 not_enough_data:
3228   {
3229     GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3230     return GST_FLOW_OK;         /* not absolutely fatal */
3231   }
3234 static GstFlowReturn
3235 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3236     guint64 size)
3238   AsfStreamExtProps esp;
3239   AsfStream *stream = NULL;
3240   AsfObject stream_obj;
3241   guint16 stream_name_count;
3242   guint16 num_payload_ext;
3243   guint64 len;
3244   guint8 *stream_obj_data = NULL;
3245   guint8 *data_start;
3246   guint obj_size;
3247   guint i, stream_num;
3249   data_start = data;
3250   obj_size = (guint) size;
3252   if (size < 64)
3253     goto not_enough_data;
3255   esp.valid = TRUE;
3256   esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3257   esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3258   esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3259   esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3260   esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3261   esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3262   esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3263   esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3264   esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3265   esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3266   stream_num = gst_asf_demux_get_uint16 (&data, &size);
3267   esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3268   esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3269   stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3270   num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3272   GST_INFO ("start_time             = %" GST_TIME_FORMAT,
3273       GST_TIME_ARGS (esp.start_time));
3274   GST_INFO ("end_time               = %" GST_TIME_FORMAT,
3275       GST_TIME_ARGS (esp.end_time));
3276   GST_INFO ("flags                  = %08x", esp.flags);
3277   GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3278       GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3279   GST_INFO ("stream number          = %u", stream_num);
3280   GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3281       (esp.lang_idx < demux->num_languages) ?
3282       GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3283   GST_INFO ("stream name count      = %u", stream_name_count);
3285   /* read stream names */
3286   for (i = 0; i < stream_name_count; ++i) {
3287     guint16 stream_lang_idx;
3288     gchar *stream_name = NULL;
3290     if (size < 2)
3291       goto not_enough_data;
3292     stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3293     if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3294       goto not_enough_data;
3295     GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3296     g_free (stream_name);       /* TODO: store names in struct */
3297   }
3299   /* read payload extension systems stuff */
3300   GST_LOG ("payload extension systems count = %u", num_payload_ext);
3302   if (num_payload_ext > 0)
3303     esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3304   else
3305     esp.payload_extensions = NULL;
3307   for (i = 0; i < num_payload_ext; ++i) {
3308     AsfPayloadExtension ext;
3309     ASFGuid ext_guid;
3310     guint32 sys_info_len;
3312     if (size < 16 + 2 + 4)
3313       goto not_enough_data;
3315     gst_asf_demux_get_guid (&ext_guid, &data, &size);
3316     ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3317     ext.len = gst_asf_demux_get_uint16 (&data, &size);
3319     sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3320     GST_LOG ("payload systems info len = %u", sys_info_len);
3321     if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3322       goto not_enough_data;
3324     esp.payload_extensions[i] = ext;
3325   }
3327   GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3329   /* there might be an optional STREAM_INFO object here now; if not, we
3330    * should have parsed the corresponding stream info object already (since
3331    * we are parsing the extended stream properties objects delayed) */
3332   if (size == 0) {
3333     stream = gst_asf_demux_get_stream (demux, stream_num);
3334     goto done;
3335   }
3337   /* get size of the stream object */
3338   if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3339     goto not_enough_data;
3341   if (stream_obj.id != ASF_OBJ_STREAM)
3342     goto expected_stream_object;
3344   if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3345       stream_obj.size > (10 * 1024 * 1024))
3346     goto not_enough_data;
3348   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3350   /* process this stream object later after all the other 'normal' ones
3351    * have been processed (since the others are more important/non-hidden) */
3352   len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3353   if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3354     goto not_enough_data;
3356   /* parse stream object */
3357   stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3358   g_free (stream_obj_data);
3360 done:
3362   if (stream) {
3363     stream->ext_props = esp;
3365     /* try to set the framerate */
3366     if (stream->is_video && stream->caps) {
3367       GValue framerate = { 0 };
3368       GstStructure *s;
3369       gint num, denom;
3371       g_value_init (&framerate, GST_TYPE_FRACTION);
3373       num = GST_SECOND / 100;
3374       denom = esp.avg_time_per_frame;
3375       if (denom == 0) {
3376         /* avoid division by 0, assume 25/1 framerate */
3377         denom = GST_SECOND / 2500;
3378       }
3380       gst_value_set_fraction (&framerate, num, denom);
3382       stream->caps = gst_caps_make_writable (stream->caps);
3383       s = gst_caps_get_structure (stream->caps, 0);
3384       gst_structure_set_value (s, "framerate", &framerate);
3385       g_value_unset (&framerate);
3386       GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3387           num, denom, ((gdouble) num) / denom);
3388     }
3390     /* add language info now if we have it */
3391     if (stream->ext_props.lang_idx < demux->num_languages) {
3392       if (stream->pending_tags == NULL)
3393         stream->pending_tags = gst_tag_list_new ();
3394       GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3395           demux->languages[stream->ext_props.lang_idx]);
3396       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3397           GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3398           NULL);
3399     }
3400   } else {
3401     GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3402   }
3404   return GST_FLOW_OK;
3406   /* Errors */
3407 not_enough_data:
3408   {
3409     GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3410     return GST_FLOW_OK;         /* not absolutely fatal */
3411   }
3412 expected_stream_object:
3413   {
3414     GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3415         "object: expected embedded stream object, but got %s object instead!",
3416         gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3417     return GST_FLOW_OK;         /* not absolutely fatal */
3418   }
3421 static const gchar *
3422 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3424   const gchar *nick;
3426   nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3427   if (g_str_has_prefix (nick, "ASF_OBJ_"))
3428     nick += strlen ("ASF_OBJ_");
3430   if (demux->objpath == NULL) {
3431     demux->objpath = g_strdup (nick);
3432   } else {
3433     gchar *newpath;
3435     newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3436     g_free (demux->objpath);
3437     demux->objpath = newpath;
3438   }
3440   return (const gchar *) demux->objpath;
3443 static void
3444 gst_asf_demux_pop_obj (GstASFDemux * demux)
3446   gchar *s;
3448   if ((s = g_strrstr (demux->objpath, "/"))) {
3449     *s = '\0';
3450   } else {
3451     g_free (demux->objpath);
3452     demux->objpath = NULL;
3453   }
3456 static void
3457 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3459   GSList *l;
3460   guint i;
3462   /* Parse the queued extended stream property objects and add the info
3463    * to the existing streams or add the new embedded streams, but without
3464    * activating them yet */
3465   GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3466       g_slist_length (demux->ext_stream_props));
3468   for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3469     GstBuffer *buf = GST_BUFFER (l->data);
3471     GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3472     gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
3473         GST_BUFFER_SIZE (buf));
3474     gst_buffer_unref (buf);
3475   }
3476   g_slist_free (demux->ext_stream_props);
3477   demux->ext_stream_props = NULL;
3480 #if 0
3481 static void
3482 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3484   guint i, j;
3486   for (i = 0; i < demux->num_streams; ++i) {
3487     AsfStream *stream;
3488     gboolean is_hidden;
3489     GSList *x;
3491     stream = &demux->stream[i];
3493     GST_LOG_OBJECT (demux, "checking  stream %2u", stream->id);
3495     if (stream->active) {
3496       GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3497       continue;
3498     }
3500     is_hidden = FALSE;
3501     for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3502       guint8 *mes;
3504       /* check for each mutual exclusion whether it affects this stream */
3505       for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3506         if (*mes == stream->id) {
3507           /* if yes, check if we've already added streams that are mutually
3508            * exclusive with the stream we're about to add */
3509           for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3510             for (j = 0; j < demux->num_streams; ++j) {
3511               /* if the broadcast flag is set, assume the hidden streams aren't
3512                * actually streamed and hide them (or playbin won't work right),
3513                * otherwise assume their data is available */
3514               if (demux->stream[j].id == *mes && demux->broadcast) {
3515                 is_hidden = TRUE;
3516                 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3517                     "mutually exclusive with already existing stream ID %d, "
3518                     "hiding stream", stream->id, demux->stream[j].id);
3519                 goto next;
3520               }
3521             }
3522           }
3523           break;
3524         }
3525       }
3526     }
3528   next:
3530     /* FIXME: we should do stream activation based on preroll data in
3531      * streaming mode too */
3532     if (demux->streaming && !is_hidden)
3533       gst_asf_demux_activate_stream (demux, stream);
3534   }
3536 #endif
3538 static GstFlowReturn
3539 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3540     guint64 * p_size)
3542   GstFlowReturn ret = GST_FLOW_OK;
3543   AsfObject obj;
3544   guint64 obj_data_size;
3546   if (*p_size < ASF_OBJECT_HEADER_SIZE)
3547     return ASF_FLOW_NEED_MORE_DATA;
3549   asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
3550   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3552   obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3554   if (*p_size < obj_data_size)
3555     return ASF_FLOW_NEED_MORE_DATA;
3557   gst_asf_demux_push_obj (demux, obj.id);
3559   GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3561   switch (obj.id) {
3562     case ASF_OBJ_STREAM:{
3563       AsfStream *stream;
3565       stream =
3566           gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3568       ret = GST_FLOW_OK;
3569       break;
3570     }
3571     case ASF_OBJ_FILE:
3572       ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3573       break;
3574     case ASF_OBJ_HEADER:
3575       ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3576       break;
3577     case ASF_OBJ_COMMENT:
3578       ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3579       break;
3580     case ASF_OBJ_HEAD1:
3581       ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3582       break;
3583     case ASF_OBJ_BITRATE_PROPS:
3584       ret =
3585           gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3586           obj_data_size);
3587       break;
3588     case ASF_OBJ_EXT_CONTENT_DESC:
3589       ret =
3590           gst_asf_demux_process_ext_content_desc (demux, *p_data,
3591           obj_data_size);
3592       break;
3593     case ASF_OBJ_METADATA_OBJECT:
3594       ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3595       break;
3596     case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3597       GstBuffer *buf;
3599       /* process these later, we might not have parsed the corresponding
3600        * stream object yet */
3601       GST_LOG ("%s: queued for later parsing", demux->objpath);
3602       buf = gst_buffer_new_and_alloc (obj_data_size);
3603       memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3604       demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3605       ret = GST_FLOW_OK;
3606       break;
3607     }
3608     case ASF_OBJ_LANGUAGE_LIST:
3609       ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3610       break;
3611     case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3612       ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3613           obj_data_size);
3614       break;
3615     case ASF_OBJ_SIMPLE_INDEX:
3616       ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3617       break;
3618     case ASF_OBJ_CONTENT_ENCRYPTION:
3619     case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3620     case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3621       goto error_encrypted;
3622     case ASF_OBJ_CONCEAL_NONE:
3623     case ASF_OBJ_HEAD2:
3624     case ASF_OBJ_UNDEFINED:
3625     case ASF_OBJ_CODEC_COMMENT:
3626     case ASF_OBJ_INDEX:
3627     case ASF_OBJ_PADDING:
3628     case ASF_OBJ_BITRATE_MUTEX:
3629     case ASF_OBJ_COMPATIBILITY:
3630     case ASF_OBJ_INDEX_PLACEHOLDER:
3631     case ASF_OBJ_INDEX_PARAMETERS:
3632     case ASF_OBJ_STREAM_PRIORITIZATION:
3633     case ASF_OBJ_SCRIPT_COMMAND:
3634     default:
3635       /* Unknown/unhandled object, skip it and hope for the best */
3636       GST_INFO ("%s: skipping object", demux->objpath);
3637       ret = GST_FLOW_OK;
3638       break;
3639   }
3641   /* this can't fail, we checked the number of bytes available before */
3642   gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3644   GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3646   gst_asf_demux_pop_obj (demux);
3648   return ret;
3650 /* ERRORS */
3651 error_encrypted:
3652   {
3653     GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3654     return GST_FLOW_ERROR;
3655   }
3658 static void
3659 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3660     GstBuffer ** p_buffer)
3662   GstBuffer *descrambled_buffer;
3663   GstBuffer *scrambled_buffer;
3664   GstBuffer *sub_buffer;
3665   guint offset;
3666   guint off;
3667   guint row;
3668   guint col;
3669   guint idx;
3671   /* descrambled_buffer is initialised in the first iteration */
3672   descrambled_buffer = NULL;
3673   scrambled_buffer = *p_buffer;
3675   if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3676     return;
3678   for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3679       offset += demux->ds_chunk_size) {
3680     off = offset / demux->ds_chunk_size;
3681     row = off / demux->span;
3682     col = off % demux->span;
3683     idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3684     GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3685         col, off, demux->ds_chunk_size);
3686     GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3687         GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3688     GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3689         GST_BUFFER_SIZE (scrambled_buffer));
3690     sub_buffer =
3691         gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3692         demux->ds_chunk_size);
3693     if (!offset) {
3694       descrambled_buffer = sub_buffer;
3695     } else {
3696       descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3697     }
3698   }
3700   gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3701       GST_BUFFER_COPY_TIMESTAMPS);
3703   /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3705   gst_buffer_unref (scrambled_buffer);
3706   *p_buffer = descrambled_buffer;
3709 static gboolean
3710 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3712   GstASFDemux *demux = GST_ASF_DEMUX (element);
3713   gint i;
3715   GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3717   for (i = 0; i < demux->num_streams; ++i) {
3718     gst_event_ref (event);
3719     if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3720       gst_event_unref (event);
3721       return TRUE;
3722     }
3723   }
3725   gst_event_unref (event);
3726   return FALSE;
3729 /* takes ownership of the passed event */
3730 static gboolean
3731 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3733   gboolean ret = TRUE;
3734   gint i;
3736   GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3737       GST_EVENT_TYPE_NAME (event));
3739   for (i = 0; i < demux->num_streams; ++i) {
3740     gst_event_ref (event);
3741     ret &= gst_pad_push_event (demux->stream[i].pad, event);
3742   }
3743   gst_event_unref (event);
3744   return ret;
3747 static const GstQueryType *
3748 gst_asf_demux_get_src_query_types (GstPad * pad)
3750   static const GstQueryType types[] = {
3751     GST_QUERY_POSITION,
3752     GST_QUERY_DURATION,
3753     GST_QUERY_SEEKING,
3754     0
3755   };
3757   return types;
3760 static gboolean
3761 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3763   GstASFDemux *demux;
3764   gboolean res = FALSE;
3766   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3768   GST_DEBUG ("handling %s query",
3769       gst_query_type_get_name (GST_QUERY_TYPE (query)));
3771   switch (GST_QUERY_TYPE (query)) {
3772     case GST_QUERY_DURATION:
3773     {
3774       GstFormat format;
3776       gst_query_parse_duration (query, &format, NULL);
3778       if (format != GST_FORMAT_TIME) {
3779         GST_LOG ("only support duration queries in TIME format");
3780         break;
3781       }
3783       GST_OBJECT_LOCK (demux);
3785       if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3786         GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3787             GST_TIME_ARGS (demux->segment.duration));
3789         gst_query_set_duration (query, GST_FORMAT_TIME,
3790             demux->segment.duration);
3792         res = TRUE;
3793       } else {
3794         GST_LOG ("duration not known yet");
3795       }
3797       GST_OBJECT_UNLOCK (demux);
3798       break;
3799     }
3801     case GST_QUERY_POSITION:{
3802       GstFormat format;
3804       gst_query_parse_position (query, &format, NULL);
3806       if (format != GST_FORMAT_TIME) {
3807         GST_LOG ("only support position queries in TIME format");
3808         break;
3809       }
3811       GST_OBJECT_LOCK (demux);
3813       if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3814         GST_LOG ("returning position: %" GST_TIME_FORMAT,
3815             GST_TIME_ARGS (demux->segment.last_stop));
3817         gst_query_set_position (query, GST_FORMAT_TIME,
3818             demux->segment.last_stop);
3820         res = TRUE;
3821       } else {
3822         GST_LOG ("position not known yet");
3823       }
3825       GST_OBJECT_UNLOCK (demux);
3826       break;
3827     }
3829     case GST_QUERY_SEEKING:{
3830       GstFormat format;
3832       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3833       if (format == GST_FORMAT_TIME) {
3834         gint64 duration;
3836         GST_OBJECT_LOCK (demux);
3837         duration = demux->segment.duration;
3838         GST_OBJECT_UNLOCK (demux);
3840         if (!demux->streaming || !demux->seekable) {
3841           gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3842               duration);
3843           res = TRUE;
3844         } else {
3845           GstFormat fmt;
3846           gboolean seekable;
3848           /* try downstream first in TIME */
3849           res = gst_pad_query_default (pad, query);
3851           gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3852           GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3853               GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3854           /* if no luck, maybe in BYTES */
3855           if (!seekable || fmt != GST_FORMAT_TIME) {
3856             GstQuery *q;
3858             q = gst_query_new_seeking (GST_FORMAT_BYTES);
3859             if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3860               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3861               GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3862                   GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3863               if (fmt != GST_FORMAT_BYTES)
3864                 seekable = FALSE;
3865             }
3866             gst_query_unref (q);
3867             gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3868                 duration);
3869             res = TRUE;
3870           }
3871         }
3872       } else
3873         GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3874       break;
3875     }
3877     case GST_QUERY_LATENCY:
3878     {
3879       gboolean live;
3880       GstClockTime min, max;
3882       /* preroll delay does not matter in non-live pipeline,
3883        * but we might end up in a live (rtsp) one ... */
3885       /* first forward */
3886       res = gst_pad_query_default (pad, query);
3887       if (!res)
3888         break;
3890       gst_query_parse_latency (query, &live, &min, &max);
3892       GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
3893           GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3894           GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3896       GST_OBJECT_LOCK (demux);
3897       if (min != -1)
3898         min += demux->latency;
3899       if (max != -1)
3900         max += demux->latency;
3901       GST_OBJECT_UNLOCK (demux);
3903       gst_query_set_latency (query, live, min, max);
3904       break;
3905     }
3906     default:
3907       res = gst_pad_query_default (pad, query);
3908       break;
3909   }
3911   gst_object_unref (demux);
3912   return res;
3915 static GstStateChangeReturn
3916 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3918   GstASFDemux *demux = GST_ASF_DEMUX (element);
3919   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3921   switch (transition) {
3922     case GST_STATE_CHANGE_NULL_TO_READY:{
3923       gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3924       demux->need_newsegment = TRUE;
3925       demux->segment_running = FALSE;
3926       demux->accurate = FALSE;
3927       demux->adapter = gst_adapter_new ();
3928       demux->metadata = gst_caps_new_empty ();
3929       demux->global_metadata = gst_structure_empty_new ("metadata");
3930       demux->data_size = 0;
3931       demux->data_offset = 0;
3932       demux->index_offset = 0;
3933       demux->base_offset = 0;
3934       break;
3935     }
3936     default:
3937       break;
3938   }
3940   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3941   if (ret == GST_STATE_CHANGE_FAILURE)
3942     return ret;
3944   switch (transition) {
3945     case GST_STATE_CHANGE_PAUSED_TO_READY:
3946     case GST_STATE_CHANGE_READY_TO_NULL:
3947       gst_asf_demux_reset (demux, FALSE);
3948       break;
3949     default:
3950       break;
3951   }
3953   return ret;