]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugins-ugly0-10.git/blob - gst/asfdemux/gstasfdemux.c
asfdemux: post tags only after we've created our source pads
[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 <stdlib.h>
41 #include <string.h>
43 #include "gstasfdemux.h"
44 #include "asfheaders.h"
45 #include "asfpacket.h"
47 static GstStaticPadTemplate gst_asf_demux_sink_template =
48 GST_STATIC_PAD_TEMPLATE ("sink",
49     GST_PAD_SINK,
50     GST_PAD_ALWAYS,
51     GST_STATIC_CAPS ("video/x-ms-asf")
52     );
54 static GstStaticPadTemplate audio_src_template =
55 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
56     GST_PAD_SRC,
57     GST_PAD_SOMETIMES,
58     GST_STATIC_CAPS_ANY);
60 static GstStaticPadTemplate video_src_template =
61 GST_STATIC_PAD_TEMPLATE ("video_%02d",
62     GST_PAD_SRC,
63     GST_PAD_SOMETIMES,
64     GST_STATIC_CAPS_ANY);
66 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
67 #define ASF_OBJECT_HEADER_SIZE  (16+8)
69 /* FIXME: get rid of this */
70 /* abuse this GstFlowReturn enum for internal usage */
71 #define ASF_FLOW_NEED_MORE_DATA  99
73 #define gst_asf_get_flow_name(flow)    \
74   (flow == ASF_FLOW_NEED_MORE_DATA) ?  \
75   "need-more-data" : gst_flow_get_name (flow)
77 GST_DEBUG_CATEGORY (asfdemux_dbg);
79 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
80     GstStateChange transition);
81 static gboolean gst_asf_demux_element_send_event (GstElement * element,
82     GstEvent * event);
83 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
84     GstEvent * event);
85 static gboolean gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query);
86 static const GstQueryType *gst_asf_demux_get_src_query_types (GstPad * pad);
87 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstBuffer * buf);
88 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstEvent * event);
89 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
90     guint8 ** p_data, guint64 * p_size);
91 static gboolean gst_asf_demux_activate (GstPad * sinkpad);
92 static gboolean gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active);
93 static gboolean gst_asf_demux_activate_pull (GstPad * sinkpad, gboolean active);
94 static void gst_asf_demux_loop (GstASFDemux * demux);
95 static void
96 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
97 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
98 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
99 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
100 static gboolean
101 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
102 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
103     AsfStream * stream, GstBuffer ** p_buffer);
104 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
105     AsfStream * stream);
106 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
107     guint stream_num);
109 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
111 static void
112 gst_asf_demux_base_init (gpointer g_class)
114   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
115   static GstElementDetails gst_asf_demux_details = {
116     "ASF Demuxer",
117     "Codec/Demuxer",
118     "Demultiplexes ASF Streams",
119     "Owen Fraser-Green <owen@discobabe.net>"
120   };
122   gst_element_class_add_pad_template (element_class,
123       gst_static_pad_template_get (&audio_src_template));
124   gst_element_class_add_pad_template (element_class,
125       gst_static_pad_template_get (&video_src_template));
126   gst_element_class_add_pad_template (element_class,
127       gst_static_pad_template_get (&gst_asf_demux_sink_template));
129   gst_element_class_set_details (element_class, &gst_asf_demux_details);
132 static void
133 gst_asf_demux_class_init (GstASFDemuxClass * klass)
135   GstElementClass *gstelement_class;
137   gstelement_class = (GstElementClass *) klass;
139   gstelement_class->change_state =
140       GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
141   gstelement_class->send_event =
142       GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
145 static void
146 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
148   gst_caps_replace (&stream->caps, NULL);
149   if (stream->pending_tags) {
150     gst_tag_list_free (stream->pending_tags);
151     stream->pending_tags = NULL;
152   }
153   if (stream->pad) {
154     if (stream->active)
155       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
156     else
157       gst_object_unref (stream->pad);
158     stream->pad = NULL;
159   }
160   if (stream->payloads) {
161     g_array_free (stream->payloads, TRUE);
162     stream->payloads = NULL;
163   }
164   if (stream->ext_props.valid) {
165     g_free (stream->ext_props.payload_extensions);
166     stream->ext_props.payload_extensions = NULL;
167   }
170 static void
171 gst_asf_demux_reset (GstASFDemux * demux)
173   GST_LOG_OBJECT (demux, "resetting");
175   gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
176   demux->segment_running = FALSE;
177   if (demux->adapter) {
178     gst_adapter_clear (demux->adapter);
179     g_object_unref (demux->adapter);
180     demux->adapter = NULL;
181   }
182   if (demux->taglist) {
183     gst_tag_list_free (demux->taglist);
184     demux->taglist = NULL;
185   }
186   if (demux->metadata) {
187     gst_caps_unref (demux->metadata);
188     demux->metadata = NULL;
189   }
190   demux->state = GST_ASF_DEMUX_STATE_HEADER;
191   g_free (demux->objpath);
192   demux->objpath = NULL;
193   g_strfreev (demux->languages);
194   demux->languages = NULL;
195   demux->num_languages = 0;
196   g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
197       NULL);
198   g_slist_free (demux->ext_stream_props);
199   demux->ext_stream_props = NULL;
200   while (demux->num_streams > 0) {
201     gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
202     --demux->num_streams;
203   }
204   memset (demux->stream, 0, sizeof (demux->stream));
205   demux->num_audio_streams = 0;
206   demux->num_video_streams = 0;
207   demux->num_streams = 0;
208   demux->activated_streams = FALSE;
209   demux->first_ts = GST_CLOCK_TIME_NONE;
210   demux->segment_ts = GST_CLOCK_TIME_NONE;
211   demux->in_gap = 0;
212   gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
213   demux->state = GST_ASF_DEMUX_STATE_HEADER;
214   demux->seekable = FALSE;
215   demux->broadcast = FALSE;
216   demux->sidx_interval = 0;
217   demux->sidx_num_entries = 0;
218   g_free (demux->sidx_entries);
219   demux->sidx_entries = NULL;
222 static void
223 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
225   demux->sinkpad =
226       gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
227   gst_pad_set_chain_function (demux->sinkpad,
228       GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
229   gst_pad_set_event_function (demux->sinkpad,
230       GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
231   gst_pad_set_activate_function (demux->sinkpad,
232       GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
233   gst_pad_set_activatepull_function (demux->sinkpad,
234       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
235   gst_pad_set_activatepush_function (demux->sinkpad,
236       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
237   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
239   /* set initial state */
240   gst_asf_demux_reset (demux);
243 static gboolean
244 gst_asf_demux_activate (GstPad * sinkpad)
246   if (gst_pad_check_pull_range (sinkpad)) {
247     return gst_pad_activate_pull (sinkpad, TRUE);
248   } else {
249     return gst_pad_activate_push (sinkpad, TRUE);
250   }
253 static gboolean
254 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
256   GstASFDemux *demux;
258   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
260   demux->state = GST_ASF_DEMUX_STATE_HEADER;
261   demux->streaming = TRUE;
263   return TRUE;
266 static gboolean
267 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
269   GstASFDemux *demux;
271   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
273   if (active) {
274     demux->state = GST_ASF_DEMUX_STATE_HEADER;
275     demux->streaming = FALSE;
277     return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
278         demux);
279   } else {
280     return gst_pad_stop_task (pad);
281   }
285 static gboolean
286 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
288   GstASFDemux *demux;
289   gboolean ret = TRUE;
291   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
293   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
294   switch (GST_EVENT_TYPE (event)) {
295     case GST_EVENT_NEWSEGMENT:{
296       GstFormat newsegment_format;
297       gint64 newsegment_start, stop, time;
298       gdouble rate, arate;
299       gboolean update;
301       gst_event_parse_new_segment_full (event, &update, &rate, &arate,
302           &newsegment_format, &newsegment_start, &stop, &time);
304       if (newsegment_format == GST_FORMAT_BYTES) {
305         if (demux->packet_size && newsegment_start > demux->data_offset)
306           demux->packet = (newsegment_start - demux->data_offset) /
307               demux->packet_size;
308         else
309           demux->packet = 0;
310       } else if (newsegment_format == GST_FORMAT_TIME) {
311         /* do not know packet position, not really a problem */
312         demux->packet = -1;
313       } else {
314         GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
315         gst_event_unref (event);
316         break;
317       }
319       /* record upstream segment for interpolation */
320       if (newsegment_format != demux->in_segment.format)
321         gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
322       gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate,
323           newsegment_format, newsegment_start, stop, time);
325       /* in either case, clear some state and generate newsegment later on */
326       GST_OBJECT_LOCK (demux);
327       demux->segment_ts = GST_CLOCK_TIME_NONE;
328       demux->in_gap = GST_CLOCK_TIME_NONE;
329       demux->need_newsegment = TRUE;
330       gst_asf_demux_reset_stream_state_after_discont (demux);
331       GST_OBJECT_UNLOCK (demux);
333       gst_event_unref (event);
334       break;
335     }
336     case GST_EVENT_EOS:{
337       if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
338         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
339             (_("This stream contains no data.")),
340             ("got eos and didn't receive a complete header object"));
341         break;
342       }
343       GST_OBJECT_LOCK (demux);
344       gst_adapter_clear (demux->adapter);
345       GST_OBJECT_UNLOCK (demux);
346       gst_asf_demux_send_event_unlocked (demux, event);
347       break;
348     }
350     case GST_EVENT_FLUSH_STOP:
351       GST_OBJECT_LOCK (demux);
352       gst_asf_demux_reset_stream_state_after_discont (demux);
353       GST_OBJECT_UNLOCK (demux);
354       gst_asf_demux_send_event_unlocked (demux, event);
355       /* upon activation, latency is no longer introduced, e.g. after seek */
356       if (demux->activated_streams)
357         demux->latency = 0;
358       break;
360     default:
361       ret = gst_pad_event_default (pad, event);
362       break;
363   }
365   gst_object_unref (demux);
366   return ret;
369 static gboolean
370 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
371     GstClockTime seek_time, GstClockTime * p_idx_time)
373   GstClockTime idx_time;
374   guint idx;
376   if (demux->sidx_num_entries == 0 || demux->sidx_interval == 0)
377     return FALSE;
379   idx = (guint) (seek_time / demux->sidx_interval);
381   /* FIXME: seek beyond end of file should result in immediate EOS from
382    * streaming thread instead of a failed seek */
383   if (idx >= demux->sidx_num_entries)
384     return FALSE;
386   *packet = demux->sidx_entries[idx];
388   /* so we get closer to the actual time of the packet ... actually, let's not
389    * do this, since we throw away superfluous payloads before the seek position
390    * anyway; this way, our key unit seek 'snap resolution' is a bit better
391    * (ie. same as index resolution) */
392   /*
393      while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
394      --idx;
395    */
397   idx_time = demux->sidx_interval * idx;
399   GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
400       GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
401       GST_TIME_ARGS (idx_time));
403   if (p_idx_time)
404     *p_idx_time = idx_time;
406   return TRUE;
409 static void
410 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
412   guint n;
414   gst_adapter_clear (demux->adapter);
416   GST_DEBUG_OBJECT (demux, "reset stream state");
418   for (n = 0; n < demux->num_streams; n++) {
419     demux->stream[n].discont = TRUE;
420     demux->stream[n].last_flow = GST_FLOW_OK;
422     while (demux->stream[n].payloads->len > 0) {
423       AsfPayload *payload;
424       guint last;
426       last = demux->stream[n].payloads->len - 1;
427       payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
428       gst_buffer_replace (&payload->buf, NULL);
429       g_array_remove_index (demux->stream[n].payloads, last);
430     }
431   }
434 static void
435 gst_asf_demux_mark_discont (GstASFDemux * demux)
437   guint n;
439   GST_DEBUG_OBJECT (demux, "Mark stream discont");
441   for (n = 0; n < demux->num_streams; n++)
442     demux->stream[n].discont = TRUE;
445 /* do a seek in push based mode */
446 static gboolean
447 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
449   gdouble rate;
450   GstFormat format;
451   GstSeekFlags flags;
452   GstSeekType cur_type, stop_type;
453   gint64 cur, stop;
454   guint packet;
455   gboolean res;
457   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
458       &stop_type, &stop);
460   stop_type = GST_SEEK_TYPE_NONE;
461   stop = -1;
463   GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
465   /* determine packet, by index or by estimation */
466   if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL)) {
467     packet = (guint) gst_util_uint64_scale (demux->num_packets,
468         cur, demux->play_time);
469   }
471   if (packet > demux->num_packets) {
472     GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
473         "seek aborted.");
474     return FALSE;
475   }
477   GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
479   cur = demux->data_offset + (packet * demux->packet_size);
481   GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
482       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
483   /* BYTE seek event */
484   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
485       stop_type, stop);
486   res = gst_pad_push_event (demux->sinkpad, event);
488   return res;
491 static gboolean
492 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
494   GstClockTime idx_time;
495   GstSegment segment;
496   GstSeekFlags flags;
497   GstSeekType cur_type, stop_type;
498   GstFormat format;
499   gboolean only_need_update;
500   gboolean keyunit_sync;
501   gboolean accurate;
502   gboolean flush;
503   gdouble rate;
504   gint64 cur, stop;
505   gint64 seek_time;
506   guint packet;
508   if (demux->seekable == FALSE || demux->packet_size == 0 ||
509       demux->num_packets == 0 || demux->play_time == 0) {
510     GST_LOG_OBJECT (demux, "stream is not seekable");
511     return FALSE;
512   }
514   if (!demux->activated_streams) {
515     GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
516     return FALSE;
517   }
519   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
520       &stop_type, &stop);
522   if (format != GST_FORMAT_TIME) {
523     GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
524     return FALSE;
525   }
527   if (rate <= 0.0) {
528     GST_LOG_OBJECT (demux, "backward playback is not supported yet");
529     return FALSE;
530   }
532   flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
533   accurate = ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
534   keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
536   if (demux->streaming) {
537     /* support it safely needs more segment handling, e.g. closing etc */
538     if (!flush) {
539       GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
540       return FALSE;
541     }
542     /* we can (re)construct the start later on, but not the end */
543     if (stop_type != GST_SEEK_TYPE_NONE) {
544       GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
545       return FALSE;
546     }
547     gst_event_ref (event);
548     /* upstream might handle TIME seek, e.g. mms or rtsp,
549      * or not, e.g. http, then we give it a hand */
550     if (!gst_pad_push_event (demux->sinkpad, event))
551       return gst_asf_demux_handle_seek_push (demux, event);
552     else
553       return TRUE;
554   }
556   /* unlock the streaming thread */
557   if (flush) {
558     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
559     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
560   } else {
561     gst_pad_pause_task (demux->sinkpad);
562   }
564   /* grab the stream lock so that streaming cannot continue, for
565    * non flushing seeks when the element is in PAUSED this could block
566    * forever */
567   GST_PAD_STREAM_LOCK (demux->sinkpad);
569   /* we now can stop flushing, since we have the stream lock now */
570   gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
572   if (flush)
573     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
575   /* operating on copy of segment until we know the seek worked */
576   segment = demux->segment;
578   if (demux->segment_running && !flush) {
579     GstEvent *newseg;
581     /* create the segment event to close the current segment */
582     newseg = gst_event_new_new_segment (TRUE, segment.rate,
583         GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
585     gst_asf_demux_send_event_unlocked (demux, newseg);
586   }
588   gst_segment_set_seek (&segment, rate, format, flags, cur_type,
589       cur, stop_type, stop, &only_need_update);
591   GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
592       "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
594   seek_time = segment.start;
596   /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
597    * real start of data and segment_start to indexed time for key unit seek*/
598   if (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time, &idx_time)) {
599     /* First try to query our source to see if it can convert for us. This is
600        the case when our source is an mms stream, notice that in this case
601        gstmms will do a time based seek to get the byte offset, this is not a
602        problem as the seek to this offset needs to happen anway. */
603     gint64 offset;
604     GstFormat dest_format = GST_FORMAT_BYTES;
606     if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
607             &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
608       packet = (offset - demux->data_offset) / demux->packet_size;
609       GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
610           " to bytes query result: %lld, data_ofset: %llu, packet_size: %u,"
611           " resulting packet: %u\n", GST_TIME_ARGS (seek_time), offset,
612           demux->data_offset, demux->packet_size, packet);
613     } else {
614       /* Hackety hack, this sucks. We just seek to an earlier position
615        *  and let the sinks throw away the stuff before the segment start */
616       if (flush && (accurate || keyunit_sync)) {
617         seek_time -= 5 * GST_SECOND;
618         if (seek_time < 0)
619           seek_time = 0;
620       }
622       packet = (guint) gst_util_uint64_scale (demux->num_packets,
623           seek_time, demux->play_time);
625       if (packet > demux->num_packets)
626         packet = demux->num_packets;
627     }
628   } else {
629     if (keyunit_sync) {
630       GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
631           GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
632           GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
633       segment.start = idx_time;
634       segment.last_stop = idx_time;
635       segment.time = idx_time;
636     }
637   }
639   GST_DEBUG_OBJECT (demux, "seeking to packet %u", packet);
641   GST_OBJECT_LOCK (demux);
642   demux->segment = segment;
643   demux->packet = packet;
644   demux->need_newsegment = TRUE;
645   gst_asf_demux_reset_stream_state_after_discont (demux);
646   GST_OBJECT_UNLOCK (demux);
648   /* restart our task since it might have been stopped when we did the flush */
649   gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
650       demux);
652   /* streaming can continue now */
653   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
655   return TRUE;
658 static gboolean
659 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
661   GstASFDemux *demux;
662   gboolean ret;
664   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
666   switch (GST_EVENT_TYPE (event)) {
667     case GST_EVENT_SEEK:
668       GST_LOG_OBJECT (pad, "seek event");
669       ret = gst_asf_demux_handle_seek_event (demux, event);
670       gst_event_unref (event);
671       break;
672     case GST_EVENT_QOS:
673     case GST_EVENT_NAVIGATION:
674       /* just drop these two silently */
675       gst_event_unref (event);
676       ret = FALSE;
677       break;
678     default:
679       GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
680       ret = gst_pad_event_default (pad, event);
681       break;
682   }
684   gst_object_unref (demux);
685   return ret;
688 static inline guint32
689 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
691   guint32 ret;
693   ret = gst_asf_identify_guid (guids, guid);
695   GST_LOG ("%s  0x%08x-0x%08x-0x%08x-0x%08x",
696       gst_asf_get_guid_nick (guids, ret),
697       guid->v1, guid->v2, guid->v3, guid->v4);
699   return ret;
702 typedef struct
704   AsfObjectID id;
705   guint64 size;
706 } AsfObject;
708 static gboolean
709 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
710     guint data_len, AsfObject * object)
712   ASFGuid guid;
714   if (data_len < ASF_OBJECT_HEADER_SIZE)
715     return FALSE;
717   guid.v1 = GST_READ_UINT32_LE (data + 0);
718   guid.v2 = GST_READ_UINT32_LE (data + 4);
719   guid.v3 = GST_READ_UINT32_LE (data + 8);
720   guid.v4 = GST_READ_UINT32_LE (data + 12);
722   object->size = GST_READ_UINT64_LE (data + 16);
724   /* FIXME: make asf_demux_identify_object_guid() */
725   object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
726   if (object->id == ASF_OBJ_UNDEFINED) {
727     GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
728         guid.v1, guid.v2, guid.v3, guid.v4);
729   }
731   return TRUE;
734 static GstFlowReturn
735 gst_asf_demux_chain_headers (GstASFDemux * demux)
737   GstFlowReturn flow;
738   AsfObject obj;
739   guint8 *header_data, *data = NULL;
740   guint64 header_size;
742   data = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
743   if (data == NULL)
744     goto need_more_data;
746   asf_demux_peek_object (demux, data, ASF_OBJECT_HEADER_SIZE, &obj);
747   if (obj.id != ASF_OBJ_HEADER)
748     goto wrong_type;
750   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
752   /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
753   if (gst_adapter_available (demux->adapter) < obj.size + 50)
754     goto need_more_data;
756   data = gst_adapter_take (demux->adapter, obj.size + 50);
758   header_data = data;
759   header_size = obj.size;
760   flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
761   if (flow != GST_FLOW_OK)
762     goto parse_failed;
764   /* calculate where the packet data starts */
765   demux->data_offset = obj.size + 50;
767   /* now parse the beginning of the ASF_OBJ_DATA object */
768   if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
769     goto wrong_type;
771   if (demux->num_streams == 0)
772     goto no_streams;
774   g_free (data);
775   return GST_FLOW_OK;
777 /* NON-FATAL */
778 need_more_data:
779   {
780     GST_LOG_OBJECT (demux, "not enough data in adapter yet");
781     return GST_FLOW_OK;
782   }
784 /* ERRORS */
785 wrong_type:
786   {
787     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
788         ("This doesn't seem to be an ASF file"));
789     g_free (data);
790     return GST_FLOW_ERROR;
791   }
792 no_streams:
793 parse_failed:
794   {
795     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
796         ("header parsing failed, or no streams found, flow = %s",
797             gst_flow_get_name (flow)));
798     g_free (data);
799     return GST_FLOW_ERROR;
800   }
803 static GstFlowReturn
804 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux)
806   int i;
807   GST_DEBUG_OBJECT (demux, "Aggregating");
809   for (i = 0; i < demux->num_streams; i++) {
810     if (demux->stream[i].active) {
811       GstFlowReturn flowret = demux->stream[i].last_flow;
812       GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
813           gst_flow_get_name (flowret));
814       if (flowret != GST_FLOW_NOT_LINKED)
815         return flowret;
816     }
817   }
819   /* If we got here, then all our active streams are not linked */
820   return GST_FLOW_NOT_LINKED;
823 static gboolean
824 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
825     GstBuffer ** p_buf, GstFlowReturn * p_flow)
827   GstFlowReturn flow;
829   GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
830       offset, size);
832   flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
834   if (p_flow)
835     *p_flow = flow;
837   if (flow != GST_FLOW_OK) {
838     GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
839         "+%u", gst_flow_get_name (flow), offset, size);
840     *p_buf = NULL;
841     return FALSE;
842   }
844   g_assert (*p_buf != NULL);
846   if (GST_BUFFER_SIZE (*p_buf) < size) {
847     GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
848         "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
849     gst_buffer_unref (*p_buf);
850     if (p_flow)
851       *p_flow = GST_FLOW_UNEXPECTED;
852     *p_buf = NULL;
853     return FALSE;
854   }
856   return TRUE;
859 static void
860 gst_asf_demux_pull_indices (GstASFDemux * demux)
862   GstBuffer *buf = NULL;
863   guint64 offset;
864   guint num_read = 0;
866   offset = demux->index_offset;
868   if (offset == 0) {
869     GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
870     return;
871   }
873   while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
874     GstFlowReturn flow;
875     AsfObject obj;
877     asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj);
878     gst_buffer_replace (&buf, NULL);
880     /* check for sanity */
881     if (obj.size > (5 * 1024 * 1024)) {
882       GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
883       break;
884     }
886     if (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf, NULL))
887       break;
889     GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
890         ", size %u", offset, (guint) obj.size);
892     offset += obj.size;         /* increase before _process_object changes it */
894     flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
895     gst_buffer_replace (&buf, NULL);
897     if (flow != GST_FLOW_OK)
898       break;
900     ++num_read;
901   }
902   GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
905 static gboolean
906 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
908   AsfObject obj;
910   asf_demux_peek_object (demux, data, 50, &obj);
911   if (obj.id != ASF_OBJ_DATA) {
912     GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
913     return FALSE;
914   }
916   demux->state = GST_ASF_DEMUX_STATE_DATA;
918   if (!demux->broadcast && obj.size > 50) {
919     demux->data_size = obj.size - 50;
920     /* CHECKME: for at least one file this is off by +158 bytes?! */
921     demux->index_offset = demux->data_offset + demux->data_size;
922   } else {
923     demux->data_size = 0;
924     demux->index_offset = 0;
925   }
927   demux->packet = 0;
929   if (!demux->broadcast) {
930     /* skip object header (24 bytes) and file GUID (16 bytes) */
931     demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
932   } else {
933     demux->num_packets = 0;
934   }
936   if (demux->num_packets == 0)
937     demux->seekable = FALSE;
939   /* fallback in the unlikely case that headers are inconsistent, can't hurt */
940   if (demux->data_size == 0 && demux->num_packets > 0) {
941     demux->data_size = demux->num_packets * demux->packet_size;
942     demux->index_offset = demux->data_offset + demux->data_size;
943   }
945   /* process pending stream objects and create pads for those */
946   gst_asf_demux_process_queued_extended_stream_objects (demux);
948   GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
949       "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
950       ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
951       demux->data_offset, demux->data_size, demux->index_offset);
953   return TRUE;
956 static gboolean
957 gst_asf_demux_pull_headers (GstASFDemux * demux)
959   GstFlowReturn flow;
960   AsfObject obj;
961   GstBuffer *buf = NULL;
962   guint64 size;
964   GST_LOG_OBJECT (demux, "reading headers");
966   /* pull HEADER object header, so we know its size */
967   if (!gst_asf_demux_pull_data (demux, 0, 16 + 8, &buf, NULL))
968     goto read_failed;
970   asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj);
971   gst_buffer_replace (&buf, NULL);
973   if (obj.id != ASF_OBJ_HEADER)
974     goto wrong_type;
976   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
978   /* pull HEADER object */
979   if (!gst_asf_demux_pull_data (demux, 0, obj.size, &buf, NULL))
980     goto read_failed;
982   size = obj.size;              /* don't want obj.size changed */
983   flow = gst_asf_demux_process_object (demux, &buf->data, &size);
984   gst_buffer_replace (&buf, NULL);
986   if (flow != GST_FLOW_OK) {
987     GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
988     goto parse_failed;
989   }
991   /* calculate where the packet data starts */
992   demux->data_offset = obj.size + 50;
994   /* now pull beginning of DATA object before packet data */
995   if (!gst_asf_demux_pull_data (demux, obj.size, 50, &buf, NULL))
996     goto read_failed;
998   if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
999     goto wrong_type;
1001   if (demux->num_streams == 0)
1002     goto no_streams;
1004   gst_buffer_replace (&buf, NULL);
1005   return TRUE;
1007 /* ERRORS */
1008 wrong_type:
1009   {
1010     gst_buffer_replace (&buf, NULL);
1011     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1012         ("This doesn't seem to be an ASF file"));
1013     return FALSE;
1014   }
1015 no_streams:
1016 read_failed:
1017 parse_failed:
1018   {
1019     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1020     return FALSE;
1021   }
1024 static gboolean
1025 all_streams_prerolled (GstASFDemux * demux)
1027   GstClockTime preroll_time;
1028   guint i, num_no_data = 0;
1030   preroll_time = demux->preroll;
1032   /* returns TRUE as long as there isn't a stream which (a) has data queued
1033    * and (b) the timestamp of last piece of data queued is < demux->preroll
1034    * AND there is at least one other stream with data queued */
1035   for (i = 0; i < demux->num_streams; ++i) {
1036     AsfPayload *last_payload;
1037     AsfStream *stream;
1038     guint last_idx;
1040     stream = &demux->stream[i];
1041     if (stream->payloads->len == 0) {
1042       ++num_no_data;
1043       GST_LOG_OBJECT (stream->pad, "no data queued");
1044       continue;
1045     }
1047     last_idx = stream->payloads->len - 1;
1048     last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1050     GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1051         GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1052         GST_TIME_ARGS (preroll_time));
1053     if (last_payload->ts <= preroll_time) {
1054       GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1055       return FALSE;
1056     }
1057   }
1059   if (num_no_data == demux->num_streams)
1060     return FALSE;
1062   return TRUE;
1065 #if 0
1066 static gboolean
1067 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1068     AsfStream * stream)
1070   GSList *l;
1072   for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1073     guint8 *mes;
1075     /* check for each mutual exclusion group whether it affects this stream */
1076     for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1077       if (*mes == stream->id) {
1078         /* we are in this group; let's check if we've already activated streams
1079          * that are in the same group (and hence mutually exclusive to this
1080          * one) */
1081         for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1082           guint i;
1084           for (i = 0; i < demux->num_streams; ++i) {
1085             if (demux->stream[i].id == *mes && demux->stream[i].active) {
1086               GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1087                   "to already active stream with ID %d", stream->id,
1088                   demux->stream[i].id);
1089               return TRUE;
1090             }
1091           }
1092         }
1093         /* we can only be in this group once, let's break out and move on to
1094          * the next mutual exclusion group */
1095         break;
1096       }
1097     }
1098   }
1100   return FALSE;
1102 #endif
1104 static gboolean
1105 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1107   guint i;
1109   if (demux->activated_streams)
1110     return TRUE;
1112   if (!all_streams_prerolled (demux) && !force) {
1113     GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1114     return FALSE;
1115   }
1117   for (i = 0; i < demux->num_streams; ++i) {
1118     AsfStream *stream = &demux->stream[i];
1120     if (stream->payloads->len > 0) {
1121       /* we don't check mutual exclusion stuff here; either we have data for
1122        * a stream, then we active it, or we don't, then we'll ignore it */
1123       GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1124       gst_asf_demux_activate_stream (demux, stream);
1125     } else {
1126       GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1127     }
1128   }
1130   demux->activated_streams = TRUE;
1131   GST_LOG_OBJECT (demux, "signalling no more pads");
1132   gst_element_no_more_pads (GST_ELEMENT (demux));
1133   return TRUE;
1136 /* returns the stream that has a complete payload with the lowest timestamp
1137  * queued, or NULL (we push things by timestamp because during the internal
1138  * prerolling we might accumulate more data then the external queues can take,
1139  * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1140 static AsfStream *
1141 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1143   AsfPayload *best_payload = NULL;
1144   AsfStream *best_stream = NULL;
1145   guint i;
1147   for (i = 0; i < demux->num_streams; ++i) {
1148     AsfStream *stream;
1150     stream = &demux->stream[i];
1152     /* Don't push any data until we have at least one payload that falls within
1153      * the current segment. This way we can remove out-of-segment payloads that
1154      * don't need to be decoded after a seek, sending only data from the
1155      * keyframe directly before our segment start */
1156     if (stream->payloads->len > 0) {
1157       AsfPayload *payload;
1158       guint last_idx;
1160       last_idx = stream->payloads->len - 1;
1161       payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1162       if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1163           payload->ts < demux->segment.start) {
1164         GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1165             GST_TIME_FORMAT " which is before our segment start %"
1166             GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1167             GST_TIME_ARGS (demux->segment.start));
1168         continue;
1169       }
1170     }
1172     /* Now see if there's a complete payload queued for this stream */
1173     if (stream->payloads->len > 0) {
1174       AsfPayload *payload;
1176       payload = &g_array_index (stream->payloads, AsfPayload, 0);
1177       if (!gst_asf_payload_is_complete (payload))
1178         continue;
1180       /* ... and whether its timestamp is lower than the current best */
1181       if (best_stream == NULL || best_payload->ts > payload->ts) {
1182         best_stream = stream;
1183         best_payload = payload;
1184       }
1185     }
1186   }
1188   return best_stream;
1191 static GstFlowReturn
1192 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1194   AsfStream *stream;
1196   if (G_UNLIKELY (!demux->activated_streams)) {
1197     if (!gst_asf_demux_check_activate_streams (demux, force))
1198       return GST_FLOW_OK;
1199     /* streams are now activated */
1200   }
1202   /* do we need to send a newsegment event */
1203   if (demux->need_newsegment) {
1205     /* wait until we had a chance to "lock on" some payload's timestamp */
1206     if (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts))
1207       return GST_FLOW_OK;
1208     else {
1209       /* safe default if insufficient upstream info */
1210       if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1211         demux->in_gap = 0;
1212     }
1214     if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1215         demux->segment.duration > 0) {
1216       /* slight HACK; prevent clipping of last bit */
1217       demux->segment.stop = demux->segment.duration + demux->in_gap;
1218     }
1220     GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1221         &demux->segment);
1223     /* note: we fix up all timestamps to start from 0, so this should be ok */
1224     gst_asf_demux_send_event_unlocked (demux,
1225         gst_event_new_new_segment (FALSE, demux->segment.rate,
1226             GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1227             demux->segment.start));
1229     /* now post any global tags we may have found */
1230     if (demux->taglist == NULL)
1231       demux->taglist = gst_tag_list_new ();
1233     gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1234         GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1236     GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1237     gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
1238     demux->taglist = NULL;
1240     demux->need_newsegment = FALSE;
1241     demux->segment_running = TRUE;
1242   }
1244   while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1245     AsfPayload *payload;
1247     payload = &g_array_index (stream->payloads, AsfPayload, 0);
1249     /* Do we have tags pending for this stream? */
1250     if (stream->pending_tags) {
1251       GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1252       gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1253           stream->pending_tags);
1254       stream->pending_tags = NULL;
1255     }
1257     /* We have the whole packet now so we should push the packet to
1258      * the src pad now. First though we should check if we need to do
1259      * descrambling */
1260     if (demux->span > 1) {
1261       gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1262     }
1264     payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1266     if (!payload->keyframe) {
1267       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1268     }
1270     if (stream->discont) {
1271       GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1272       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1273       stream->discont = FALSE;
1274     }
1276     gst_buffer_set_caps (payload->buf, stream->caps);
1278     /* (sort of) interpolate timestamps using upstream "frame of reference",
1279      * typically useful for live src, but might (unavoidably) mess with
1280      * position reporting if a live src is playing not so live content
1281      * (e.g. rtspsrc taking some time to fall back to tcp) */
1282     GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1283     GST_BUFFER_DURATION (payload->buf) = payload->duration;
1285     /* FIXME: we should really set durations on buffers if we can */
1287     GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1288         ", dur=%" GST_TIME_FORMAT " size=%u",
1289         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1290         GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1291         GST_BUFFER_SIZE (payload->buf));
1293     stream->last_flow = gst_pad_push (stream->pad, payload->buf);
1294     payload->buf = NULL;
1295     g_array_remove_index (stream->payloads, 0);
1296   }
1298   return gst_asf_demux_aggregate_flow_return (demux);
1301 static void
1302 gst_asf_demux_loop (GstASFDemux * demux)
1304   GstFlowReturn flow = GST_FLOW_OK;
1305   GstBuffer *buf = NULL;
1306   guint64 off;
1308   if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
1309     if (!gst_asf_demux_pull_headers (demux)) {
1310       flow = GST_FLOW_ERROR;
1311       goto pause;
1312     }
1314     gst_asf_demux_pull_indices (demux);
1315   }
1317   g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1319   if (demux->num_packets != 0 && demux->packet >= demux->num_packets)
1320     goto eos;
1322   GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1323       (guint) demux->num_packets);
1325   off = demux->data_offset + (demux->packet * demux->packet_size);
1327   if (!gst_asf_demux_pull_data (demux, off, demux->packet_size, &buf, &flow)) {
1328     GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1329     if (flow == GST_FLOW_UNEXPECTED)
1330       goto eos;
1331     else if (!GST_FLOW_IS_FATAL (flow)) {
1332       GST_DEBUG_OBJECT (demux, "Not fatal");
1333       goto pause;
1334     } else
1335       goto read_failed;
1336   }
1338   /* FIXME: maybe we should just skip broken packets and error out only
1339    * after a few broken packets in a row? */
1340   if (!gst_asf_demux_parse_packet (demux, buf))
1341     goto parse_error;
1343   gst_buffer_unref (buf);
1345   flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1347   ++demux->packet;
1349   if (demux->num_packets > 0 && demux->packet >= demux->num_packets) {
1350     GST_LOG_OBJECT (demux, "reached EOS");
1351     goto eos;
1352   }
1354   if (flow != GST_FLOW_OK) {
1355     GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1356     goto pause;
1357   }
1359   /* check if we're at the end of the configured segment */
1360   /* FIXME: check if segment end reached etc. */
1362   return;
1364 eos:
1365   {
1366     /* if we haven't activated our streams yet, this might be because we have
1367      * less data queued than required for preroll; force stream activation and
1368      * send any pending payloads before sending EOS */
1369     if (!demux->activated_streams)
1370       gst_asf_demux_push_complete_payloads (demux, TRUE);
1372     /* we want to push an eos or post a segment-done in any case */
1373     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1374       gint64 stop;
1376       /* for segment playback we need to post when (in stream time)
1377        * we stopped, this is either stop (when set) or the duration. */
1378       if ((stop = demux->segment.stop) == -1)
1379         stop = demux->segment.duration;
1381       GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1382       gst_element_post_message (GST_ELEMENT_CAST (demux),
1383           gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1384               stop));
1385     } else {
1386       /* normal playback, send EOS to all linked pads */
1387       GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1388       gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1389     }
1390     /* ... and fall through to pause */
1391     GST_DEBUG_OBJECT (demux, "EOSing");
1392   }
1393 pause:
1394   {
1395     GST_DEBUG_OBJECT (demux, "pausing task");
1396     demux->segment_running = FALSE;
1397     gst_pad_pause_task (demux->sinkpad);
1399     /* For the error cases (not EOS) */
1400     if (GST_FLOW_IS_FATAL (flow) || flow == GST_FLOW_NOT_LINKED) {
1401       /* Post an error. Hopefully something else already has, but if not... */
1402       GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1403           (_("Internal data stream error.")),
1404           ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1405     }
1406     return;
1407   }
1409 /* ERRORS */
1410 read_failed:
1411   {
1412     GST_DEBUG_OBJECT (demux, "Read failed, doh");
1413     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1414     flow = GST_FLOW_UNEXPECTED;
1415     goto pause;
1416   }
1417 parse_error:
1418   {
1419     gst_buffer_unref (buf);
1420     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1421         ("Error parsing ASF packet %u", (guint) demux->packet));
1422     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1423     flow = GST_FLOW_ERROR;
1424     goto pause;
1425   }
1428 static GstFlowReturn
1429 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1431   GstFlowReturn ret = GST_FLOW_OK;
1432   GstASFDemux *demux;
1434   demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1436   GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%"
1437       GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
1438       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1440   if (GST_BUFFER_IS_DISCONT (buf)) {
1441     GST_DEBUG_OBJECT (demux, "received DISCONT");
1442     gst_asf_demux_mark_discont (demux);
1443   }
1445   if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1446       GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
1447     demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1448     GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1449         ", interpolation gap: %" GST_TIME_FORMAT,
1450         GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1451   }
1453   gst_adapter_push (demux->adapter, buf);
1455   switch (demux->state) {
1456     case GST_ASF_DEMUX_STATE_HEADER:{
1457       ret = gst_asf_demux_chain_headers (demux);
1458       if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1459         break;
1460       /* otherwise fall through */
1461     }
1462     case GST_ASF_DEMUX_STATE_DATA:
1463     {
1464       guint64 data_size;
1466       data_size = demux->packet_size;
1468       while (gst_adapter_available (demux->adapter) >= data_size) {
1469         GstBuffer *buf;
1471         /* do not overshoot data section when streaming */
1472         if (demux->num_packets != 0 && demux->packet >= 0
1473             && demux->packet >= demux->num_packets)
1474           goto eos;
1476         buf = gst_adapter_take_buffer (demux->adapter, data_size);
1478         /* FIXME: maybe we should just skip broken packets and error out only
1479          * after a few broken packets in a row? */
1480         if (!gst_asf_demux_parse_packet (demux, buf)) {
1481           GST_WARNING_OBJECT (demux, "Parse error");
1482         }
1484         gst_buffer_unref (buf);
1486         ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1488         if (demux->packet >= 0)
1489           ++demux->packet;
1490       }
1491       break;
1492     }
1493     default:
1494       g_assert_not_reached ();
1495   }
1497 done:
1498   if (ret != GST_FLOW_OK)
1499     GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1501   return ret;
1503 eos:
1504   {
1505     GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1506     ret = GST_FLOW_UNEXPECTED;
1507     goto done;
1508   }
1511 static inline gboolean
1512 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1514   if (*p_size < num_bytes)
1515     return FALSE;
1517   *p_data += num_bytes;
1518   *p_size -= num_bytes;
1519   return TRUE;
1522 static inline guint8
1523 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1525   guint8 ret;
1527   g_assert (*p_size >= 1);
1528   ret = GST_READ_UINT8 (*p_data);
1529   *p_data += sizeof (guint8);
1530   *p_size -= sizeof (guint8);
1531   return ret;
1534 static inline guint16
1535 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1537   guint16 ret;
1539   g_assert (*p_size >= 2);
1540   ret = GST_READ_UINT16_LE (*p_data);
1541   *p_data += sizeof (guint16);
1542   *p_size -= sizeof (guint16);
1543   return ret;
1546 static inline guint32
1547 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1549   guint32 ret;
1551   g_assert (*p_size >= 4);
1552   ret = GST_READ_UINT32_LE (*p_data);
1553   *p_data += sizeof (guint32);
1554   *p_size -= sizeof (guint32);
1555   return ret;
1558 static inline guint64
1559 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1561   guint64 ret;
1563   g_assert (*p_size >= 8);
1564   ret = GST_READ_UINT64_LE (*p_data);
1565   *p_data += sizeof (guint64);
1566   *p_size -= sizeof (guint64);
1567   return ret;
1570 static inline guint32
1571 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1573   switch (type) {
1574     case 0:
1575       return 0;
1577     case 1:
1578       g_assert (*p_size >= 1);
1579       return gst_asf_demux_get_uint8 (p_data, p_size);
1581     case 2:
1582       g_assert (*p_size >= 2);
1583       return gst_asf_demux_get_uint16 (p_data, p_size);
1585     case 3:
1586       g_assert (*p_size >= 4);
1587       return gst_asf_demux_get_uint32 (p_data, p_size);
1589     default:
1590       break;
1591   }
1593   g_assert_not_reached ();
1596 static gboolean
1597 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1598     guint8 ** p_data, guint64 * p_size)
1600   *p_buf = NULL;
1602   if (*p_size < num_bytes_to_read)
1603     return FALSE;
1605   *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1606   memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1607   *p_data += num_bytes_to_read;
1608   *p_size -= num_bytes_to_read;
1609   return TRUE;
1612 static gboolean
1613 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1614     guint8 ** p_data, guint64 * p_size)
1616   *p_buf = NULL;
1618   if (*p_size < num_bytes_to_read)
1619     return FALSE;
1621   *p_buf = g_memdup (*p_data, num_bytes_to_read);
1622   *p_data += num_bytes_to_read;
1623   *p_size -= num_bytes_to_read;
1624   return TRUE;
1627 static gboolean
1628 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1629     guint8 ** p_data, guint64 * p_size)
1631   guint16 s_length;
1632   guint8 *s;
1634   *p_str = NULL;
1636   if (*p_size < 2)
1637     return FALSE;
1639   s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1641   if (p_strlen)
1642     *p_strlen = s_length;
1644   if (s_length == 0) {
1645     GST_WARNING ("zero-length string");
1646     *p_str = g_strdup ("");
1647     return TRUE;
1648   }
1650   if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1651     return FALSE;
1653   g_assert (s != NULL);
1655   /* just because They don't exist doesn't
1656    * mean They are not out to get you ... */
1657   if (s[s_length - 1] != '\0') {
1658     s = g_realloc (s, s_length + 1);
1659     s[s_length] = '\0';
1660   }
1662   *p_str = (gchar *) s;
1663   return TRUE;
1667 static void
1668 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
1670   g_assert (*p_size >= 4 * sizeof (guint32));
1672   guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
1673   guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
1674   guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
1675   guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
1678 static gboolean
1679 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
1680     guint64 * p_size)
1682   if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
1683     return FALSE;
1685   /* WAVEFORMATEX Structure */
1686   audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
1687   audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
1688   audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1689   audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
1690   audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
1691   audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
1692   /* Codec specific data size */
1693   audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
1694   return TRUE;
1697 static gboolean
1698 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
1699     guint64 * p_size)
1701   if (*p_size < (4 + 4 + 1 + 2))
1702     return FALSE;
1704   video->width = gst_asf_demux_get_uint32 (p_data, p_size);
1705   video->height = gst_asf_demux_get_uint32 (p_data, p_size);
1706   video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
1707   video->size = gst_asf_demux_get_uint16 (p_data, p_size);
1708   return TRUE;
1711 static gboolean
1712 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
1713     guint8 ** p_data, guint64 * p_size)
1715   if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
1716     return FALSE;
1718   fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
1719   fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
1720   fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
1721   fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
1722   fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
1723   fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
1724   fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
1725   fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1726   fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
1727   fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1728   fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
1729   return TRUE;
1732 AsfStream *
1733 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
1735   guint i;
1737   for (i = 0; i < demux->num_streams; i++) {
1738     if (demux->stream[i].id == id)
1739       return &demux->stream[i];
1740   }
1742   GST_WARNING ("Segment found for undefined stream: (%d)", id);
1743   return NULL;
1746 static void
1747 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
1748     GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
1750   AsfStream *stream;
1752   gst_pad_use_fixed_caps (src_pad);
1753   gst_pad_set_caps (src_pad, caps);
1755   gst_pad_set_event_function (src_pad,
1756       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
1757   gst_pad_set_query_type_function (src_pad,
1758       GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
1759   gst_pad_set_query_function (src_pad,
1760       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
1762   stream = &demux->stream[demux->num_streams];
1763   stream->caps = caps;
1764   stream->pad = src_pad;
1765   stream->id = id;
1766   stream->fps_known = !is_video;        /* bit hacky for audio */
1767   stream->is_video = is_video;
1768   stream->pending_tags = tags;
1769   stream->discont = TRUE;
1771   stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
1773   GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
1774       GST_PAD_NAME (src_pad), demux->num_streams, caps);
1776   ++demux->num_streams;
1778   stream->active = FALSE;
1781 static void
1782 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
1783     asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
1785   GstTagList *tags = NULL;
1786   GstBuffer *extradata = NULL;
1787   GstPad *src_pad;
1788   GstCaps *caps;
1789   guint16 size_left = 0;
1790   gchar *codec_name = NULL;
1791   gchar *name = NULL;
1793   size_left = audio->size;
1795   /* Create the audio pad */
1796   name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
1798   src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
1799   g_free (name);
1801   /* Swallow up any left over data and set up the 
1802    * standard properties from the header info */
1803   if (size_left) {
1804     GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
1805         "codec specific data", size_left);
1807     g_assert (size_left <= *p_size);
1808     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
1809   }
1811   /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
1812    * additional two bytes indicating extradata. */
1813   caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
1814       (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
1816   if (caps == NULL) {
1817     caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
1818         G_TYPE_INT, (gint) audio->codec_tag, NULL);
1819   }
1821   /* Informing about that audio format we just added */
1822   if (codec_name) {
1823     tags = gst_tag_list_new ();
1824     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
1825         codec_name, NULL);
1826     g_free (codec_name);
1827   }
1829   if (extradata)
1830     gst_buffer_unref (extradata);
1832   GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
1833       GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
1834       audio->codec_tag, tags);
1836   ++demux->num_audio_streams;
1838   gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
1841 static void
1842 gst_asf_demux_add_video_stream (GstASFDemux * demux,
1843     asf_stream_video_format * video, guint16 id,
1844     guint8 ** p_data, guint64 * p_size)
1846   GstTagList *tags = NULL;
1847   GstBuffer *extradata = NULL;
1848   GstPad *src_pad;
1849   GstCaps *caps;
1850   gchar *name = NULL;
1851   gchar *codec_name = NULL;
1852   gint size_left = video->size - 40;
1854   /* Create the video pad */
1855   name = g_strdup_printf ("video_%02d", demux->num_video_streams);
1856   src_pad = gst_pad_new_from_static_template (&video_src_template, name);
1857   g_free (name);
1859   /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
1860   if (size_left) {
1861     GST_LOG ("Video header has %d bytes of codec specific data", size_left);
1862     g_assert (size_left <= *p_size);
1863     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
1864   }
1866   GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
1868   /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
1869   caps = gst_riff_create_video_caps (video->tag, NULL,
1870       (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
1872   if (caps == NULL) {
1873     caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
1874         GST_TYPE_FOURCC, video->tag, NULL);
1875   } else {
1876     GstStructure *s;
1877     gint ax, ay;
1879     s = gst_asf_demux_get_metadata_for_stream (demux, id);
1880     if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
1881         gst_structure_get_int (s, "AspectRatioY", &ay)) {
1882       /* only copy sane values */
1883       if (ax > 0 && ay > 0) {
1884         gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1885             ax, ay, NULL);
1886       }
1887     }
1888     /* remove the framerate we will guess and add it later */
1889     s = gst_caps_get_structure (caps, 0);
1890     gst_structure_remove_field (s, "framerate");
1891   }
1893   /* add fourcc format to caps, some proprietary decoders seem to need it */
1894   gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
1896   if (codec_name) {
1897     tags = gst_tag_list_new ();
1898     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
1899         codec_name, NULL);
1900     g_free (codec_name);
1901   }
1903   if (extradata)
1904     gst_buffer_unref (extradata);
1906   GST_INFO ("Adding video stream #%u, id %u, codec %"
1907       GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
1908       GST_FOURCC_ARGS (video->tag), video->tag);
1910   ++demux->num_video_streams;
1912   gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
1915 static void
1916 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
1918   if (!stream->active) {
1919     GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
1920         GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
1921     gst_pad_set_active (stream->pad, TRUE);
1922     gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
1923     stream->active = TRUE;
1924   }
1927 static AsfStream *
1928 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
1929     guint64 size)
1931   AsfCorrectionType correction_type;
1932   AsfStreamType stream_type;
1933   GstClockTime time_offset;
1934   gboolean is_encrypted;
1935   guint16 stream_id;
1936   guint16 flags;
1937   ASFGuid guid;
1938   guint stream_specific_size;
1939   guint type_specific_size;
1940   guint unknown;
1942   /* Get the rest of the header's header */
1943   if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
1944     goto not_enough_data;
1946   gst_asf_demux_get_guid (&guid, &data, &size);
1947   stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
1949   gst_asf_demux_get_guid (&guid, &data, &size);
1950   correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
1952   time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
1954   type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
1955   stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
1957   flags = gst_asf_demux_get_uint16 (&data, &size);
1958   stream_id = flags & 0x7f;
1959   is_encrypted = !!((flags & 0x8000) << 15);
1960   unknown = gst_asf_demux_get_uint32 (&data, &size);
1962   GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
1963       stream_id, GST_TIME_ARGS (time_offset));
1965   switch (stream_type) {
1966     case ASF_STREAM_AUDIO:{
1967       asf_stream_audio audio_object;
1969       if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
1970         goto not_enough_data;
1972       GST_INFO ("Object is an audio stream with %u bytes of additional data",
1973           audio_object.size);
1975       gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
1976           &data, &size);
1978       switch (correction_type) {
1979         case ASF_CORRECTION_ON:{
1980           guint span, packet_size, chunk_size, data_size, silence_data;
1982           GST_INFO ("Using error correction");
1984           if (size < (1 + 2 + 2 + 2 + 1))
1985             goto not_enough_data;
1987           span = gst_asf_demux_get_uint8 (&data, &size);
1988           packet_size = gst_asf_demux_get_uint16 (&data, &size);
1989           chunk_size = gst_asf_demux_get_uint16 (&data, &size);
1990           data_size = gst_asf_demux_get_uint16 (&data, &size);
1991           silence_data = gst_asf_demux_get_uint8 (&data, &size);
1993           /* FIXME: shouldn't this be per-stream? */
1994           demux->span = span;
1996           GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
1997               packet_size, chunk_size, data_size, span, silence_data);
1999           if (demux->span > 1) {
2000             if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2001               /* Disable descrambling */
2002               demux->span = 0;
2003             } else {
2004               /* FIXME: this else branch was added for
2005                * weird_al_yankovic - the saga begins.asf */
2006               demux->ds_packet_size = packet_size;
2007               demux->ds_chunk_size = chunk_size;
2008             }
2009           } else {
2010             /* Descambling is enabled */
2011             demux->ds_packet_size = packet_size;
2012             demux->ds_chunk_size = chunk_size;
2013           }
2014 #if 0
2015           /* Now skip the rest of the silence data */
2016           if (data_size > 1)
2017             gst_bytestream_flush (demux->bs, data_size - 1);
2018 #else
2019           /* FIXME: CHECKME. And why -1? */
2020           if (data_size > 1) {
2021             if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2022               goto not_enough_data;
2023             }
2024           }
2025 #endif
2026           break;
2027         }
2028         case ASF_CORRECTION_OFF:{
2029           GST_INFO ("Error correction off");
2030           if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2031             goto not_enough_data;
2032           break;
2033         }
2034         default:
2035           GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2036               ("Audio stream using unknown error correction"));
2037           return NULL;
2038       }
2040       break;
2041     }
2043     case ASF_STREAM_VIDEO:{
2044       asf_stream_video_format video_format_object;
2045       asf_stream_video video_object;
2046       guint16 vsize;
2048       if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2049         goto not_enough_data;
2051       vsize = video_object.size - 40;   /* Byte order gets offset by single byte */
2053       GST_INFO ("object is a video stream with %u bytes of "
2054           "additional data", vsize);
2056       if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2057               &data, &size)) {
2058         goto not_enough_data;
2059       }
2061       gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2062           &data, &size);
2064       break;
2065     }
2067     default:
2068       GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2069           stream_id);
2070       break;
2071   }
2073   return gst_asf_demux_get_stream (demux, stream_id);
2075 not_enough_data:
2076   {
2077     GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2078     /* we'll error out later if we found no streams */
2079     return NULL;
2080   }
2083 static const gchar *
2084 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf16le,
2085     gsize name_len)
2087   const struct
2088   {
2089     const gchar *asf_name;
2090     const gchar *gst_name;
2091   } tags[] = {
2092     {
2093     "WM/Genre", GST_TAG_GENRE}, {
2094     "WM/AlbumTitle", GST_TAG_ALBUM}, {
2095     "WM/AlbumArtist", GST_TAG_ARTIST}, {
2096     "WM/Picture", GST_TAG_IMAGE}, {
2097     "WM/Track", GST_TAG_TRACK_NUMBER}, {
2098     "WM/Year", GST_TAG_DATE}
2099     /* { "WM/Composer", GST_TAG_COMPOSER } */
2100   };
2101   gchar *name_utf8;
2102   gsize in, out;
2103   guint i;
2105   /* convert name to UTF-8 */
2106   name_utf8 = g_convert (name_utf16le, name_len, "UTF-8", "UTF-16LE", &in,
2107       &out, NULL);
2109   if (name_utf8 == NULL) {
2110     GST_WARNING ("Failed to convert name to UTF8, skipping");
2111     return NULL;
2112   }
2114   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2115     if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2116       GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2117       g_free (name_utf8);
2118       return tags[i].gst_name;
2119     }
2120   }
2122   GST_LOG ("unhandled tagname '%s'", name_utf8);
2123   g_free (name_utf8);
2124   return NULL;
2127 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2128 static void
2129 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2131   GstTagList *t;
2133   GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2135   if (taglist == NULL)
2136     return;
2138   if (gst_tag_list_is_empty (taglist)) {
2139     gst_tag_list_free (taglist);
2140     return;
2141   }
2143   t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2144   gst_tag_list_free (demux->taglist);
2145   gst_tag_list_free (taglist);
2146   demux->taglist = t;
2147   GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2150 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING  0
2151 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY      1
2152 #define ASF_DEMUX_DATA_TYPE_DWORD           3
2154 static void
2155 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2156     guint tag_data_len)
2158   GstByteReader r;
2159   const guint8 *img_data;
2160   guint32 img_data_len;
2161   guint8 pic_type;
2163   gst_byte_reader_init (&r, tag_data, tag_data_len);
2165   /* skip mime type string (we don't trust it and do our own typefinding),
2166    * and also skip the description string, since we don't use it */
2167   if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2168       !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2169       !gst_byte_reader_skip_string_utf16 (&r) ||
2170       !gst_byte_reader_skip_string_utf16 (&r) ||
2171       !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2172     goto not_enough_data;
2173   }
2176   if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2177     GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2179   return;
2181 not_enough_data:
2182   {
2183     GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2184     GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2185     return;
2186   }
2189 /* Extended Content Description Object */
2190 static GstFlowReturn
2191 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2192     guint64 size)
2194   /* Other known (and unused) 'text/unicode' metadata available :
2195    *
2196    *   WM/Lyrics =
2197    *   WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2198    *   WMFSDKVersion = 9.00.00.2980
2199    *   WMFSDKNeeded = 0.0.0.0000
2200    *   WM/UniqueFileIdentifier = AMGa_id=R    15334;AMGp_id=P     5149;AMGt_id=T  2324984
2201    *   WM/Publisher = 4AD
2202    *   WM/Provider = AMG
2203    *   WM/ProviderRating = 8
2204    *   WM/ProviderStyle = Rock (similar to WM/Genre)
2205    *   WM/GenreID (similar to WM/Genre)
2206    *   WM/TrackNumber (same as WM/Track but as a string)
2207    *
2208    * Other known (and unused) 'non-text' metadata available :
2209    *
2210    *   WM/EncodingTime
2211    *   WM/MCDI
2212    *   IsVBR
2213    *
2214    * We might want to read WM/TrackNumber and use atoi() if we don't have
2215    * WM/Track
2216    */
2218   GstTagList *taglist;
2219   guint16 blockcount, i;
2221   GST_INFO_OBJECT (demux, "object is an extended content description");
2223   taglist = gst_tag_list_new ();
2225   /* Content Descriptor Count */
2226   if (size < 2)
2227     goto not_enough_data;
2229   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2231   for (i = 1; i <= blockcount; ++i) {
2232     const gchar *gst_tag_name;
2233     guint16 datatype;
2234     guint16 value_len;
2235     guint16 name_len;
2236     GValue tag_value = { 0, };
2237     gsize in, out;
2238     gchar *name;
2239     gchar *value;
2241     /* Descriptor */
2242     if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2243       goto not_enough_data;
2245     if (size < 2) {
2246       g_free (name);
2247       goto not_enough_data;
2248     }
2249     /* Descriptor Value Data Type */
2250     datatype = gst_asf_demux_get_uint16 (&data, &size);
2252     /* Descriptor Value (not really a string, but same thing reading-wise) */
2253     if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2254       g_free (name);
2255       goto not_enough_data;
2256     }
2258     gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name, name_len);
2259     if (gst_tag_name != NULL) {
2260       switch (datatype) {
2261         case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2262           gchar *value_utf8;
2264           value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2265               &in, &out, NULL);
2267           /* get rid of tags with empty value */
2268           if (value_utf8 != NULL && *value_utf8 != '\0') {
2269             value_utf8[out] = '\0';
2271             if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2272               guint year = atoi (value_utf8);
2274               if (year > 0) {
2275                 GDate *date = g_date_new_dmy (1, 1, year);
2277                 g_value_init (&tag_value, GST_TYPE_DATE);
2278                 gst_value_set_date (&tag_value, date);
2279                 g_date_free (date);
2280               }
2281             } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2282               guint id3v1_genre_id;
2283               const gchar *genre_str;
2285               if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2286                   ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2287                 GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2288                 g_free (value_utf8);
2289                 value_utf8 = g_strdup (genre_str);
2290               }
2291             } else {
2292               GType tag_type;
2294               /* convert tag from string to other type if required */
2295               tag_type = gst_tag_get_type (gst_tag_name);
2296               g_value_init (&tag_value, tag_type);
2297               if (!gst_value_deserialize (&tag_value, value_utf8)) {
2298                 GValue from_val = { 0, };
2300                 g_value_init (&from_val, G_TYPE_STRING);
2301                 g_value_set_string (&from_val, value_utf8);
2302                 if (!g_value_transform (&from_val, &tag_value)) {
2303                   GST_WARNING_OBJECT (demux,
2304                       "Could not transform string tag to " "%s tag type %s",
2305                       gst_tag_name, g_type_name (tag_type));
2306                   g_value_unset (&tag_value);
2307                 }
2308                 g_value_unset (&from_val);
2309               }
2310             }
2311           } else if (value_utf8 == NULL) {
2312             GST_WARNING ("Failed to convert string value to UTF8, skipping");
2313           } else {
2314             GST_DEBUG ("Skipping empty string value for %s", gst_tag_name);
2315           }
2316           g_free (value_utf8);
2317           break;
2318         }
2319         case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2320           if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2321             GST_FIXME ("Unhandled byte array tag %s", gst_tag_name);
2322             break;
2323           } else {
2324             asf_demux_parse_picture_tag (taglist, (guint8 *) value, value_len);
2325           }
2326           break;
2327         }
2328         case ASF_DEMUX_DATA_TYPE_DWORD:{
2329           /* this is the track number */
2330           g_value_init (&tag_value, G_TYPE_UINT);
2331           g_value_set_uint (&tag_value, (guint) GST_READ_UINT32_LE (value));
2332           break;
2333         }
2334         default:{
2335           GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2336           break;
2337         }
2338       }
2340       if (G_IS_VALUE (&tag_value)) {
2341         gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2342             gst_tag_name, &tag_value, NULL);
2344         g_value_unset (&tag_value);
2345       }
2346     }
2348     g_free (name);
2349     g_free (value);
2350   }
2352   gst_asf_demux_add_global_tags (demux, taglist);
2354   return GST_FLOW_OK;
2356   /* Errors */
2357 not_enough_data:
2358   {
2359     GST_WARNING ("Unexpected end of data parsing ext content desc object");
2360     gst_tag_list_free (taglist);
2361     return GST_FLOW_OK;         /* not really fatal */
2362   }
2365 static GstStructure *
2366 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2368   gchar sname[32];
2369   guint i;
2371   g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2373   for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2374     GstStructure *s;
2376     s = gst_caps_get_structure (demux->metadata, i);
2377     if (gst_structure_has_name (s, sname))
2378       return s;
2379   }
2381   gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2383   /* try lookup again; demux->metadata took ownership of the structure, so we
2384    * can't really make any assumptions about what happened to it, so we can't
2385    * just return it directly after appending it */
2386   return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2389 static GstFlowReturn
2390 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2391     guint64 size)
2393   guint16 blockcount, i;
2395   GST_INFO_OBJECT (demux, "object is a metadata object");
2397   /* Content Descriptor Count */
2398   if (size < 2)
2399     goto not_enough_data;
2401   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2403   for (i = 0; i < blockcount; ++i) {
2404     GstStructure *s;
2405     guint16 lang_idx, stream_num, name_len, data_type;
2406     guint32 data_len, ival;
2407     gchar *name_utf8;
2409     if (size < (2 + 2 + 2 + 2 + 4))
2410       goto not_enough_data;
2412     lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2413     stream_num = gst_asf_demux_get_uint16 (&data, &size);
2414     name_len = gst_asf_demux_get_uint16 (&data, &size);
2415     data_type = gst_asf_demux_get_uint16 (&data, &size);
2416     data_len = gst_asf_demux_get_uint32 (&data, &size);
2418     if (size < name_len + data_len)
2419       goto not_enough_data;
2421     /* convert name to UTF-8 */
2422     name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2423         NULL, NULL, NULL);
2424     gst_asf_demux_skip_bytes (name_len, &data, &size);
2426     if (name_utf8 == NULL) {
2427       GST_WARNING ("Failed to convert value name to UTF8, skipping");
2428       gst_asf_demux_skip_bytes (data_len, &data, &size);
2429       continue;
2430     }
2432     if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2433       gst_asf_demux_skip_bytes (data_len, &data, &size);
2434       g_free (name_utf8);
2435       continue;
2436     }
2438     /* read DWORD */
2439     if (size < 4) {
2440       g_free (name_utf8);
2441       goto not_enough_data;
2442     }
2444     ival = gst_asf_demux_get_uint32 (&data, &size);
2446     /* skip anything else there may be, just in case */
2447     gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2449     s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2450     gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2451     g_free (name_utf8);
2452   }
2454   GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2455   return GST_FLOW_OK;
2457   /* Errors */
2458 not_enough_data:
2459   {
2460     GST_WARNING ("Unexpected end of data parsing metadata object");
2461     return GST_FLOW_OK;         /* not really fatal */
2462   }
2465 static GstFlowReturn
2466 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2468   GstFlowReturn ret = GST_FLOW_OK;
2469   guint32 i, num_objects;
2470   guint8 unknown;
2472   /* Get the rest of the header's header */
2473   if (size < (4 + 1 + 1))
2474     goto not_enough_data;
2476   num_objects = gst_asf_demux_get_uint32 (&data, &size);
2477   unknown = gst_asf_demux_get_uint8 (&data, &size);
2478   unknown = gst_asf_demux_get_uint8 (&data, &size);
2480   GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2482   /* Loop through the header's objects, processing those */
2483   for (i = 0; i < num_objects; ++i) {
2484     GST_INFO_OBJECT (demux, "reading header part %u", i);
2485     ret = gst_asf_demux_process_object (demux, &data, &size);
2486     if (ret != GST_FLOW_OK) {
2487       GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2488       break;
2489     }
2490   }
2492   return ret;
2494 not_enough_data:
2495   {
2496     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2497         ("short read parsing HEADER object"));
2498     return GST_FLOW_ERROR;
2499   }
2502 static GstFlowReturn
2503 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2505   guint64 file_size, creation_time, packets_count;
2506   guint64 play_time, send_time, preroll;
2507   guint32 flags, min_pktsize, max_pktsize, min_bitrate;
2509   if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2510     goto not_enough_data;
2512   gst_asf_demux_skip_bytes (16, &data, &size);  /* skip GUID */
2513   file_size = gst_asf_demux_get_uint64 (&data, &size);
2514   creation_time = gst_asf_demux_get_uint64 (&data, &size);
2515   packets_count = gst_asf_demux_get_uint64 (&data, &size);
2516   play_time = gst_asf_demux_get_uint64 (&data, &size);
2517   send_time = gst_asf_demux_get_uint64 (&data, &size);
2518   preroll = gst_asf_demux_get_uint64 (&data, &size);
2519   flags = gst_asf_demux_get_uint32 (&data, &size);
2520   min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2521   max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2522   min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2524   demux->broadcast = !!(flags & 0x01);
2525   demux->seekable = !!(flags & 0x02);
2527   GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2528   GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2529   GST_DEBUG_OBJECT (demux, "flags::seekable  = %d", demux->seekable);
2531   if (demux->broadcast) {
2532     /* these fields are invalid if the broadcast flag is set */
2533     play_time = 0;
2534     file_size = 0;
2535   }
2537   if (min_pktsize != max_pktsize)
2538     goto non_fixed_packet_size;
2540   demux->packet_size = max_pktsize;
2542   /* FIXME: do we need send_time as well? what is it? */
2543   if ((play_time * 100) >= (preroll * GST_MSECOND))
2544     demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2545   else
2546     demux->play_time = 0;
2548   demux->preroll = preroll * GST_MSECOND;
2550   /* initial latency */
2551   demux->latency = demux->preroll;
2553   if (demux->play_time == 0)
2554     demux->seekable = FALSE;
2556   GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2557       GST_TIME_ARGS (demux->play_time));
2558   GST_DEBUG_OBJECT (demux, "preroll   %" GST_TIME_FORMAT,
2559       GST_TIME_ARGS (demux->preroll));
2561   if (demux->play_time > 0) {
2562     gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2563         demux->play_time);
2564   }
2566   GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2567       packets_count);
2568   GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2570   return GST_FLOW_OK;
2572 /* ERRORS */
2573 non_fixed_packet_size:
2574   {
2575     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2576         ("packet size must be fixed"));
2577     return GST_FLOW_ERROR;
2578   }
2579 not_enough_data:
2580   {
2581     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2582         ("short read parsing FILE object"));
2583     return GST_FLOW_ERROR;
2584   }
2587 /* Content Description Object */
2588 static GstFlowReturn
2589 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2591   struct
2592   {
2593     const gchar *gst_tag;
2594     guint16 val_length;
2595     gchar *val_utf8;
2596   } tags[5] = {
2597     {
2598     GST_TAG_TITLE, 0, NULL}, {
2599     GST_TAG_ARTIST, 0, NULL}, {
2600     GST_TAG_COPYRIGHT, 0, NULL}, {
2601     GST_TAG_DESCRIPTION, 0, NULL}, {
2602     GST_TAG_COMMENT, 0, NULL}
2603   };
2604   GstTagList *taglist;
2605   GValue value = { 0 };
2606   gsize in, out;
2607   gint i = -1;
2609   GST_INFO_OBJECT (demux, "object is a comment");
2611   if (size < (2 + 2 + 2 + 2 + 2))
2612     goto not_enough_data;
2614   tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
2615   tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
2616   tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
2617   tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
2618   tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
2620   GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
2621       "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
2622       tags[2].val_length, tags[3].val_length, tags[4].val_length);
2624   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2625     if (size < tags[i].val_length)
2626       goto not_enough_data;
2628     /* might be just '/0', '/0'... */
2629     if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
2630       /* convert to UTF-8 */
2631       tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
2632           "UTF-8", "UTF-16LE", &in, &out, NULL);
2633     }
2634     gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
2635   }
2637   /* parse metadata into taglist */
2638   taglist = gst_tag_list_new ();
2639   g_value_init (&value, G_TYPE_STRING);
2640   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2641     if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
2642       g_value_set_string (&value, tags[i].val_utf8);
2643       gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
2644           tags[i].gst_tag, &value, NULL);
2645     }
2646   }
2647   g_value_unset (&value);
2649   gst_asf_demux_add_global_tags (demux, taglist);
2651   for (i = 0; i < G_N_ELEMENTS (tags); ++i)
2652     g_free (tags[i].val_utf8);
2654   return GST_FLOW_OK;
2656 not_enough_data:
2657   {
2658     GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
2659         "comment tag section %d, skipping comment object", i);
2660     for (i = 0; i < G_N_ELEMENTS (tags); i++)
2661       g_free (tags[i].val_utf8);
2662     return GST_FLOW_OK;         /* not really fatal */
2663   }
2666 static GstFlowReturn
2667 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
2668     guint64 size)
2670   guint16 num_streams, i;
2672   if (size < 2)
2673     goto not_enough_data;
2675   num_streams = gst_asf_demux_get_uint16 (&data, &size);
2677   GST_INFO ("object is a bitrate properties object with %u streams",
2678       num_streams);
2680   if (size < (num_streams * (2 + 4)))
2681     goto not_enough_data;
2683   for (i = 0; i < num_streams; ++i) {
2684     guint32 bitrate;
2685     guint16 stream_id;
2687     stream_id = gst_asf_demux_get_uint16 (&data, &size);
2688     bitrate = gst_asf_demux_get_uint32 (&data, &size);
2690     if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
2691       demux->bitrate[stream_id] = bitrate;
2692       GST_DEBUG ("bitrate[%u] = %u", stream_id, bitrate);
2693     } else {
2694       GST_WARNING ("stream id %u is too large", stream_id);
2695     }
2696   }
2698   return GST_FLOW_OK;
2700 not_enough_data:
2701   {
2702     GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
2703     return GST_FLOW_OK;         /* not really fatal */
2704   }
2707 static GstFlowReturn
2708 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
2709     guint64 size)
2711   GstFlowReturn ret = GST_FLOW_OK;
2712   guint64 hdr_size;
2714   /* Get the rest of the header's header */
2715   if (size < (16 + 2 + 4))
2716     goto not_enough_data;
2718   /* skip GUID and two other bytes */
2719   gst_asf_demux_skip_bytes (16 + 2, &data, &size);
2720   hdr_size = gst_asf_demux_get_uint32 (&data, &size);
2722   GST_INFO ("extended header object with a size of %u bytes", (guint) size);
2724   /* FIXME: does data_size include the rest of the header that we have read? */
2725   if (hdr_size > size)
2726     goto not_enough_data;
2728   while (hdr_size > 0) {
2729     ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
2730     if (ret != GST_FLOW_OK)
2731       break;
2732   }
2734   return ret;
2736 not_enough_data:
2737   {
2738     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2739         ("short read parsing extended header object"));
2740     return GST_FLOW_ERROR;
2741   }
2744 static GstFlowReturn
2745 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
2746     guint64 size)
2748   guint i;
2750   if (size < 2)
2751     goto not_enough_data;
2753   if (demux->languages) {
2754     GST_WARNING ("More than one LANGUAGE_LIST object in stream");
2755     g_strfreev (demux->languages);
2756     demux->languages = NULL;
2757     demux->num_languages = 0;
2758   }
2760   demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
2761   GST_LOG ("%u languages:", demux->num_languages);
2763   demux->languages = g_new0 (gchar *, demux->num_languages + 1);
2764   for (i = 0; i < demux->num_languages; ++i) {
2765     guint8 len, *lang_data = NULL;
2767     if (size < 1)
2768       goto not_enough_data;
2769     len = gst_asf_demux_get_uint8 (&data, &size);
2770     if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
2771       gchar *utf8;
2773       utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
2774           NULL, NULL);
2776       /* truncate "en-us" etc. to just "en" */
2777       if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
2778         utf8[2] = '\0';
2779       }
2780       GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
2781       demux->languages[i] = utf8;
2782       g_free (lang_data);
2783     } else {
2784       goto not_enough_data;
2785     }
2786   }
2788   return GST_FLOW_OK;
2790 not_enough_data:
2791   {
2792     GST_WARNING_OBJECT (demux, "short read parsing language list object!");
2793     g_free (demux->languages);
2794     demux->languages = NULL;
2795     return GST_FLOW_OK;         /* not fatal */
2796   }
2799 static GstFlowReturn
2800 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
2801     guint64 size)
2803   GstClockTime interval;
2804   guint32 x, count, i;
2806   if (size < (16 + 8 + 4 + 4))
2807     goto not_enough_data;
2809   /* skip file id */
2810   gst_asf_demux_skip_bytes (16, &data, &size);
2811   interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
2812   x = gst_asf_demux_get_uint32 (&data, &size);
2813   count = gst_asf_demux_get_uint32 (&data, &size);
2814   if (count > 0) {
2815     demux->sidx_interval = interval;
2816     demux->sidx_num_entries = count;
2817     g_free (demux->sidx_entries);
2818     demux->sidx_entries = g_new0 (guint32, count);
2820     for (i = 0; i < count && size > (4 + 2); ++i) {
2821       demux->sidx_entries[i] = gst_asf_demux_get_uint32 (&data, &size);
2822       x = (guint32) gst_asf_demux_get_uint16 (&data, &size);
2823       GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u",
2824           GST_TIME_ARGS (i * interval), demux->sidx_entries[i]);
2825     }
2826   } else {
2827     GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
2828   }
2830   return GST_FLOW_OK;
2832 not_enough_data:
2833   {
2834     GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
2835     return GST_FLOW_OK;         /* not fatal */
2836   }
2839 static GstFlowReturn
2840 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
2841     guint8 * data, guint64 size)
2843   ASFGuid guid;
2844   guint16 num, i;
2845   guint8 *mes;
2847   if (size < 16 + 2 + (2 * 2))
2848     goto not_enough_data;
2850   gst_asf_demux_get_guid (&guid, &data, &size);
2851   num = gst_asf_demux_get_uint16 (&data, &size);
2853   if (num < 2) {
2854     GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
2855     return GST_FLOW_OK;
2856   }
2858   if (size < (num * sizeof (guint16)))
2859     goto not_enough_data;
2861   /* read mutually exclusive stream numbers */
2862   mes = g_new (guint8, num + 1);
2863   for (i = 0; i < num; ++i) {
2864     mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
2865     GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
2866   }
2868   /* add terminator so we can easily get the count or know when to stop */
2869   mes[i] = (guint8) - 1;
2871   demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
2873   return GST_FLOW_OK;
2875   /* Errors */
2876 not_enough_data:
2877   {
2878     GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
2879     return GST_FLOW_OK;         /* not absolutely fatal */
2880   }
2883 static GstFlowReturn
2884 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
2885     guint64 size)
2887   AsfStreamExtProps esp;
2888   AsfStream *stream = NULL;
2889   AsfObject stream_obj;
2890   guint16 stream_name_count;
2891   guint16 num_payload_ext;
2892   guint64 len;
2893   guint8 *stream_obj_data = NULL;
2894   guint8 *data_start;
2895   guint obj_size;
2896   guint i, stream_num;
2898   data_start = data;
2899   obj_size = (guint) size;
2901   if (size < 64)
2902     goto not_enough_data;
2904   esp.valid = TRUE;
2905   esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
2906   esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
2907   esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2908   esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
2909   esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
2910   esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
2911   esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
2912   esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
2913   esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
2914   esp.flags = gst_asf_demux_get_uint32 (&data, &size);
2915   stream_num = gst_asf_demux_get_uint16 (&data, &size);
2916   esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2917   esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
2918   stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
2919   num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
2921   GST_INFO ("start_time             = %" GST_TIME_FORMAT,
2922       GST_TIME_ARGS (esp.start_time));
2923   GST_INFO ("end_time               = %" GST_TIME_FORMAT,
2924       GST_TIME_ARGS (esp.end_time));
2925   GST_INFO ("flags                  = %08x", esp.flags);
2926   GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
2927       GST_TIME_ARGS (esp.avg_time_per_frame * 100));
2928   GST_INFO ("stream number          = %u", stream_num);
2929   GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
2930       (esp.lang_idx < demux->num_languages) ?
2931       GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
2932   GST_INFO ("stream name count      = %u", stream_name_count);
2934   /* read stream names */
2935   for (i = 0; i < stream_name_count; ++i) {
2936     guint16 stream_lang_idx;
2937     gchar *stream_name = NULL;
2939     if (size < 2)
2940       goto not_enough_data;
2941     stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2942     if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
2943       goto not_enough_data;
2944     GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
2945     g_free (stream_name);       /* TODO: store names in struct */
2946   }
2948   /* read payload extension systems stuff */
2949   GST_LOG ("payload extension systems count = %u", num_payload_ext);
2951   if (num_payload_ext > 0)
2952     esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
2953   else
2954     esp.payload_extensions = NULL;
2956   for (i = 0; i < num_payload_ext; ++i) {
2957     AsfPayloadExtension ext;
2958     ASFGuid ext_guid;
2959     guint32 sys_info_len;
2961     if (size < 16 + 2 + 4)
2962       goto not_enough_data;
2964     gst_asf_demux_get_guid (&ext_guid, &data, &size);
2965     ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
2966     ext.len = gst_asf_demux_get_uint16 (&data, &size);
2968     sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
2969     GST_LOG ("payload systems info len = %u", sys_info_len);
2970     if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
2971       goto not_enough_data;
2973     esp.payload_extensions[i] = ext;
2974   }
2976   GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
2978   /* there might be an optional STREAM_INFO object here now; if not, we
2979    * should have parsed the corresponding stream info object already (since
2980    * we are parsing the extended stream properties objects delayed) */
2981   if (size == 0) {
2982     stream = gst_asf_demux_get_stream (demux, stream_num);
2983     goto done;
2984   }
2986   /* get size of the stream object */
2987   if (!asf_demux_peek_object (demux, data, size, &stream_obj))
2988     goto not_enough_data;
2990   if (stream_obj.id != ASF_OBJ_STREAM)
2991     goto expected_stream_object;
2993   if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
2994       stream_obj.size > (10 * 1024 * 1024))
2995     goto not_enough_data;
2997   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
2999   /* process this stream object later after all the other 'normal' ones
3000    * have been processed (since the others are more important/non-hidden) */
3001   len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3002   if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3003     goto not_enough_data;
3005   /* parse stream object */
3006   stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3007   g_free (stream_obj_data);
3009 done:
3011   if (stream) {
3012     stream->ext_props = esp;
3014     /* try to set the framerate */
3015     if (stream->is_video && stream->caps) {
3016       GValue framerate = { 0 };
3017       GstStructure *s;
3018       gint num, denom;
3020       g_value_init (&framerate, GST_TYPE_FRACTION);
3022       num = GST_SECOND / 100;
3023       denom = esp.avg_time_per_frame;
3024       if (denom == 0) {
3025         /* avoid division by 0, assume 25/1 framerate */
3026         denom = GST_SECOND / 2500;
3027       }
3029       gst_value_set_fraction (&framerate, num, denom);
3031       stream->caps = gst_caps_make_writable (stream->caps);
3032       s = gst_caps_get_structure (stream->caps, 0);
3033       gst_structure_set_value (s, "framerate", &framerate);
3034       g_value_unset (&framerate);
3035       GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3036           num, denom, ((gdouble) num) / denom);
3037     }
3039     /* add language info now if we have it */
3040     if (stream->ext_props.lang_idx < demux->num_languages) {
3041       if (stream->pending_tags == NULL)
3042         stream->pending_tags = gst_tag_list_new ();
3043       GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3044           demux->languages[stream->ext_props.lang_idx]);
3045       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3046           GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3047           NULL);
3048     }
3049   } else {
3050     GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3051   }
3053   return GST_FLOW_OK;
3055   /* Errors */
3056 not_enough_data:
3057   {
3058     GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3059     return GST_FLOW_OK;         /* not absolutely fatal */
3060   }
3061 expected_stream_object:
3062   {
3063     GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3064         "object: expected embedded stream object, but got %s object instead!",
3065         gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3066     return GST_FLOW_OK;         /* not absolutely fatal */
3067   }
3070 static const gchar *
3071 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
3073   const gchar *nick;
3075   nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
3076   if (g_str_has_prefix (nick, "ASF_OBJ_"))
3077     nick += strlen ("ASF_OBJ_");
3079   if (demux->objpath == NULL) {
3080     demux->objpath = g_strdup (nick);
3081   } else {
3082     gchar *newpath;
3084     newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
3085     g_free (demux->objpath);
3086     demux->objpath = newpath;
3087   }
3089   return (const gchar *) demux->objpath;
3092 static void
3093 gst_asf_demux_pop_obj (GstASFDemux * demux)
3095   gchar *s;
3097   if ((s = g_strrstr (demux->objpath, "/"))) {
3098     *s = '\0';
3099   } else {
3100     g_free (demux->objpath);
3101     demux->objpath = NULL;
3102   }
3105 static void
3106 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
3108   GSList *l;
3109   guint i;
3111   /* Parse the queued extended stream property objects and add the info
3112    * to the existing streams or add the new embedded streams, but without
3113    * activating them yet */
3114   GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
3115       g_slist_length (demux->ext_stream_props));
3117   for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
3118     GstBuffer *buf = GST_BUFFER (l->data);
3120     GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
3121     gst_asf_demux_process_ext_stream_props (demux, GST_BUFFER_DATA (buf),
3122         GST_BUFFER_SIZE (buf));
3123     gst_buffer_unref (buf);
3124   }
3125   g_slist_free (demux->ext_stream_props);
3126   demux->ext_stream_props = NULL;
3129 #if 0
3130 static void
3131 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
3133   guint i, j;
3135   for (i = 0; i < demux->num_streams; ++i) {
3136     AsfStream *stream;
3137     gboolean is_hidden;
3138     GSList *x;
3140     stream = &demux->stream[i];
3142     GST_LOG_OBJECT (demux, "checking  stream %2u", stream->id);
3144     if (stream->active) {
3145       GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
3146       continue;
3147     }
3149     is_hidden = FALSE;
3150     for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
3151       guint8 *mes;
3153       /* check for each mutual exclusion whether it affects this stream */
3154       for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3155         if (*mes == stream->id) {
3156           /* if yes, check if we've already added streams that are mutually
3157            * exclusive with the stream we're about to add */
3158           for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
3159             for (j = 0; j < demux->num_streams; ++j) {
3160               /* if the broadcast flag is set, assume the hidden streams aren't
3161                * actually streamed and hide them (or playbin won't work right),
3162                * otherwise assume their data is available */
3163               if (demux->stream[j].id == *mes && demux->broadcast) {
3164                 is_hidden = TRUE;
3165                 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
3166                     "mutually exclusive with already existing stream ID %d, "
3167                     "hiding stream", stream->id, demux->stream[j].id);
3168                 goto next;
3169               }
3170             }
3171           }
3172           break;
3173         }
3174       }
3175     }
3177   next:
3179     /* FIXME: we should do stream activation based on preroll data in
3180      * streaming mode too */
3181     if (demux->streaming && !is_hidden)
3182       gst_asf_demux_activate_stream (demux, stream);
3183   }
3185 #endif
3187 static GstFlowReturn
3188 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
3189     guint64 * p_size)
3191   GstFlowReturn ret = GST_FLOW_OK;
3192   AsfObject obj;
3193   guint64 obj_data_size;
3195   if (*p_size < ASF_OBJECT_HEADER_SIZE)
3196     return ASF_FLOW_NEED_MORE_DATA;
3198   asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj);
3199   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
3201   obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
3203   if (*p_size < obj_data_size)
3204     return ASF_FLOW_NEED_MORE_DATA;
3206   gst_asf_demux_push_obj (demux, obj.id);
3208   GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
3210   switch (obj.id) {
3211     case ASF_OBJ_STREAM:{
3212       AsfStream *stream;
3214       stream =
3215           gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
3217       ret = GST_FLOW_OK;
3218       break;
3219     }
3220     case ASF_OBJ_FILE:
3221       ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
3222       break;
3223     case ASF_OBJ_HEADER:
3224       ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
3225       break;
3226     case ASF_OBJ_COMMENT:
3227       ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
3228       break;
3229     case ASF_OBJ_HEAD1:
3230       ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
3231       break;
3232     case ASF_OBJ_BITRATE_PROPS:
3233       ret =
3234           gst_asf_demux_process_bitrate_props_object (demux, *p_data,
3235           obj_data_size);
3236       break;
3237     case ASF_OBJ_EXT_CONTENT_DESC:
3238       ret =
3239           gst_asf_demux_process_ext_content_desc (demux, *p_data,
3240           obj_data_size);
3241       break;
3242     case ASF_OBJ_METADATA_OBJECT:
3243       ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
3244       break;
3245     case ASF_OBJ_EXTENDED_STREAM_PROPS:{
3246       GstBuffer *buf;
3248       /* process these later, we might not have parsed the corresponding
3249        * stream object yet */
3250       GST_LOG ("%s: queued for later parsing", demux->objpath);
3251       buf = gst_buffer_new_and_alloc (obj_data_size);
3252       memcpy (GST_BUFFER_DATA (buf), *p_data, obj_data_size);
3253       demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
3254       ret = GST_FLOW_OK;
3255       break;
3256     }
3257     case ASF_OBJ_LANGUAGE_LIST:
3258       ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
3259       break;
3260     case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
3261       ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
3262           obj_data_size);
3263       break;
3264     case ASF_OBJ_SIMPLE_INDEX:
3265       ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
3266       break;
3267     case ASF_OBJ_CONTENT_ENCRYPTION:
3268     case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
3269     case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
3270       goto error_encrypted;
3271     case ASF_OBJ_CONCEAL_NONE:
3272     case ASF_OBJ_HEAD2:
3273     case ASF_OBJ_UNDEFINED:
3274     case ASF_OBJ_CODEC_COMMENT:
3275     case ASF_OBJ_INDEX:
3276     case ASF_OBJ_PADDING:
3277     case ASF_OBJ_BITRATE_MUTEX:
3278     case ASF_OBJ_COMPATIBILITY:
3279     case ASF_OBJ_INDEX_PLACEHOLDER:
3280     case ASF_OBJ_INDEX_PARAMETERS:
3281     case ASF_OBJ_STREAM_PRIORITIZATION:
3282     case ASF_OBJ_SCRIPT_COMMAND:
3283     default:
3284       /* Unknown/unhandled object, skip it and hope for the best */
3285       GST_INFO ("%s: skipping object", demux->objpath);
3286       ret = GST_FLOW_OK;
3287       break;
3288   }
3290   /* this can't fail, we checked the number of bytes available before */
3291   gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
3293   GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
3295   gst_asf_demux_pop_obj (demux);
3297   return ret;
3299 /* ERRORS */
3300 error_encrypted:
3301   {
3302     GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
3303     return GST_FLOW_ERROR;
3304   }
3307 static void
3308 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
3309     GstBuffer ** p_buffer)
3311   GstBuffer *descrambled_buffer;
3312   GstBuffer *scrambled_buffer;
3313   GstBuffer *sub_buffer;
3314   guint offset;
3315   guint off;
3316   guint row;
3317   guint col;
3318   guint idx;
3320   /* descrambled_buffer is initialised in the first iteration */
3321   descrambled_buffer = NULL;
3322   scrambled_buffer = *p_buffer;
3324   if (GST_BUFFER_SIZE (scrambled_buffer) < demux->ds_packet_size * demux->span)
3325     return;
3327   for (offset = 0; offset < GST_BUFFER_SIZE (scrambled_buffer);
3328       offset += demux->ds_chunk_size) {
3329     off = offset / demux->ds_chunk_size;
3330     row = off / demux->span;
3331     col = off % demux->span;
3332     idx = row + col * demux->ds_packet_size / demux->ds_chunk_size;
3333     GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
3334         col, off, demux->ds_chunk_size);
3335     GST_DEBUG ("scrambled buffer size=%u, span=%u, packet_size=%u",
3336         GST_BUFFER_SIZE (scrambled_buffer), demux->span, demux->ds_packet_size);
3337     GST_DEBUG ("GST_BUFFER_SIZE (scrambled_buffer) = %u",
3338         GST_BUFFER_SIZE (scrambled_buffer));
3339     sub_buffer =
3340         gst_buffer_create_sub (scrambled_buffer, idx * demux->ds_chunk_size,
3341         demux->ds_chunk_size);
3342     if (!offset) {
3343       descrambled_buffer = sub_buffer;
3344     } else {
3345       descrambled_buffer = gst_buffer_join (descrambled_buffer, sub_buffer);
3346     }
3347   }
3349   gst_buffer_copy_metadata (descrambled_buffer, scrambled_buffer,
3350       GST_BUFFER_COPY_TIMESTAMPS);
3352   /* FIXME/CHECK: do we need to transfer buffer flags here too? */
3354   gst_buffer_unref (scrambled_buffer);
3355   *p_buffer = descrambled_buffer;
3358 static gboolean
3359 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
3361   GstASFDemux *demux = GST_ASF_DEMUX (element);
3362   gint i;
3364   GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
3366   for (i = 0; i < demux->num_streams; ++i) {
3367     gst_event_ref (event);
3368     if (gst_asf_demux_handle_src_event (demux->stream[i].pad, event)) {
3369       gst_event_unref (event);
3370       return TRUE;
3371     }
3372   }
3374   gst_event_unref (event);
3375   return FALSE;
3378 /* takes ownership of the passed event */
3379 static gboolean
3380 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
3382   gboolean ret = TRUE;
3383   gint i;
3385   GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
3386       GST_EVENT_TYPE_NAME (event));
3388   for (i = 0; i < demux->num_streams; ++i) {
3389     gst_event_ref (event);
3390     ret &= gst_pad_push_event (demux->stream[i].pad, event);
3391   }
3392   gst_event_unref (event);
3393   return ret;
3396 static const GstQueryType *
3397 gst_asf_demux_get_src_query_types (GstPad * pad)
3399   static const GstQueryType types[] = {
3400     GST_QUERY_POSITION,
3401     GST_QUERY_DURATION,
3402     GST_QUERY_SEEKING,
3403     0
3404   };
3406   return types;
3409 static gboolean
3410 gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query)
3412   GstASFDemux *demux;
3413   gboolean res = FALSE;
3415   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
3417   GST_DEBUG ("handling %s query",
3418       gst_query_type_get_name (GST_QUERY_TYPE (query)));
3420   switch (GST_QUERY_TYPE (query)) {
3421     case GST_QUERY_DURATION:
3422     {
3423       GstFormat format;
3425       gst_query_parse_duration (query, &format, NULL);
3427       if (format != GST_FORMAT_TIME) {
3428         GST_LOG ("only support duration queries in TIME format");
3429         break;
3430       }
3432       GST_OBJECT_LOCK (demux);
3434       if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
3435         GST_LOG ("returning duration: %" GST_TIME_FORMAT,
3436             GST_TIME_ARGS (demux->segment.duration));
3438         gst_query_set_duration (query, GST_FORMAT_TIME,
3439             demux->segment.duration);
3441         res = TRUE;
3442       } else {
3443         GST_LOG ("duration not known yet");
3444       }
3446       GST_OBJECT_UNLOCK (demux);
3447       break;
3448     }
3450     case GST_QUERY_POSITION:{
3451       GstFormat format;
3453       gst_query_parse_position (query, &format, NULL);
3455       if (format != GST_FORMAT_TIME) {
3456         GST_LOG ("only support position queries in TIME format");
3457         break;
3458       }
3460       GST_OBJECT_LOCK (demux);
3462       if (demux->segment.last_stop != GST_CLOCK_TIME_NONE) {
3463         GST_LOG ("returning position: %" GST_TIME_FORMAT,
3464             GST_TIME_ARGS (demux->segment.last_stop));
3466         gst_query_set_position (query, GST_FORMAT_TIME,
3467             demux->segment.last_stop);
3469         res = TRUE;
3470       } else {
3471         GST_LOG ("position not known yet");
3472       }
3474       GST_OBJECT_UNLOCK (demux);
3475       break;
3476     }
3478     case GST_QUERY_SEEKING:{
3479       GstFormat format;
3481       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
3482       if (format == GST_FORMAT_TIME) {
3483         gint64 duration;
3485         GST_OBJECT_LOCK (demux);
3486         duration = demux->segment.duration;
3487         GST_OBJECT_UNLOCK (demux);
3489         if (!demux->streaming || !demux->seekable) {
3490           gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
3491               duration);
3492           res = TRUE;
3493         } else {
3494           GstFormat fmt;
3495           gboolean seekable;
3497           /* try downstream first in TIME */
3498           res = gst_pad_query_default (pad, query);
3500           gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
3501           GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3502               GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3503           /* if no luck, maybe in BYTES */
3504           if (!seekable || fmt != GST_FORMAT_TIME) {
3505             GstQuery *q;
3507             q = gst_query_new_seeking (GST_FORMAT_BYTES);
3508             if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
3509               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
3510               GST_LOG_OBJECT (demux, "upstream %s seekable %d",
3511                   GST_STR_NULL (gst_format_get_name (fmt)), seekable);
3512               if (fmt != GST_FORMAT_BYTES)
3513                 seekable = FALSE;
3514             }
3515             gst_query_unref (q);
3516             gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3517                 duration);
3518             res = TRUE;
3519           }
3520         }
3521       } else
3522         GST_LOG_OBJECT (demux, "only support seeking in TIME format");
3523       break;
3524     }
3526     case GST_QUERY_LATENCY:
3527     {
3528       gboolean live;
3529       GstClockTime min, max;
3531       /* preroll delay does not matter in non-live pipeline,
3532        * but we might end up in a live (rtsp) one ... */
3534       /* first forward */
3535       res = gst_pad_query_default (pad, query);
3536       if (!res)
3537         break;
3539       gst_query_parse_latency (query, &live, &min, &max);
3541       GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
3542           GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
3543           GST_TIME_ARGS (min), GST_TIME_ARGS (max));
3545       GST_OBJECT_LOCK (demux);
3546       if (min != -1)
3547         min += demux->latency;
3548       if (max != -1)
3549         max += demux->latency;
3550       GST_OBJECT_UNLOCK (demux);
3552       gst_query_set_latency (query, live, min, max);
3553       break;
3554     }
3555     default:
3556       res = gst_pad_query_default (pad, query);
3557       break;
3558   }
3560   gst_object_unref (demux);
3561   return res;
3564 static GstStateChangeReturn
3565 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
3567   GstASFDemux *demux = GST_ASF_DEMUX (element);
3568   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3570   switch (transition) {
3571     case GST_STATE_CHANGE_NULL_TO_READY:{
3572       gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3573       demux->need_newsegment = TRUE;
3574       demux->segment_running = FALSE;
3575       demux->adapter = gst_adapter_new ();
3576       demux->metadata = gst_caps_new_empty ();
3577       demux->data_size = 0;
3578       demux->data_offset = 0;
3579       demux->index_offset = 0;
3580       break;
3581     }
3582     default:
3583       break;
3584   }
3586   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3587   if (ret == GST_STATE_CHANGE_FAILURE)
3588     return ret;
3590   switch (transition) {
3591     case GST_STATE_CHANGE_PAUSED_TO_READY:
3592     case GST_STATE_CHANGE_READY_TO_NULL:
3593       gst_asf_demux_reset (demux);
3594       break;
3595     default:
3596       break;
3597   }
3599   return ret;