asfdemux: don't leak payload bufs in gst_asf_demux_free_stream
[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 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
36  * with newer GLib versions (>= 2.31.0) */
37 #define GLIB_DISABLE_DEPRECATION_WARNINGS
39 #include <gst/gstutils.h>
40 #include <gst/base/gstbytereader.h>
41 #include <gst/riff/riff-media.h>
42 #include <gst/tag/tag.h>
43 #include <gst/gst-i18n-plugin.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
48 #include "gstasfdemux.h"
49 #include "asfheaders.h"
50 #include "asfpacket.h"
52 static GstStaticPadTemplate gst_asf_demux_sink_template =
53 GST_STATIC_PAD_TEMPLATE ("sink",
54     GST_PAD_SINK,
55     GST_PAD_ALWAYS,
56     GST_STATIC_CAPS ("video/x-ms-asf")
57     );
59 static GstStaticPadTemplate audio_src_template =
60 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
61     GST_PAD_SRC,
62     GST_PAD_SOMETIMES,
63     GST_STATIC_CAPS_ANY);
65 static GstStaticPadTemplate video_src_template =
66 GST_STATIC_PAD_TEMPLATE ("video_%02d",
67     GST_PAD_SRC,
68     GST_PAD_SOMETIMES,
69     GST_STATIC_CAPS_ANY);
71 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
72 #define ASF_OBJECT_HEADER_SIZE  (16+8)
74 /* FIXME: get rid of this */
75 /* abuse this GstFlowReturn enum for internal usage */
76 #define ASF_FLOW_NEED_MORE_DATA  99
78 #define gst_asf_get_flow_name(flow)    \
79   (flow == ASF_FLOW_NEED_MORE_DATA) ?  \
80   "need-more-data" : gst_flow_get_name (flow)
82 GST_DEBUG_CATEGORY (asfdemux_dbg);
84 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
85     GstStateChange transition);
86 static gboolean gst_asf_demux_element_send_event (GstElement * element,
87     GstEvent * event);
88 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
89     GstEvent * event);
90 static gboolean gst_asf_demux_handle_src_query (GstPad * pad, GstQuery * query);
91 static const GstQueryType *gst_asf_demux_get_src_query_types (GstPad * pad);
92 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstBuffer * buf);
93 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstEvent * event);
94 static GstFlowReturn gst_asf_demux_process_object (GstASFDemux * demux,
95     guint8 ** p_data, guint64 * p_size);
96 static gboolean gst_asf_demux_activate (GstPad * sinkpad);
97 static gboolean gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active);
98 static gboolean gst_asf_demux_activate_pull (GstPad * sinkpad, gboolean active);
99 static void gst_asf_demux_loop (GstASFDemux * demux);
100 static void
101 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
102 static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux);
103 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
104 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
105 static gboolean
106 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
107 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
108     AsfStream * stream, GstBuffer ** p_buffer);
109 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
110     AsfStream * stream);
111 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
112     guint stream_num);
113 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
114     gboolean force);
116 GST_BOILERPLATE (GstASFDemux, gst_asf_demux, GstElement, GST_TYPE_ELEMENT);
118 static void
119 gst_asf_demux_base_init (gpointer g_class)
121   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
123   gst_element_class_add_static_pad_template (element_class,
124       &audio_src_template);
125   gst_element_class_add_static_pad_template (element_class,
126       &video_src_template);
127   gst_element_class_add_static_pad_template (element_class,
128       &gst_asf_demux_sink_template);
130   gst_element_class_set_details_simple (element_class, "ASF Demuxer",
131       "Codec/Demuxer",
132       "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
135 static void
136 gst_asf_demux_class_init (GstASFDemuxClass * klass)
138   GstElementClass *gstelement_class;
140   gstelement_class = (GstElementClass *) klass;
142   gstelement_class->change_state =
143       GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
144   gstelement_class->send_event =
145       GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
148 static void
149 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
151   gst_caps_replace (&stream->caps, NULL);
152   if (stream->pending_tags) {
153     gst_tag_list_free (stream->pending_tags);
154     stream->pending_tags = NULL;
155   }
156   if (stream->pad) {
157     if (stream->active)
158       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159     else
160       gst_object_unref (stream->pad);
161     stream->pad = NULL;
162   }
164   while (stream->payloads->len > 0) {
165     AsfPayload *payload;
166     guint last;
168     last = stream->payloads->len - 1;
169     payload = &g_array_index (stream->payloads, AsfPayload, last);
170     gst_buffer_replace (&payload->buf, NULL);
171     g_array_remove_index (stream->payloads, last);
172   }
173   if (stream->payloads) {
174     int i;
175     for (i = 0; i < stream->payloads->len; i++) {
176       AsfPayload *payload;
177       payload = &g_array_index (stream->payloads, AsfPayload, i);
178       gst_buffer_replace (&payload->buf, NULL);
179     }
180     g_array_free (stream->payloads, TRUE);
181     stream->payloads = NULL;
182   }
183   if (stream->ext_props.valid) {
184     g_free (stream->ext_props.payload_extensions);
185     stream->ext_props.payload_extensions = NULL;
186   }
189 static void
190 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
192   GST_LOG_OBJECT (demux, "resetting");
194   gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
195   demux->segment_running = FALSE;
196   if (demux->adapter && !chain_reset) {
197     gst_adapter_clear (demux->adapter);
198     g_object_unref (demux->adapter);
199     demux->adapter = NULL;
200   }
201   if (demux->taglist) {
202     gst_tag_list_free (demux->taglist);
203     demux->taglist = NULL;
204   }
205   if (demux->metadata) {
206     gst_caps_unref (demux->metadata);
207     demux->metadata = NULL;
208   }
209   if (demux->global_metadata) {
210     gst_structure_free (demux->global_metadata);
211     demux->global_metadata = NULL;
212   }
214   demux->state = GST_ASF_DEMUX_STATE_HEADER;
215   g_free (demux->objpath);
216   demux->objpath = NULL;
217   g_strfreev (demux->languages);
218   demux->languages = NULL;
219   demux->num_languages = 0;
220   g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
221       NULL);
222   g_slist_free (demux->ext_stream_props);
223   demux->ext_stream_props = NULL;
225   while (demux->old_num_streams > 0) {
226     gst_asf_demux_free_stream (demux,
227         &demux->old_stream[demux->old_num_streams - 1]);
228     --demux->old_num_streams;
229   }
230   memset (demux->old_stream, 0, sizeof (demux->old_stream));
231   demux->old_num_streams = 0;
233   /* when resetting for a new chained asf, we don't want to remove the pads
234    * before adding the new ones */
235   if (chain_reset) {
236     memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
237     demux->old_num_streams = demux->num_streams;
238     demux->num_streams = 0;
239   }
241   while (demux->num_streams > 0) {
242     gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
243     --demux->num_streams;
244   }
245   memset (demux->stream, 0, sizeof (demux->stream));
246   if (!chain_reset) {
247     /* do not remove those for not adding pads with same name */
248     demux->num_audio_streams = 0;
249     demux->num_video_streams = 0;
250   }
251   demux->num_streams = 0;
252   demux->activated_streams = FALSE;
253   demux->first_ts = GST_CLOCK_TIME_NONE;
254   demux->segment_ts = GST_CLOCK_TIME_NONE;
255   demux->in_gap = 0;
256   if (!chain_reset)
257     gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
258   demux->state = GST_ASF_DEMUX_STATE_HEADER;
259   demux->seekable = FALSE;
260   demux->broadcast = FALSE;
261   demux->sidx_interval = 0;
262   demux->sidx_num_entries = 0;
263   g_free (demux->sidx_entries);
264   demux->sidx_entries = NULL;
266   demux->speed_packets = 1;
268   if (chain_reset) {
269     GST_LOG_OBJECT (demux, "Restarting");
270     gst_segment_init (&demux->segment, GST_FORMAT_TIME);
271     demux->need_newsegment = TRUE;
272     demux->segment_running = FALSE;
273     demux->accurate = FALSE;
274     demux->metadata = gst_caps_new_empty ();
275     demux->global_metadata = gst_structure_empty_new ("metadata");
276     demux->data_size = 0;
277     demux->data_offset = 0;
278     demux->index_offset = 0;
279   } else {
280     demux->base_offset = 0;
281   }
284 static void
285 gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass)
287   demux->sinkpad =
288       gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
289   gst_pad_set_chain_function (demux->sinkpad,
290       GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
291   gst_pad_set_event_function (demux->sinkpad,
292       GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
293   gst_pad_set_activate_function (demux->sinkpad,
294       GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
295   gst_pad_set_activatepull_function (demux->sinkpad,
296       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_pull));
297   gst_pad_set_activatepush_function (demux->sinkpad,
298       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_push));
299   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
301   /* set initial state */
302   gst_asf_demux_reset (demux, FALSE);
305 static gboolean
306 gst_asf_demux_activate (GstPad * sinkpad)
308   if (gst_pad_check_pull_range (sinkpad)) {
309     return gst_pad_activate_pull (sinkpad, TRUE);
310   } else {
311     return gst_pad_activate_push (sinkpad, TRUE);
312   }
315 static gboolean
316 gst_asf_demux_activate_push (GstPad * sinkpad, gboolean active)
318   GstASFDemux *demux;
320   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (sinkpad));
322   demux->state = GST_ASF_DEMUX_STATE_HEADER;
323   demux->streaming = TRUE;
325   return TRUE;
328 static gboolean
329 gst_asf_demux_activate_pull (GstPad * pad, gboolean active)
331   GstASFDemux *demux;
333   demux = GST_ASF_DEMUX (GST_OBJECT_PARENT (pad));
335   if (active) {
336     demux->state = GST_ASF_DEMUX_STATE_HEADER;
337     demux->streaming = FALSE;
339     return gst_pad_start_task (pad, (GstTaskFunction) gst_asf_demux_loop,
340         demux);
341   } else {
342     return gst_pad_stop_task (pad);
343   }
347 static gboolean
348 gst_asf_demux_sink_event (GstPad * pad, GstEvent * event)
350   GstASFDemux *demux;
351   gboolean ret = TRUE;
353   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
355   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
356   switch (GST_EVENT_TYPE (event)) {
357     case GST_EVENT_NEWSEGMENT:{
358       GstFormat newsegment_format;
359       gint64 newsegment_start, stop, time;
360       gdouble rate, arate;
361       gboolean update;
363       gst_event_parse_new_segment_full (event, &update, &rate, &arate,
364           &newsegment_format, &newsegment_start, &stop, &time);
366       if (newsegment_format == GST_FORMAT_BYTES) {
367         if (demux->packet_size && newsegment_start > demux->data_offset)
368           demux->packet = (newsegment_start - demux->data_offset) /
369               demux->packet_size;
370         else
371           demux->packet = 0;
372       } else if (newsegment_format == GST_FORMAT_TIME) {
373         /* do not know packet position, not really a problem */
374         demux->packet = -1;
375       } else {
376         GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
377         gst_event_unref (event);
378         break;
379       }
381       /* record upstream segment for interpolation */
382       if (newsegment_format != demux->in_segment.format)
383         gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
384       gst_segment_set_newsegment_full (&demux->in_segment, update, rate, arate,
385           newsegment_format, newsegment_start, stop, time);
387       /* in either case, clear some state and generate newsegment later on */
388       GST_OBJECT_LOCK (demux);
389       demux->segment_ts = GST_CLOCK_TIME_NONE;
390       demux->in_gap = GST_CLOCK_TIME_NONE;
391       demux->need_newsegment = TRUE;
392       gst_asf_demux_reset_stream_state_after_discont (demux);
393       GST_OBJECT_UNLOCK (demux);
395       gst_event_unref (event);
396       break;
397     }
398     case GST_EVENT_EOS:{
399       GstFlowReturn flow;
401       if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
402         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
403             (_("This stream contains no data.")),
404             ("got eos and didn't receive a complete header object"));
405         break;
406       }
407       flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
408       if (flow < GST_FLOW_UNEXPECTED || flow == GST_FLOW_NOT_LINKED) {
409         GST_ELEMENT_ERROR (demux, STREAM, FAILED,
410             (_("Internal data stream error.")),
411             ("streaming stopped, reason %s", gst_flow_get_name (flow)));
412         break;
413       }
415       GST_OBJECT_LOCK (demux);
416       gst_adapter_clear (demux->adapter);
417       GST_OBJECT_UNLOCK (demux);
418       gst_asf_demux_send_event_unlocked (demux, event);
419       break;
420     }
422     case GST_EVENT_FLUSH_STOP:
423       GST_OBJECT_LOCK (demux);
424       gst_asf_demux_reset_stream_state_after_discont (demux);
425       GST_OBJECT_UNLOCK (demux);
426       gst_asf_demux_send_event_unlocked (demux, event);
427       /* upon activation, latency is no longer introduced, e.g. after seek */
428       if (demux->activated_streams)
429         demux->latency = 0;
430       break;
432     default:
433       ret = gst_pad_event_default (pad, event);
434       break;
435   }
437   gst_object_unref (demux);
438   return ret;
441 static gboolean
442 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
443     GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed)
445   GstClockTime idx_time;
446   guint idx;
448   if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
449     return FALSE;
451   idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
453   /* FIXME: seek beyond end of file should result in immediate EOS from
454    * streaming thread instead of a failed seek */
455   if (G_UNLIKELY (idx >= demux->sidx_num_entries))
456     return FALSE;
458   *packet = demux->sidx_entries[idx].packet;
459   if (speed)
460     *speed = demux->sidx_entries[idx].count;
462   /* so we get closer to the actual time of the packet ... actually, let's not
463    * do this, since we throw away superfluous payloads before the seek position
464    * anyway; this way, our key unit seek 'snap resolution' is a bit better
465    * (ie. same as index resolution) */
466   /*
467      while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
468      --idx;
469    */
471   idx_time = demux->sidx_interval * idx;
472   if (G_LIKELY (idx_time >= demux->preroll))
473     idx_time -= demux->preroll;
475   GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
476       GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
477       GST_TIME_ARGS (idx_time));
479   if (G_LIKELY (p_idx_time))
480     *p_idx_time = idx_time;
482   return TRUE;
485 static void
486 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
488   guint n;
490   gst_adapter_clear (demux->adapter);
492   GST_DEBUG_OBJECT (demux, "reset stream state");
494   for (n = 0; n < demux->num_streams; n++) {
495     demux->stream[n].discont = TRUE;
496     demux->stream[n].last_flow = GST_FLOW_OK;
498     while (demux->stream[n].payloads->len > 0) {
499       AsfPayload *payload;
500       guint last;
502       last = demux->stream[n].payloads->len - 1;
503       payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
504       gst_buffer_replace (&payload->buf, NULL);
505       g_array_remove_index (demux->stream[n].payloads, last);
506     }
507   }
510 static void
511 gst_asf_demux_mark_discont (GstASFDemux * demux)
513   guint n;
515   GST_DEBUG_OBJECT (demux, "Mark stream discont");
517   for (n = 0; n < demux->num_streams; n++)
518     demux->stream[n].discont = TRUE;
521 /* do a seek in push based mode */
522 static gboolean
523 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
525   gdouble rate;
526   GstFormat format;
527   GstSeekFlags flags;
528   GstSeekType cur_type, stop_type;
529   gint64 cur, stop;
530   guint packet;
531   gboolean res;
533   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
534       &stop_type, &stop);
536   stop_type = GST_SEEK_TYPE_NONE;
537   stop = -1;
539   GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
541   /* determine packet, by index or by estimation */
542   if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL)) {
543     packet = (guint) gst_util_uint64_scale (demux->num_packets,
544         cur, demux->play_time);
545   }
547   if (packet > demux->num_packets) {
548     GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
549         "seek aborted.");
550     return FALSE;
551   }
553   GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
555   cur = demux->data_offset + (packet * demux->packet_size);
557   GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
558       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
559   /* BYTE seek event */
560   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur,
561       stop_type, stop);
562   res = gst_pad_push_event (demux->sinkpad, event);
564   return res;
567 static gboolean
568 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
570   GstClockTime idx_time;
571   GstSegment segment;
572   GstSeekFlags flags;
573   GstSeekType cur_type, stop_type;
574   GstFormat format;
575   gboolean only_need_update;
576   gboolean keyunit_sync;
577   gboolean flush;
578   gdouble rate;
579   gint64 cur, stop;
580   gint64 seek_time;
581   guint packet, speed_count = 1;
583   if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
584           demux->num_packets == 0 || demux->play_time == 0)) {
585     GST_LOG_OBJECT (demux, "stream is not seekable");
586     return FALSE;
587   }
589   if (G_UNLIKELY (!demux->activated_streams)) {
590     GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
591     return FALSE;
592   }
594   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
595       &stop_type, &stop);
597   if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
598     GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
599     return FALSE;
600   }
602   if (G_UNLIKELY (rate <= 0.0)) {
603     GST_LOG_OBJECT (demux, "backward playback is not supported yet");
604     return FALSE;
605   }
607   flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
608   demux->accurate =
609       ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
610   keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
612   if (G_UNLIKELY (demux->streaming)) {
613     /* support it safely needs more segment handling, e.g. closing etc */
614     if (!flush) {
615       GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
616       return FALSE;
617     }
618     /* we can (re)construct the start later on, but not the end */
619     if (stop_type != GST_SEEK_TYPE_NONE) {
620       GST_LOG_OBJECT (demux, "streaming; end type must be NONE");
621       return FALSE;
622     }
623     gst_event_ref (event);
624     /* upstream might handle TIME seek, e.g. mms or rtsp,
625      * or not, e.g. http, then we give it a hand */
626     if (!gst_pad_push_event (demux->sinkpad, event))
627       return gst_asf_demux_handle_seek_push (demux, event);
628     else
629       return TRUE;
630   }
632   /* unlock the streaming thread */
633   if (G_LIKELY (flush)) {
634     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
635     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_start ());
636   } else {
637     gst_pad_pause_task (demux->sinkpad);
638   }
640   /* grab the stream lock so that streaming cannot continue, for
641    * non flushing seeks when the element is in PAUSED this could block
642    * forever */
643   GST_PAD_STREAM_LOCK (demux->sinkpad);
645   /* we now can stop flushing, since we have the stream lock now */
646   gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
648   if (G_LIKELY (flush))
649     gst_asf_demux_send_event_unlocked (demux, gst_event_new_flush_stop ());
651   /* operating on copy of segment until we know the seek worked */
652   segment = demux->segment;
654   if (G_UNLIKELY (demux->segment_running && !flush)) {
655     GstEvent *newseg;
657     /* create the segment event to close the current segment */
658     newseg = gst_event_new_new_segment (TRUE, segment.rate,
659         GST_FORMAT_TIME, segment.start, segment.last_stop, segment.time);
661     gst_asf_demux_send_event_unlocked (demux, newseg);
662   }
664   gst_segment_set_seek (&segment, rate, format, flags, cur_type,
665       cur, stop_type, stop, &only_need_update);
667   GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
668       "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
670   seek_time = segment.start;
672   /* FIXME: should check the KEY_UNIT flag; need to adjust last_stop to
673    * real start of data and segment_start to indexed time for key unit seek*/
674   if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
675               &idx_time, &speed_count))) {
676     /* First try to query our source to see if it can convert for us. This is
677        the case when our source is an mms stream, notice that in this case
678        gstmms will do a time based seek to get the byte offset, this is not a
679        problem as the seek to this offset needs to happen anway. */
680     gint64 offset;
681     GstFormat dest_format = GST_FORMAT_BYTES;
683     if (gst_pad_query_peer_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
684             &dest_format, &offset) && dest_format == GST_FORMAT_BYTES) {
685       packet = (offset - demux->data_offset) / demux->packet_size;
686       GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
687           " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
688           G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
689           GST_TIME_ARGS (seek_time), offset, demux->data_offset,
690           demux->packet_size, packet);
691     } else {
692       /* FIXME: For streams containing video, seek to an earlier position in
693        * the hope of hitting a keyframe and let the sinks throw away the stuff
694        * before the segment start. For audio-only this is unnecessary as every
695        * frame is 'key'. */
696       if (flush && (demux->accurate || keyunit_sync)
697           && demux->num_video_streams > 0) {
698         seek_time -= 5 * GST_SECOND;
699         if (seek_time < 0)
700           seek_time = 0;
701       }
703       packet = (guint) gst_util_uint64_scale (demux->num_packets,
704           seek_time, demux->play_time);
706       if (packet > demux->num_packets)
707         packet = demux->num_packets;
708     }
709   } else {
710     if (G_LIKELY (keyunit_sync)) {
711       GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
712           GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
713           GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
714       segment.start = idx_time;
715       segment.last_stop = idx_time;
716       segment.time = idx_time;
717     }
718   }
720   GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
722   GST_OBJECT_LOCK (demux);
723   demux->segment = segment;
724   demux->packet = packet;
725   demux->need_newsegment = TRUE;
726   demux->speed_packets = speed_count;
727   gst_asf_demux_reset_stream_state_after_discont (demux);
728   GST_OBJECT_UNLOCK (demux);
730   /* restart our task since it might have been stopped when we did the flush */
731   gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
732       demux);
734   /* streaming can continue now */
735   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
737   return TRUE;
740 static gboolean
741 gst_asf_demux_handle_src_event (GstPad * pad, GstEvent * event)
743   GstASFDemux *demux;
744   gboolean ret;
746   demux = GST_ASF_DEMUX (gst_pad_get_parent (pad));
748   switch (GST_EVENT_TYPE (event)) {
749     case GST_EVENT_SEEK:
750       GST_LOG_OBJECT (pad, "seek event");
751       ret = gst_asf_demux_handle_seek_event (demux, event);
752       gst_event_unref (event);
753       break;
754     case GST_EVENT_QOS:
755     case GST_EVENT_NAVIGATION:
756       /* just drop these two silently */
757       gst_event_unref (event);
758       ret = FALSE;
759       break;
760     default:
761       GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
762       ret = gst_pad_event_default (pad, event);
763       break;
764   }
766   gst_object_unref (demux);
767   return ret;
770 static inline guint32
771 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
773   guint32 ret;
775   ret = gst_asf_identify_guid (guids, guid);
777   GST_LOG ("%s  0x%08x-0x%08x-0x%08x-0x%08x",
778       gst_asf_get_guid_nick (guids, ret),
779       guid->v1, guid->v2, guid->v3, guid->v4);
781   return ret;
784 typedef struct
786   AsfObjectID id;
787   guint64 size;
788 } AsfObject;
791 /* expect is true when the user is expeting an object,
792  * when false, it will give no warnings if the object
793  * is not identified
794  */
795 static gboolean
796 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
797     guint data_len, AsfObject * object, gboolean expect)
799   ASFGuid guid;
801   if (data_len < ASF_OBJECT_HEADER_SIZE)
802     return FALSE;
804   guid.v1 = GST_READ_UINT32_LE (data + 0);
805   guid.v2 = GST_READ_UINT32_LE (data + 4);
806   guid.v3 = GST_READ_UINT32_LE (data + 8);
807   guid.v4 = GST_READ_UINT32_LE (data + 12);
809   object->size = GST_READ_UINT64_LE (data + 16);
811   /* FIXME: make asf_demux_identify_object_guid() */
812   object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
813   if (object->id == ASF_OBJ_UNDEFINED && expect) {
814     GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
815         guid.v1, guid.v2, guid.v3, guid.v4);
816   }
818   return TRUE;
821 static void
822 gst_asf_demux_release_old_pads (GstASFDemux * demux)
824   GST_DEBUG_OBJECT (demux, "Releasing old pads");
826   while (demux->old_num_streams > 0) {
827     gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
828         gst_event_new_eos ());
829     gst_asf_demux_free_stream (demux,
830         &demux->old_stream[demux->old_num_streams - 1]);
831     --demux->old_num_streams;
832   }
833   memset (demux->old_stream, 0, sizeof (demux->old_stream));
834   demux->old_num_streams = 0;
837 static GstFlowReturn
838 gst_asf_demux_chain_headers (GstASFDemux * demux)
840   GstFlowReturn flow;
841   AsfObject obj;
842   guint8 *header_data, *data = NULL;
843   const guint8 *cdata = NULL;
844   guint64 header_size;
846   cdata = (guint8 *) gst_adapter_peek (demux->adapter, ASF_OBJECT_HEADER_SIZE);
847   if (cdata == NULL)
848     goto need_more_data;
850   asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
851   if (obj.id != ASF_OBJ_HEADER)
852     goto wrong_type;
854   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
856   /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
857   if (gst_adapter_available (demux->adapter) < obj.size + 50)
858     goto need_more_data;
860   data = gst_adapter_take (demux->adapter, obj.size + 50);
862   header_data = data;
863   header_size = obj.size;
864   flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
865   if (flow != GST_FLOW_OK)
866     goto parse_failed;
868   /* calculate where the packet data starts */
869   demux->data_offset = obj.size + 50;
871   /* now parse the beginning of the ASF_OBJ_DATA object */
872   if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
873     goto wrong_type;
875   if (demux->num_streams == 0)
876     goto no_streams;
878   g_free (data);
879   return GST_FLOW_OK;
881 /* NON-FATAL */
882 need_more_data:
883   {
884     GST_LOG_OBJECT (demux, "not enough data in adapter yet");
885     return GST_FLOW_OK;
886   }
888 /* ERRORS */
889 wrong_type:
890   {
891     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
892         ("This doesn't seem to be an ASF file"));
893     g_free (data);
894     return GST_FLOW_ERROR;
895   }
896 no_streams:
897 parse_failed:
898   {
899     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
900         ("header parsing failed, or no streams found, flow = %s",
901             gst_flow_get_name (flow)));
902     g_free (data);
903     return GST_FLOW_ERROR;
904   }
907 static GstFlowReturn
908 gst_asf_demux_aggregate_flow_return (GstASFDemux * demux, AsfStream * stream,
909     GstFlowReturn flow)
911   int i;
913   GST_DEBUG_OBJECT (demux, "Aggregating");
915   /* Store the value */
916   stream->last_flow = flow;
918   /* any other error that is not not-linked can be returned right away */
919   if (flow != GST_FLOW_NOT_LINKED)
920     goto done;
922   for (i = 0; i < demux->num_streams; i++) {
923     if (demux->stream[i].active) {
924       flow = demux->stream[i].last_flow;
925       GST_DEBUG_OBJECT (demux, "Aggregating: flow %i return %s", i,
926           gst_flow_get_name (flow));
927       if (flow != GST_FLOW_NOT_LINKED)
928         goto done;
929     }
930   }
932   /* If we got here, then all our active streams are not linked */
933 done:
934   return flow;
937 static gboolean
938 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
939     GstBuffer ** p_buf, GstFlowReturn * p_flow)
941   GstFlowReturn flow;
943   GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
944       offset, size);
946   flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
948   if (G_LIKELY (p_flow))
949     *p_flow = flow;
951   if (G_UNLIKELY (flow != GST_FLOW_OK)) {
952     GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
953         "+%u", gst_flow_get_name (flow), offset, size);
954     *p_buf = NULL;
955     return FALSE;
956   }
958   g_assert (*p_buf != NULL);
960   if (G_UNLIKELY (GST_BUFFER_SIZE (*p_buf) < size)) {
961     GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
962         "+%u (got only %u bytes)", offset, size, GST_BUFFER_SIZE (*p_buf));
963     gst_buffer_unref (*p_buf);
964     if (G_LIKELY (p_flow))
965       *p_flow = GST_FLOW_UNEXPECTED;
966     *p_buf = NULL;
967     return FALSE;
968   }
970   return TRUE;
973 static void
974 gst_asf_demux_pull_indices (GstASFDemux * demux)
976   GstBuffer *buf = NULL;
977   guint64 offset;
978   guint num_read = 0;
980   offset = demux->index_offset;
982   if (G_UNLIKELY (offset == 0)) {
983     GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
984     return;
985   }
987   while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
988     GstFlowReturn flow;
989     AsfObject obj;
991     asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
992     gst_buffer_replace (&buf, NULL);
994     /* check for sanity */
995     if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
996       GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
997       break;
998     }
1000     if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1001                 NULL)))
1002       break;
1004     GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1005         ", size %u", offset, (guint) obj.size);
1007     offset += obj.size;         /* increase before _process_object changes it */
1009     flow = gst_asf_demux_process_object (demux, &buf->data, &obj.size);
1010     gst_buffer_replace (&buf, NULL);
1012     if (G_UNLIKELY (flow != GST_FLOW_OK))
1013       break;
1015     ++num_read;
1016   }
1017   GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1020 static gboolean
1021 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1023   AsfObject obj;
1025   asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1026   if (obj.id != ASF_OBJ_DATA) {
1027     GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1028     return FALSE;
1029   }
1031   demux->state = GST_ASF_DEMUX_STATE_DATA;
1033   if (!demux->broadcast && obj.size > 50) {
1034     demux->data_size = obj.size - 50;
1035     /* CHECKME: for at least one file this is off by +158 bytes?! */
1036     demux->index_offset = demux->data_offset + demux->data_size;
1037   } else {
1038     demux->data_size = 0;
1039     demux->index_offset = 0;
1040   }
1042   demux->packet = 0;
1044   if (!demux->broadcast) {
1045     /* skip object header (24 bytes) and file GUID (16 bytes) */
1046     demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1047   } else {
1048     demux->num_packets = 0;
1049   }
1051   if (demux->num_packets == 0)
1052     demux->seekable = FALSE;
1054   /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1055   if (demux->data_size == 0 && demux->num_packets > 0) {
1056     demux->data_size = demux->num_packets * demux->packet_size;
1057     demux->index_offset = demux->data_offset + demux->data_size;
1058   }
1060   /* process pending stream objects and create pads for those */
1061   gst_asf_demux_process_queued_extended_stream_objects (demux);
1063   GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1064       "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1065       ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1066       demux->data_offset, demux->data_size, demux->index_offset);
1068   return TRUE;
1071 static gboolean
1072 gst_asf_demux_pull_headers (GstASFDemux * demux)
1074   GstFlowReturn flow;
1075   AsfObject obj;
1076   GstBuffer *buf = NULL;
1077   guint64 size;
1079   GST_LOG_OBJECT (demux, "reading headers");
1081   /* pull HEADER object header, so we know its size */
1082   if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, NULL))
1083     goto read_failed;
1085   asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE);
1086   gst_buffer_replace (&buf, NULL);
1088   if (obj.id != ASF_OBJ_HEADER)
1089     goto wrong_type;
1091   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1093   /* pull HEADER object */
1094   if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1095           NULL))
1096     goto read_failed;
1098   size = obj.size;              /* don't want obj.size changed */
1099   flow = gst_asf_demux_process_object (demux, &buf->data, &size);
1100   gst_buffer_replace (&buf, NULL);
1102   if (flow != GST_FLOW_OK) {
1103     GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1104     goto parse_failed;
1105   }
1107   /* calculate where the packet data starts */
1108   demux->data_offset = demux->base_offset + obj.size + 50;
1110   /* now pull beginning of DATA object before packet data */
1111   if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1112           NULL))
1113     goto read_failed;
1115   if (!gst_asf_demux_parse_data_object_start (demux, GST_BUFFER_DATA (buf)))
1116     goto wrong_type;
1118   if (demux->num_streams == 0)
1119     goto no_streams;
1121   gst_buffer_replace (&buf, NULL);
1122   return TRUE;
1124 /* ERRORS */
1125 wrong_type:
1126   {
1127     gst_buffer_replace (&buf, NULL);
1128     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1129         ("This doesn't seem to be an ASF file"));
1130     return FALSE;
1131   }
1132 no_streams:
1133 read_failed:
1134 parse_failed:
1135   {
1136     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), (NULL));
1137     return FALSE;
1138   }
1141 static gboolean
1142 all_streams_prerolled (GstASFDemux * demux)
1144   GstClockTime preroll_time;
1145   guint i, num_no_data = 0;
1147   /* Allow at least 500ms of preroll_time  */
1148   preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1150   /* returns TRUE as long as there isn't a stream which (a) has data queued
1151    * and (b) the timestamp of last piece of data queued is < demux->preroll
1152    * AND there is at least one other stream with data queued */
1153   for (i = 0; i < demux->num_streams; ++i) {
1154     AsfPayload *last_payload;
1155     AsfStream *stream;
1156     guint last_idx;
1158     stream = &demux->stream[i];
1159     if (G_UNLIKELY (stream->payloads->len == 0)) {
1160       ++num_no_data;
1161       GST_LOG_OBJECT (stream->pad, "no data queued");
1162       continue;
1163     }
1165     last_idx = stream->payloads->len - 1;
1166     last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1168     GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1169         GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1170         GST_TIME_ARGS (preroll_time));
1171     if (G_UNLIKELY (last_payload->ts <= preroll_time)) {
1172       GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1173       return FALSE;
1174     }
1175   }
1177   if (G_UNLIKELY (num_no_data == demux->num_streams))
1178     return FALSE;
1180   return TRUE;
1183 #if 0
1184 static gboolean
1185 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1186     AsfStream * stream)
1188   GSList *l;
1190   for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1191     guint8 *mes;
1193     /* check for each mutual exclusion group whether it affects this stream */
1194     for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1195       if (*mes == stream->id) {
1196         /* we are in this group; let's check if we've already activated streams
1197          * that are in the same group (and hence mutually exclusive to this
1198          * one) */
1199         for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1200           guint i;
1202           for (i = 0; i < demux->num_streams; ++i) {
1203             if (demux->stream[i].id == *mes && demux->stream[i].active) {
1204               GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1205                   "to already active stream with ID %d", stream->id,
1206                   demux->stream[i].id);
1207               return TRUE;
1208             }
1209           }
1210         }
1211         /* we can only be in this group once, let's break out and move on to
1212          * the next mutual exclusion group */
1213         break;
1214       }
1215     }
1216   }
1218   return FALSE;
1220 #endif
1222 static gboolean
1223 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1225   guint i;
1227   if (demux->activated_streams)
1228     return TRUE;
1230   if (!all_streams_prerolled (demux) && !force) {
1231     GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1232     return FALSE;
1233   }
1235   for (i = 0; i < demux->num_streams; ++i) {
1236     AsfStream *stream = &demux->stream[i];
1238     if (stream->payloads->len > 0) {
1239       /* we don't check mutual exclusion stuff here; either we have data for
1240        * a stream, then we active it, or we don't, then we'll ignore it */
1241       GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1242       gst_asf_demux_activate_stream (demux, stream);
1243     } else {
1244       GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1245     }
1246   }
1248   gst_asf_demux_release_old_pads (demux);
1250   demux->activated_streams = TRUE;
1251   GST_LOG_OBJECT (demux, "signalling no more pads");
1252   gst_element_no_more_pads (GST_ELEMENT (demux));
1253   return TRUE;
1256 /* returns the stream that has a complete payload with the lowest timestamp
1257  * queued, or NULL (we push things by timestamp because during the internal
1258  * prerolling we might accumulate more data then the external queues can take,
1259  * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1260 static AsfStream *
1261 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1263   AsfPayload *best_payload = NULL;
1264   AsfStream *best_stream = NULL;
1265   guint i;
1267   for (i = 0; i < demux->num_streams; ++i) {
1268     AsfStream *stream;
1270     stream = &demux->stream[i];
1272     /* Don't push any data until we have at least one payload that falls within
1273      * the current segment. This way we can remove out-of-segment payloads that
1274      * don't need to be decoded after a seek, sending only data from the
1275      * keyframe directly before our segment start */
1276     if (stream->payloads->len > 0) {
1277       AsfPayload *payload;
1278       guint last_idx;
1280       last_idx = stream->payloads->len - 1;
1281       payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1282       if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1283               (payload->ts < demux->segment.start))) {
1284         if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
1285           GST_DEBUG_OBJECT (stream->pad,
1286               "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1287               GST_TIME_ARGS (payload->ts));
1288           demux->segment.start = payload->ts;
1289           demux->segment.time = payload->ts;
1290         } else {
1291           GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1292               GST_TIME_FORMAT " which is before our segment start %"
1293               GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
1294               GST_TIME_ARGS (demux->segment.start));
1295           continue;
1296         }
1297       }
1299       /* Now see if there's a complete payload queued for this stream */
1301       payload = &g_array_index (stream->payloads, AsfPayload, 0);
1302       if (!gst_asf_payload_is_complete (payload))
1303         continue;
1305       /* ... and whether its timestamp is lower than the current best */
1306       if (best_stream == NULL || best_payload->ts > payload->ts) {
1307         best_stream = stream;
1308         best_payload = payload;
1309       }
1310     }
1311   }
1313   return best_stream;
1316 static GstFlowReturn
1317 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1319   AsfStream *stream;
1320   GstFlowReturn ret = GST_FLOW_OK;
1322   if (G_UNLIKELY (!demux->activated_streams)) {
1323     if (!gst_asf_demux_check_activate_streams (demux, force))
1324       return GST_FLOW_OK;
1325     /* streams are now activated */
1326   }
1328   /* wait until we had a chance to "lock on" some payload's timestamp */
1329   if (G_UNLIKELY (demux->need_newsegment
1330           && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1331     return GST_FLOW_OK;
1333   while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1334     AsfPayload *payload;
1336     payload = &g_array_index (stream->payloads, AsfPayload, 0);
1338     /* do we need to send a newsegment event */
1339     if ((G_UNLIKELY (demux->need_newsegment))) {
1341       /* safe default if insufficient upstream info */
1342       if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1343         demux->in_gap = 0;
1345       if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1346           demux->segment.duration > 0) {
1347         /* slight HACK; prevent clipping of last bit */
1348         demux->segment.stop = demux->segment.duration + demux->in_gap;
1349       }
1351       /* FIXME : only if ACCURATE ! */
1352       if (G_LIKELY (!demux->accurate
1353               && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
1354         GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1355             GST_TIME_ARGS (payload->ts));
1356         demux->segment.start = payload->ts;
1357         demux->segment.time = payload->ts;
1358       }
1360       GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1361           &demux->segment);
1363       /* note: we fix up all timestamps to start from 0, so this should be ok */
1364       gst_asf_demux_send_event_unlocked (demux,
1365           gst_event_new_new_segment (FALSE, demux->segment.rate,
1366               GST_FORMAT_TIME, demux->segment.start, demux->segment.stop,
1367               demux->segment.start));
1369       /* now post any global tags we may have found */
1370       if (demux->taglist == NULL)
1371         demux->taglist = gst_tag_list_new ();
1373       gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1374           GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1376       GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1377       gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
1378       demux->taglist = NULL;
1380       demux->need_newsegment = FALSE;
1381       demux->segment_running = TRUE;
1382     }
1384     /* Do we have tags pending for this stream? */
1385     if (G_UNLIKELY (stream->pending_tags)) {
1386       GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1387       gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad,
1388           stream->pending_tags);
1389       stream->pending_tags = NULL;
1390     }
1392     /* We have the whole packet now so we should push the packet to
1393      * the src pad now. First though we should check if we need to do
1394      * descrambling */
1395     if (G_UNLIKELY (demux->span > 1)) {
1396       gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1397     }
1399     payload->buf = gst_buffer_make_metadata_writable (payload->buf);
1401     if (G_LIKELY (!payload->keyframe)) {
1402       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1403     }
1405     if (G_UNLIKELY (stream->discont)) {
1406       GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1407       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1408       stream->discont = FALSE;
1409     }
1411     if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1412             (payload->par_x != stream->par_x) &&
1413             (payload->par_y != stream->par_y))) {
1414       GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1415           stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1416       stream->par_x = payload->par_x;
1417       stream->par_y = payload->par_y;
1418       gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1419           GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1420       gst_pad_set_caps (stream->pad, stream->caps);
1421     }
1423     if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1424       GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1425           payload->interlaced);
1426       stream->interlaced = payload->interlaced;
1427       gst_caps_set_simple (stream->caps, "interlaced", G_TYPE_BOOLEAN,
1428           stream->interlaced, NULL);
1429     }
1431     gst_buffer_set_caps (payload->buf, stream->caps);
1433     /* (sort of) interpolate timestamps using upstream "frame of reference",
1434      * typically useful for live src, but might (unavoidably) mess with
1435      * position reporting if a live src is playing not so live content
1436      * (e.g. rtspsrc taking some time to fall back to tcp) */
1437     GST_BUFFER_TIMESTAMP (payload->buf) = payload->ts + demux->in_gap;
1438     if (payload->duration == GST_CLOCK_TIME_NONE
1439         && stream->ext_props.avg_time_per_frame != 0)
1440       GST_BUFFER_DURATION (payload->buf) =
1441           stream->ext_props.avg_time_per_frame * 100;
1442     else
1443       GST_BUFFER_DURATION (payload->buf) = payload->duration;
1445     /* FIXME: we should really set durations on buffers if we can */
1447     GST_LOG_OBJECT (stream->pad, "pushing buffer, ts=%" GST_TIME_FORMAT
1448         ", dur=%" GST_TIME_FORMAT " size=%u",
1449         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (payload->buf)),
1450         GST_TIME_ARGS (GST_BUFFER_DURATION (payload->buf)),
1451         GST_BUFFER_SIZE (payload->buf));
1453     ret = gst_pad_push (stream->pad, payload->buf);
1454     ret = gst_asf_demux_aggregate_flow_return (demux, stream, ret);
1455     payload->buf = NULL;
1456     g_array_remove_index (stream->payloads, 0);
1458     /* Break out as soon as we have an issue */
1459     if (G_UNLIKELY (ret != GST_FLOW_OK))
1460       break;
1461   }
1463   return ret;
1466 static gboolean
1467 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1469   AsfObject obj;
1470   g_assert (buf != NULL);
1472   GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1474   /* we return false on buffer too small */
1475   if (GST_BUFFER_SIZE (buf) < ASF_OBJECT_HEADER_SIZE)
1476     return FALSE;
1478   /* check if it is a header */
1479   asf_demux_peek_object (demux, GST_BUFFER_DATA (buf),
1480       ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1481   if (obj.id == ASF_OBJ_HEADER) {
1482     return TRUE;
1483   }
1484   return FALSE;
1487 static gboolean
1488 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1490   guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1491   GstFlowReturn ret = GST_FLOW_OK;
1492   GstBuffer *buf = NULL;
1493   gboolean header = FALSE;
1495   /* TODO maybe we should skip index objects after the data and look
1496    * further for a new header */
1497   if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1498     g_assert (buf != NULL);
1499     /* check if it is a header */
1500     if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1501       GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1502       demux->base_offset = off;
1503       header = TRUE;
1504     }
1506     gst_buffer_unref (buf);
1507   }
1509   return header;
1512 static void
1513 gst_asf_demux_loop (GstASFDemux * demux)
1515   GstFlowReturn flow = GST_FLOW_OK;
1516   GstBuffer *buf = NULL;
1517   guint64 off;
1518   gboolean sent_eos = FALSE;
1520   if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1521     if (!gst_asf_demux_pull_headers (demux)) {
1522       flow = GST_FLOW_ERROR;
1523       goto pause;
1524     }
1526     gst_asf_demux_pull_indices (demux);
1527   }
1529   g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1531   if (G_UNLIKELY (demux->num_packets != 0
1532           && demux->packet >= demux->num_packets))
1533     goto eos;
1535   GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1536       (guint) demux->num_packets);
1538   off = demux->data_offset + (demux->packet * demux->packet_size);
1540   if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1541               demux->packet_size * demux->speed_packets, &buf, &flow))) {
1542     GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1543     if (flow == GST_FLOW_UNEXPECTED)
1544       goto eos;
1545     else if (flow == GST_FLOW_WRONG_STATE) {
1546       GST_DEBUG_OBJECT (demux, "Not fatal");
1547       goto pause;
1548     } else
1549       goto read_failed;
1550   }
1552   if (G_LIKELY (demux->speed_packets == 1)) {
1553     /* FIXME: maybe we should just skip broken packets and error out only
1554      * after a few broken packets in a row? */
1555     if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1556       /* when we don't know when the data object ends, we should check
1557        * for a chained asf */
1558       if (demux->num_packets == 0) {
1559         if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1560           GST_INFO_OBJECT (demux, "Chained asf found");
1561           demux->base_offset = off;
1562           gst_asf_demux_reset (demux, TRUE);
1563           gst_buffer_unref (buf);
1564           return;
1565         }
1566       }
1567       goto parse_error;
1568     }
1570     flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1572     ++demux->packet;
1574   } else {
1575     guint n;
1576     for (n = 0; n < demux->speed_packets; n++) {
1577       GstBuffer *sub;
1579       sub =
1580           gst_buffer_create_sub (buf, n * demux->packet_size,
1581           demux->packet_size);
1582       /* FIXME: maybe we should just skip broken packets and error out only
1583        * after a few broken packets in a row? */
1584       if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, sub))) {
1585         /* when we don't know when the data object ends, we should check
1586          * for a chained asf */
1587         if (demux->num_packets == 0) {
1588           if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
1589             GST_INFO_OBJECT (demux, "Chained asf found");
1590             demux->base_offset = off + n * demux->packet_size;
1591             gst_asf_demux_reset (demux, TRUE);
1592             gst_buffer_unref (sub);
1593             gst_buffer_unref (buf);
1594             return;
1595           }
1596         }
1597         goto parse_error;
1598       }
1600       gst_buffer_unref (sub);
1602       flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1604       ++demux->packet;
1606     }
1608     /* reset speed pull */
1609     demux->speed_packets = 1;
1610   }
1612   gst_buffer_unref (buf);
1614   if (G_UNLIKELY (demux->num_packets > 0
1615           && demux->packet >= demux->num_packets)) {
1616     GST_LOG_OBJECT (demux, "reached EOS");
1617     goto eos;
1618   }
1620   if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1621     GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
1622     goto pause;
1623   }
1625   /* check if we're at the end of the configured segment */
1626   /* FIXME: check if segment end reached etc. */
1628   return;
1630 eos:
1631   {
1632     /* if we haven't activated our streams yet, this might be because we have
1633      * less data queued than required for preroll; force stream activation and
1634      * send any pending payloads before sending EOS */
1635     if (!demux->activated_streams)
1636       gst_asf_demux_push_complete_payloads (demux, TRUE);
1638     /* we want to push an eos or post a segment-done in any case */
1639     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1640       gint64 stop;
1642       /* for segment playback we need to post when (in stream time)
1643        * we stopped, this is either stop (when set) or the duration. */
1644       if ((stop = demux->segment.stop) == -1)
1645         stop = demux->segment.duration;
1647       GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
1648       gst_element_post_message (GST_ELEMENT_CAST (demux),
1649           gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
1650               stop));
1651     } else if (flow != GST_FLOW_UNEXPECTED) {
1652       /* check if we have a chained asf, in case, we don't eos yet */
1653       if (gst_asf_demux_check_chained_asf (demux)) {
1654         GST_INFO_OBJECT (demux, "Chained ASF starting");
1655         gst_asf_demux_reset (demux, TRUE);
1656         return;
1657       }
1658     }
1659     /* normal playback, send EOS to all linked pads */
1660     GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
1661     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1662     sent_eos = TRUE;
1663     /* ... and fall through to pause */
1664   }
1665 pause:
1666   {
1667     GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
1668         gst_flow_get_name (flow));
1669     demux->segment_running = FALSE;
1670     gst_pad_pause_task (demux->sinkpad);
1672     /* For the error cases (not EOS) */
1673     if (!sent_eos) {
1674       if (flow == GST_FLOW_UNEXPECTED)
1675         gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1676       else if (flow < GST_FLOW_UNEXPECTED || flow == GST_FLOW_NOT_LINKED) {
1677         /* Post an error. Hopefully something else already has, but if not... */
1678         GST_ELEMENT_ERROR (demux, STREAM, FAILED,
1679             (_("Internal data stream error.")),
1680             ("streaming stopped, reason %s", gst_flow_get_name (flow)));
1681       }
1682     }
1683     return;
1684   }
1686 /* ERRORS */
1687 read_failed:
1688   {
1689     GST_DEBUG_OBJECT (demux, "Read failed, doh");
1690     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1691     flow = GST_FLOW_UNEXPECTED;
1692     goto pause;
1693   }
1694 parse_error:
1695   {
1696     gst_buffer_unref (buf);
1697     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1698         ("Error parsing ASF packet %u", (guint) demux->packet));
1699     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
1700     flow = GST_FLOW_ERROR;
1701     goto pause;
1702   }
1705 #define GST_ASF_DEMUX_CHECK_HEADER_YES       0
1706 #define GST_ASF_DEMUX_CHECK_HEADER_NO        1
1707 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
1709 static gint
1710 gst_asf_demux_check_header (GstASFDemux * demux)
1712   AsfObject obj;
1713   guint8 *cdata = (guint8 *) gst_adapter_peek (demux->adapter,
1714       ASF_OBJECT_HEADER_SIZE);
1715   if (cdata == NULL)            /* need more data */
1716     return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
1718   asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
1719   if (obj.id != ASF_OBJ_HEADER) {
1720     return GST_ASF_DEMUX_CHECK_HEADER_NO;
1721   } else {
1722     return GST_ASF_DEMUX_CHECK_HEADER_YES;
1723   }
1726 static GstFlowReturn
1727 gst_asf_demux_chain (GstPad * pad, GstBuffer * buf)
1729   GstFlowReturn ret = GST_FLOW_OK;
1730   GstASFDemux *demux;
1732   demux = GST_ASF_DEMUX (GST_PAD_PARENT (pad));
1734   GST_LOG_OBJECT (demux, "buffer: size=%u, offset=%" G_GINT64_FORMAT ", time=%"
1735       GST_TIME_FORMAT, GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf),
1736       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1738   if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
1739     GST_DEBUG_OBJECT (demux, "received DISCONT");
1740     gst_asf_demux_mark_discont (demux);
1741   }
1743   if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
1744               GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
1745     demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
1746     GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
1747         ", interpolation gap: %" GST_TIME_FORMAT,
1748         GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
1749   }
1751   gst_adapter_push (demux->adapter, buf);
1753   switch (demux->state) {
1754     case GST_ASF_DEMUX_STATE_INDEX:{
1755       gint result = gst_asf_demux_check_header (demux);
1756       if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA)       /* need more data */
1757         break;
1759       if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
1760         /* we don't care about this, probably an index */
1761         /* TODO maybe would be smarter to skip all the indices
1762          * until we got a new header or EOS to decide */
1763         GST_LOG_OBJECT (demux, "Received index object, its EOS");
1764         goto eos;
1765       } else {
1766         GST_INFO_OBJECT (demux, "Chained asf starting");
1767         /* cleanup and get ready for a chained asf */
1768         gst_asf_demux_reset (demux, TRUE);
1769         /* fall through */
1770       }
1771     }
1772     case GST_ASF_DEMUX_STATE_HEADER:{
1773       ret = gst_asf_demux_chain_headers (demux);
1774       if (demux->state != GST_ASF_DEMUX_STATE_DATA)
1775         break;
1776       /* otherwise fall through */
1777     }
1778     case GST_ASF_DEMUX_STATE_DATA:
1779     {
1780       guint64 data_size;
1782       data_size = demux->packet_size;
1784       while (gst_adapter_available (demux->adapter) >= data_size) {
1785         GstBuffer *buf;
1787         /* we don't know the length of the stream
1788          * check for a chained asf everytime */
1789         if (demux->num_packets == 0) {
1790           gint result = gst_asf_demux_check_header (demux);
1792           if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
1793             GST_INFO_OBJECT (demux, "Chained asf starting");
1794             /* cleanup and get ready for a chained asf */
1795             gst_asf_demux_reset (demux, TRUE);
1796             break;
1797           }
1798         } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1799                 && demux->packet >= demux->num_packets)) {
1800           /* do not overshoot data section when streaming */
1801           break;
1802         }
1804         buf = gst_adapter_take_buffer (demux->adapter, data_size);
1806         /* FIXME: maybe we should just skip broken packets and error out only
1807          * after a few broken packets in a row? */
1808         if (G_UNLIKELY (!gst_asf_demux_parse_packet (demux, buf))) {
1809           GST_WARNING_OBJECT (demux, "Parse error");
1810         }
1812         gst_buffer_unref (buf);
1814         ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
1816         if (demux->packet >= 0)
1817           ++demux->packet;
1818       }
1819       if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
1820               && demux->packet >= demux->num_packets)) {
1821         demux->state = GST_ASF_DEMUX_STATE_INDEX;
1822       }
1823       break;
1824     }
1825     default:
1826       g_assert_not_reached ();
1827   }
1829 done:
1830   if (ret != GST_FLOW_OK)
1831     GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
1833   return ret;
1835 eos:
1836   {
1837     GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
1838     ret = GST_FLOW_UNEXPECTED;
1839     goto done;
1840   }
1843 static inline gboolean
1844 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
1846   if (*p_size < num_bytes)
1847     return FALSE;
1849   *p_data += num_bytes;
1850   *p_size -= num_bytes;
1851   return TRUE;
1854 static inline guint8
1855 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
1857   guint8 ret;
1859   g_assert (*p_size >= 1);
1860   ret = GST_READ_UINT8 (*p_data);
1861   *p_data += sizeof (guint8);
1862   *p_size -= sizeof (guint8);
1863   return ret;
1866 static inline guint16
1867 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
1869   guint16 ret;
1871   g_assert (*p_size >= 2);
1872   ret = GST_READ_UINT16_LE (*p_data);
1873   *p_data += sizeof (guint16);
1874   *p_size -= sizeof (guint16);
1875   return ret;
1878 static inline guint32
1879 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
1881   guint32 ret;
1883   g_assert (*p_size >= 4);
1884   ret = GST_READ_UINT32_LE (*p_data);
1885   *p_data += sizeof (guint32);
1886   *p_size -= sizeof (guint32);
1887   return ret;
1890 static inline guint64
1891 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
1893   guint64 ret;
1895   g_assert (*p_size >= 8);
1896   ret = GST_READ_UINT64_LE (*p_data);
1897   *p_data += sizeof (guint64);
1898   *p_size -= sizeof (guint64);
1899   return ret;
1902 static inline guint32
1903 gst_asf_demux_get_var_length (guint8 type, guint8 ** p_data, guint64 * p_size)
1905   switch (type) {
1906     case 0:
1907       return 0;
1909     case 1:
1910       g_assert (*p_size >= 1);
1911       return gst_asf_demux_get_uint8 (p_data, p_size);
1913     case 2:
1914       g_assert (*p_size >= 2);
1915       return gst_asf_demux_get_uint16 (p_data, p_size);
1917     case 3:
1918       g_assert (*p_size >= 4);
1919       return gst_asf_demux_get_uint32 (p_data, p_size);
1921     default:
1922       g_assert_not_reached ();
1923       break;
1924   }
1925   return 0;
1928 static gboolean
1929 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
1930     guint8 ** p_data, guint64 * p_size)
1932   *p_buf = NULL;
1934   if (*p_size < num_bytes_to_read)
1935     return FALSE;
1937   *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
1938   memcpy (GST_BUFFER_DATA (*p_buf), *p_data, num_bytes_to_read);
1939   *p_data += num_bytes_to_read;
1940   *p_size -= num_bytes_to_read;
1941   return TRUE;
1944 static gboolean
1945 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
1946     guint8 ** p_data, guint64 * p_size)
1948   *p_buf = NULL;
1950   if (*p_size < num_bytes_to_read)
1951     return FALSE;
1953   *p_buf = g_memdup (*p_data, num_bytes_to_read);
1954   *p_data += num_bytes_to_read;
1955   *p_size -= num_bytes_to_read;
1956   return TRUE;
1959 static gboolean
1960 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
1961     guint8 ** p_data, guint64 * p_size)
1963   guint16 s_length;
1964   guint8 *s;
1966   *p_str = NULL;
1968   if (*p_size < 2)
1969     return FALSE;
1971   s_length = gst_asf_demux_get_uint16 (p_data, p_size);
1973   if (p_strlen)
1974     *p_strlen = s_length;
1976   if (s_length == 0) {
1977     GST_WARNING ("zero-length string");
1978     *p_str = g_strdup ("");
1979     return TRUE;
1980   }
1982   if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
1983     return FALSE;
1985   g_assert (s != NULL);
1987   /* just because They don't exist doesn't
1988    * mean They are not out to get you ... */
1989   if (s[s_length - 1] != '\0') {
1990     s = g_realloc (s, s_length + 1);
1991     s[s_length] = '\0';
1992   }
1994   *p_str = (gchar *) s;
1995   return TRUE;
1999 static void
2000 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2002   g_assert (*p_size >= 4 * sizeof (guint32));
2004   guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2005   guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2006   guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2007   guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2010 static gboolean
2011 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2012     guint64 * p_size)
2014   if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2015     return FALSE;
2017   /* WAVEFORMATEX Structure */
2018   audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2019   audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2020   audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2021   audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2022   audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2023   audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2024   /* Codec specific data size */
2025   audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2026   return TRUE;
2029 static gboolean
2030 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2031     guint64 * p_size)
2033   if (*p_size < (4 + 4 + 1 + 2))
2034     return FALSE;
2036   video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2037   video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2038   video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2039   video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2040   return TRUE;
2043 static gboolean
2044 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2045     guint8 ** p_data, guint64 * p_size)
2047   if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2048     return FALSE;
2050   fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2051   fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2052   fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2053   fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2054   fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2055   fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2056   fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2057   fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2058   fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2059   fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2060   fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2061   return TRUE;
2064 AsfStream *
2065 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2067   guint i;
2069   for (i = 0; i < demux->num_streams; i++) {
2070     if (demux->stream[i].id == id)
2071       return &demux->stream[i];
2072   }
2074   GST_WARNING ("Segment found for undefined stream: (%d)", id);
2075   return NULL;
2078 static void
2079 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2080     GstCaps * caps, guint16 id, gboolean is_video, GstTagList * tags)
2082   AsfStream *stream;
2084   gst_pad_use_fixed_caps (src_pad);
2085   gst_pad_set_caps (src_pad, caps);
2087   gst_pad_set_event_function (src_pad,
2088       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2089   gst_pad_set_query_type_function (src_pad,
2090       GST_DEBUG_FUNCPTR (gst_asf_demux_get_src_query_types));
2091   gst_pad_set_query_function (src_pad,
2092       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2094   stream = &demux->stream[demux->num_streams];
2095   stream->caps = caps;
2096   stream->pad = src_pad;
2097   stream->id = id;
2098   stream->fps_known = !is_video;        /* bit hacky for audio */
2099   stream->is_video = is_video;
2100   stream->pending_tags = tags;
2101   stream->discont = TRUE;
2102   if (is_video) {
2103     GstStructure *st;
2104     gint par_x, par_y;
2105     st = gst_caps_get_structure (caps, 0);
2106     if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2107         par_x > 0 && par_y > 0) {
2108       GST_DEBUG ("PAR %d/%d", par_x, par_y);
2109       stream->par_x = par_x;
2110       stream->par_y = par_y;
2111     }
2112   }
2114   stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2116   GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2117       GST_PAD_NAME (src_pad), demux->num_streams, caps);
2119   ++demux->num_streams;
2121   stream->active = FALSE;
2124 static void
2125 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2126     asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2128   GstTagList *tags = NULL;
2129   GstBuffer *extradata = NULL;
2130   GstPad *src_pad;
2131   GstCaps *caps;
2132   guint16 size_left = 0;
2133   gchar *codec_name = NULL;
2134   gchar *name = NULL;
2136   size_left = audio->size;
2138   /* Create the audio pad */
2139   name = g_strdup_printf ("audio_%02d", demux->num_audio_streams);
2141   src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2142   g_free (name);
2144   /* Swallow up any left over data and set up the 
2145    * standard properties from the header info */
2146   if (size_left) {
2147     GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2148         "codec specific data", size_left);
2150     g_assert (size_left <= *p_size);
2151     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2152   }
2154   /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2155    * additional two bytes indicating extradata. */
2156   caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2157       (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name);
2159   if (caps == NULL) {
2160     caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2161         G_TYPE_INT, (gint) audio->codec_tag, NULL);
2162   }
2164   /* Informing about that audio format we just added */
2165   if (codec_name) {
2166     tags = gst_tag_list_new ();
2167     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
2168         codec_name, NULL);
2169     g_free (codec_name);
2170   }
2172   if (extradata)
2173     gst_buffer_unref (extradata);
2175   GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2176       GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2177       audio->codec_tag, tags);
2179   ++demux->num_audio_streams;
2181   gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, tags);
2184 static void
2185 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2186     asf_stream_video_format * video, guint16 id,
2187     guint8 ** p_data, guint64 * p_size)
2189   GstTagList *tags = NULL;
2190   GstBuffer *extradata = NULL;
2191   GstPad *src_pad;
2192   GstCaps *caps;
2193   gchar *name = NULL;
2194   gchar *codec_name = NULL;
2195   gint size_left = video->size - 40;
2197   /* Create the video pad */
2198   name = g_strdup_printf ("video_%02d", demux->num_video_streams);
2199   src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2200   g_free (name);
2202   /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2203   if (size_left) {
2204     GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2205     g_assert (size_left <= *p_size);
2206     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2207   }
2209   GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2211   /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2212   caps = gst_riff_create_video_caps (video->tag, NULL,
2213       (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2215   if (caps == NULL) {
2216     caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2217         GST_TYPE_FOURCC, video->tag, NULL);
2218   } else {
2219     GstStructure *s;
2220     gint ax, ay;
2222     s = gst_asf_demux_get_metadata_for_stream (demux, id);
2223     if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2224         gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2225       gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2226           ax, ay, NULL);
2228     } else {
2229       guint ax, ay;
2230       /* retry with the global metadata */
2231       GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2232           demux->global_metadata);
2233       s = demux->global_metadata;
2234       if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2235           gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2236         GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2237         if (ax > 0 && ay > 0)
2238           gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2239               ax, ay, NULL);
2240       }
2241     }
2242     s = gst_caps_get_structure (caps, 0);
2243     gst_structure_remove_field (s, "framerate");
2244   }
2246   /* add fourcc format to caps, some proprietary decoders seem to need it */
2247   gst_caps_set_simple (caps, "format", GST_TYPE_FOURCC, video->tag, NULL);
2249   if (codec_name) {
2250     tags = gst_tag_list_new ();
2251     gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
2252         codec_name, NULL);
2253     g_free (codec_name);
2254   }
2256   if (extradata)
2257     gst_buffer_unref (extradata);
2259   GST_INFO ("Adding video stream #%u, id %u, codec %"
2260       GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2261       GST_FOURCC_ARGS (video->tag), video->tag);
2263   ++demux->num_video_streams;
2265   gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE, tags);
2268 static void
2269 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2271   if (!stream->active) {
2272     GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2273         GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2274     gst_pad_set_active (stream->pad, TRUE);
2275     gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2276     stream->active = TRUE;
2277   }
2280 static AsfStream *
2281 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2282     guint64 size)
2284   AsfCorrectionType correction_type;
2285   AsfStreamType stream_type;
2286   GstClockTime time_offset;
2287   gboolean is_encrypted G_GNUC_UNUSED;
2288   guint16 stream_id;
2289   guint16 flags;
2290   ASFGuid guid;
2291   guint stream_specific_size;
2292   guint type_specific_size G_GNUC_UNUSED;
2293   guint unknown G_GNUC_UNUSED;
2295   /* Get the rest of the header's header */
2296   if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2297     goto not_enough_data;
2299   gst_asf_demux_get_guid (&guid, &data, &size);
2300   stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2302   gst_asf_demux_get_guid (&guid, &data, &size);
2303   correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2305   time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2307   type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2308   stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2310   flags = gst_asf_demux_get_uint16 (&data, &size);
2311   stream_id = flags & 0x7f;
2312   is_encrypted = ! !((flags & 0x8000) << 15);
2313   unknown = gst_asf_demux_get_uint32 (&data, &size);
2315   GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2316       stream_id, GST_TIME_ARGS (time_offset));
2318   switch (stream_type) {
2319     case ASF_STREAM_AUDIO:{
2320       asf_stream_audio audio_object;
2322       if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2323         goto not_enough_data;
2325       GST_INFO ("Object is an audio stream with %u bytes of additional data",
2326           audio_object.size);
2328       gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2329           &data, &size);
2331       switch (correction_type) {
2332         case ASF_CORRECTION_ON:{
2333           guint span, packet_size, chunk_size, data_size, silence_data;
2335           GST_INFO ("Using error correction");
2337           if (size < (1 + 2 + 2 + 2 + 1))
2338             goto not_enough_data;
2340           span = gst_asf_demux_get_uint8 (&data, &size);
2341           packet_size = gst_asf_demux_get_uint16 (&data, &size);
2342           chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2343           data_size = gst_asf_demux_get_uint16 (&data, &size);
2344           silence_data = gst_asf_demux_get_uint8 (&data, &size);
2346           /* FIXME: shouldn't this be per-stream? */
2347           demux->span = span;
2349           GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2350               packet_size, chunk_size, data_size, span, silence_data);
2352           if (demux->span > 1) {
2353             if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2354               /* Disable descrambling */
2355               demux->span = 0;
2356             } else {
2357               /* FIXME: this else branch was added for
2358                * weird_al_yankovic - the saga begins.asf */
2359               demux->ds_packet_size = packet_size;
2360               demux->ds_chunk_size = chunk_size;
2361             }
2362           } else {
2363             /* Descambling is enabled */
2364             demux->ds_packet_size = packet_size;
2365             demux->ds_chunk_size = chunk_size;
2366           }
2367 #if 0
2368           /* Now skip the rest of the silence data */
2369           if (data_size > 1)
2370             gst_bytestream_flush (demux->bs, data_size - 1);
2371 #else
2372           /* FIXME: CHECKME. And why -1? */
2373           if (data_size > 1) {
2374             if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2375               goto not_enough_data;
2376             }
2377           }
2378 #endif
2379           break;
2380         }
2381         case ASF_CORRECTION_OFF:{
2382           GST_INFO ("Error correction off");
2383           if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2384             goto not_enough_data;
2385           break;
2386         }
2387         default:
2388           GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2389               ("Audio stream using unknown error correction"));
2390           return NULL;
2391       }
2393       break;
2394     }
2396     case ASF_STREAM_VIDEO:{
2397       asf_stream_video_format video_format_object;
2398       asf_stream_video video_object;
2399       guint16 vsize;
2401       if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
2402         goto not_enough_data;
2404       vsize = video_object.size - 40;   /* Byte order gets offset by single byte */
2406       GST_INFO ("object is a video stream with %u bytes of "
2407           "additional data", vsize);
2409       if (!gst_asf_demux_get_stream_video_format (&video_format_object,
2410               &data, &size)) {
2411         goto not_enough_data;
2412       }
2414       gst_asf_demux_add_video_stream (demux, &video_format_object, stream_id,
2415           &data, &size);
2417       break;
2418     }
2420     default:
2421       GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
2422           stream_id);
2423       break;
2424   }
2426   return gst_asf_demux_get_stream (demux, stream_id);
2428 not_enough_data:
2429   {
2430     GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
2431     /* we'll error out later if we found no streams */
2432     return NULL;
2433   }
2436 static const gchar *
2437 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
2439   const struct
2440   {
2441     const gchar *asf_name;
2442     const gchar *gst_name;
2443   } tags[] = {
2444     {
2445     "WM/Genre", GST_TAG_GENRE}, {
2446     "WM/AlbumTitle", GST_TAG_ALBUM}, {
2447     "WM/AlbumArtist", GST_TAG_ARTIST}, {
2448     "WM/Picture", GST_TAG_IMAGE}, {
2449     "WM/Track", GST_TAG_TRACK_NUMBER}, {
2450     "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
2451     "WM/Year", GST_TAG_DATE}
2452     /* { "WM/Composer", GST_TAG_COMPOSER } */
2453   };
2454   gsize out;
2455   guint i;
2457   if (name_utf8 == NULL) {
2458     GST_WARNING ("Failed to convert name to UTF8, skipping");
2459     return NULL;
2460   }
2462   out = strlen (name_utf8);
2464   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
2465     if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
2466       GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
2467       return tags[i].gst_name;
2468     }
2469   }
2471   return NULL;
2474 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
2475 static void
2476 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
2478   GstTagList *t;
2480   GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
2482   if (taglist == NULL)
2483     return;
2485   if (gst_tag_list_is_empty (taglist)) {
2486     gst_tag_list_free (taglist);
2487     return;
2488   }
2490   t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
2491   if (demux->taglist)
2492     gst_tag_list_free (demux->taglist);
2493   gst_tag_list_free (taglist);
2494   demux->taglist = t;
2495   GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
2498 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING  0
2499 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY      1
2500 #define ASF_DEMUX_DATA_TYPE_DWORD           3
2502 static void
2503 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
2504     guint tag_data_len)
2506   GstByteReader r;
2507   const guint8 *img_data = NULL;
2508   guint32 img_data_len = 0;
2509   guint8 pic_type = 0;
2511   gst_byte_reader_init (&r, tag_data, tag_data_len);
2513   /* skip mime type string (we don't trust it and do our own typefinding),
2514    * and also skip the description string, since we don't use it */
2515   if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
2516       !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
2517       !gst_byte_reader_skip_string_utf16 (&r) ||
2518       !gst_byte_reader_skip_string_utf16 (&r) ||
2519       !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
2520     goto not_enough_data;
2521   }
2524   if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
2525     GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
2527   return;
2529 not_enough_data:
2530   {
2531     GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
2532     GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
2533     return;
2534   }
2537 /* Extended Content Description Object */
2538 static GstFlowReturn
2539 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
2540     guint64 size)
2542   /* Other known (and unused) 'text/unicode' metadata available :
2543    *
2544    *   WM/Lyrics =
2545    *   WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
2546    *   WMFSDKVersion = 9.00.00.2980
2547    *   WMFSDKNeeded = 0.0.0.0000
2548    *   WM/UniqueFileIdentifier = AMGa_id=R    15334;AMGp_id=P     5149;AMGt_id=T  2324984
2549    *   WM/Publisher = 4AD
2550    *   WM/Provider = AMG
2551    *   WM/ProviderRating = 8
2552    *   WM/ProviderStyle = Rock (similar to WM/Genre)
2553    *   WM/GenreID (similar to WM/Genre)
2554    *   WM/TrackNumber (same as WM/Track but as a string)
2555    *
2556    * Other known (and unused) 'non-text' metadata available :
2557    *
2558    *   WM/EncodingTime
2559    *   WM/MCDI
2560    *   IsVBR
2561    *
2562    * We might want to read WM/TrackNumber and use atoi() if we don't have
2563    * WM/Track
2564    */
2566   GstTagList *taglist;
2567   guint16 blockcount, i;
2569   GST_INFO_OBJECT (demux, "object is an extended content description");
2571   taglist = gst_tag_list_new ();
2573   /* Content Descriptor Count */
2574   if (size < 2)
2575     goto not_enough_data;
2577   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2579   for (i = 1; i <= blockcount; ++i) {
2580     const gchar *gst_tag_name;
2581     guint16 datatype;
2582     guint16 value_len;
2583     guint16 name_len;
2584     GValue tag_value = { 0, };
2585     gsize in, out;
2586     gchar *name;
2587     gchar *name_utf8 = NULL;
2588     gchar *value;
2590     /* Descriptor */
2591     if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
2592       goto not_enough_data;
2594     if (size < 2) {
2595       g_free (name);
2596       goto not_enough_data;
2597     }
2598     /* Descriptor Value Data Type */
2599     datatype = gst_asf_demux_get_uint16 (&data, &size);
2601     /* Descriptor Value (not really a string, but same thing reading-wise) */
2602     if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
2603       g_free (name);
2604       goto not_enough_data;
2605     }
2607     name_utf8 =
2608         g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
2610     if (name_utf8 != NULL) {
2611       GST_DEBUG ("Found tag/metadata %s", name_utf8);
2613       gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
2614       GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
2616       switch (datatype) {
2617         case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
2618           gchar *value_utf8;
2620           value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
2621               &in, &out, NULL);
2623           /* get rid of tags with empty value */
2624           if (value_utf8 != NULL && *value_utf8 != '\0') {
2625             GST_DEBUG ("string value %s", value_utf8);
2627             value_utf8[out] = '\0';
2629             if (gst_tag_name != NULL) {
2630               if (strcmp (gst_tag_name, GST_TAG_DATE) == 0) {
2631                 guint year = atoi (value_utf8);
2633                 if (year > 0) {
2634                   GDate *date = g_date_new_dmy (1, 1, year);
2636                   g_value_init (&tag_value, GST_TYPE_DATE);
2637                   gst_value_set_date (&tag_value, date);
2638                   g_date_free (date);
2639                 }
2640               } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
2641                 guint id3v1_genre_id;
2642                 const gchar *genre_str;
2644                 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
2645                     ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
2646                   GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
2647                   g_free (value_utf8);
2648                   value_utf8 = g_strdup (genre_str);
2649                 }
2650               } else {
2651                 GType tag_type;
2653                 /* convert tag from string to other type if required */
2654                 tag_type = gst_tag_get_type (gst_tag_name);
2655                 g_value_init (&tag_value, tag_type);
2656                 if (!gst_value_deserialize (&tag_value, value_utf8)) {
2657                   GValue from_val = { 0, };
2659                   g_value_init (&from_val, G_TYPE_STRING);
2660                   g_value_set_string (&from_val, value_utf8);
2661                   if (!g_value_transform (&from_val, &tag_value)) {
2662                     GST_WARNING_OBJECT (demux,
2663                         "Could not transform string tag to " "%s tag type %s",
2664                         gst_tag_name, g_type_name (tag_type));
2665                     g_value_unset (&tag_value);
2666                   }
2667                   g_value_unset (&from_val);
2668                 }
2669               }
2670             } else {
2671               /* metadata ! */
2672               GST_DEBUG ("Setting metadata");
2673               g_value_init (&tag_value, G_TYPE_STRING);
2674               g_value_set_string (&tag_value, value_utf8);
2675             }
2676           } else if (value_utf8 == NULL) {
2677             GST_WARNING ("Failed to convert string value to UTF8, skipping");
2678           } else {
2679             GST_DEBUG ("Skipping empty string value for %s",
2680                 GST_STR_NULL (gst_tag_name));
2681           }
2682           g_free (value_utf8);
2683           break;
2684         }
2685         case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
2686           if (gst_tag_name) {
2687             if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
2688               GST_FIXME ("Unhandled byte array tag %s",
2689                   GST_STR_NULL (gst_tag_name));
2690               break;
2691             } else {
2692               asf_demux_parse_picture_tag (taglist, (guint8 *) value,
2693                   value_len);
2694             }
2695           }
2696           break;
2697         }
2698         case ASF_DEMUX_DATA_TYPE_DWORD:{
2699           guint uint_val = GST_READ_UINT32_LE (value);
2701           /* this is the track number */
2702           g_value_init (&tag_value, G_TYPE_UINT);
2704           /* WM/Track counts from 0 */
2705           if (!strcmp (name_utf8, "WM/Track"))
2706             ++uint_val;
2708           g_value_set_uint (&tag_value, uint_val);
2709           break;
2710         }
2711         default:{
2712           GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
2713           break;
2714         }
2715       }
2717       if (G_IS_VALUE (&tag_value)) {
2718         if (gst_tag_name) {
2719           GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
2721           /* WM/TrackNumber is more reliable than WM/Track, since the latter
2722            * is supposed to have a 0 base but is often wrongly written to start
2723            * from 1 as well, so prefer WM/TrackNumber when we have it: either
2724            * replace the value added earlier from WM/Track or put it first in
2725            * the list, so that it will get picked up by _get_uint() */
2726           if (strcmp (name_utf8, "WM/TrackNumber") == 0)
2727             merge_mode = GST_TAG_MERGE_REPLACE;
2729           gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
2730               &tag_value, NULL);
2731         } else {
2732           GST_DEBUG ("Setting global metadata %s", name_utf8);
2733           gst_structure_set_value (demux->global_metadata, name_utf8,
2734               &tag_value);
2735         }
2737         g_value_unset (&tag_value);
2738       }
2739     }
2741     g_free (name);
2742     g_free (value);
2743     g_free (name_utf8);
2744   }
2746   gst_asf_demux_add_global_tags (demux, taglist);
2748   return GST_FLOW_OK;
2750   /* Errors */
2751 not_enough_data:
2752   {
2753     GST_WARNING ("Unexpected end of data parsing ext content desc object");
2754     gst_tag_list_free (taglist);
2755     return GST_FLOW_OK;         /* not really fatal */
2756   }
2759 static GstStructure *
2760 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
2762   gchar sname[32];
2763   guint i;
2765   g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
2767   for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
2768     GstStructure *s;
2770     s = gst_caps_get_structure (demux->metadata, i);
2771     if (gst_structure_has_name (s, sname))
2772       return s;
2773   }
2775   gst_caps_append_structure (demux->metadata, gst_structure_empty_new (sname));
2777   /* try lookup again; demux->metadata took ownership of the structure, so we
2778    * can't really make any assumptions about what happened to it, so we can't
2779    * just return it directly after appending it */
2780   return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2783 static GstFlowReturn
2784 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
2785     guint64 size)
2787   guint16 blockcount, i;
2789   GST_INFO_OBJECT (demux, "object is a metadata object");
2791   /* Content Descriptor Count */
2792   if (size < 2)
2793     goto not_enough_data;
2795   blockcount = gst_asf_demux_get_uint16 (&data, &size);
2797   for (i = 0; i < blockcount; ++i) {
2798     GstStructure *s;
2799     guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
2800     guint32 data_len, ival;
2801     gchar *name_utf8;
2803     if (size < (2 + 2 + 2 + 2 + 4))
2804       goto not_enough_data;
2806     lang_idx = gst_asf_demux_get_uint16 (&data, &size);
2807     stream_num = gst_asf_demux_get_uint16 (&data, &size);
2808     name_len = gst_asf_demux_get_uint16 (&data, &size);
2809     data_type = gst_asf_demux_get_uint16 (&data, &size);
2810     data_len = gst_asf_demux_get_uint32 (&data, &size);
2812     if (size < name_len + data_len)
2813       goto not_enough_data;
2815     /* convert name to UTF-8 */
2816     name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
2817         NULL, NULL, NULL);
2818     gst_asf_demux_skip_bytes (name_len, &data, &size);
2820     if (name_utf8 == NULL) {
2821       GST_WARNING ("Failed to convert value name to UTF8, skipping");
2822       gst_asf_demux_skip_bytes (data_len, &data, &size);
2823       continue;
2824     }
2826     if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
2827       gst_asf_demux_skip_bytes (data_len, &data, &size);
2828       g_free (name_utf8);
2829       continue;
2830     }
2832     /* read DWORD */
2833     if (size < 4) {
2834       g_free (name_utf8);
2835       goto not_enough_data;
2836     }
2838     ival = gst_asf_demux_get_uint32 (&data, &size);
2840     /* skip anything else there may be, just in case */
2841     gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
2843     s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
2844     gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
2845     g_free (name_utf8);
2846   }
2848   GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
2849   return GST_FLOW_OK;
2851   /* Errors */
2852 not_enough_data:
2853   {
2854     GST_WARNING ("Unexpected end of data parsing metadata object");
2855     return GST_FLOW_OK;         /* not really fatal */
2856   }
2859 static GstFlowReturn
2860 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
2862   GstFlowReturn ret = GST_FLOW_OK;
2863   guint32 i, num_objects;
2864   guint8 unknown G_GNUC_UNUSED;
2866   /* Get the rest of the header's header */
2867   if (size < (4 + 1 + 1))
2868     goto not_enough_data;
2870   num_objects = gst_asf_demux_get_uint32 (&data, &size);
2871   unknown = gst_asf_demux_get_uint8 (&data, &size);
2872   unknown = gst_asf_demux_get_uint8 (&data, &size);
2874   GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
2876   /* Loop through the header's objects, processing those */
2877   for (i = 0; i < num_objects; ++i) {
2878     GST_INFO_OBJECT (demux, "reading header part %u", i);
2879     ret = gst_asf_demux_process_object (demux, &data, &size);
2880     if (ret != GST_FLOW_OK) {
2881       GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
2882       break;
2883     }
2884   }
2886   return ret;
2888 not_enough_data:
2889   {
2890     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2891         ("short read parsing HEADER object"));
2892     return GST_FLOW_ERROR;
2893   }
2896 static GstFlowReturn
2897 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
2899   guint64 creation_time G_GNUC_UNUSED;
2900   guint64 file_size G_GNUC_UNUSED;
2901   guint64 send_time G_GNUC_UNUSED;
2902   guint64 packets_count, play_time, preroll;
2903   guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
2905   if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
2906     goto not_enough_data;
2908   gst_asf_demux_skip_bytes (16, &data, &size);  /* skip GUID */
2909   file_size = gst_asf_demux_get_uint64 (&data, &size);
2910   creation_time = gst_asf_demux_get_uint64 (&data, &size);
2911   packets_count = gst_asf_demux_get_uint64 (&data, &size);
2912   play_time = gst_asf_demux_get_uint64 (&data, &size);
2913   send_time = gst_asf_demux_get_uint64 (&data, &size);
2914   preroll = gst_asf_demux_get_uint64 (&data, &size);
2915   flags = gst_asf_demux_get_uint32 (&data, &size);
2916   min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2917   max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
2918   min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
2920   demux->broadcast = ! !(flags & 0x01);
2921   demux->seekable = ! !(flags & 0x02);
2923   GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
2924   GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
2925   GST_DEBUG_OBJECT (demux, "flags::seekable  = %d", demux->seekable);
2927   if (demux->broadcast) {
2928     /* these fields are invalid if the broadcast flag is set */
2929     play_time = 0;
2930     file_size = 0;
2931   }
2933   if (min_pktsize != max_pktsize)
2934     goto non_fixed_packet_size;
2936   demux->packet_size = max_pktsize;
2938   /* FIXME: do we need send_time as well? what is it? */
2939   if ((play_time * 100) >= (preroll * GST_MSECOND))
2940     demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
2941   else
2942     demux->play_time = 0;
2944   demux->preroll = preroll * GST_MSECOND;
2946   /* initial latency */
2947   demux->latency = demux->preroll;
2949   if (demux->play_time == 0)
2950     demux->seekable = FALSE;
2952   GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
2953       GST_TIME_ARGS (demux->play_time));
2954   GST_DEBUG_OBJECT (demux, "preroll   %" GST_TIME_FORMAT,
2955       GST_TIME_ARGS (demux->preroll));
2957   if (demux->play_time > 0) {
2958     gst_segment_set_duration (&demux->segment, GST_FORMAT_TIME,
2959         demux->play_time);
2960   }
2962   GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
2963       packets_count);
2964   GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
2966   return GST_FLOW_OK;
2968 /* ERRORS */
2969 non_fixed_packet_size:
2970   {
2971     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2972         ("packet size must be fixed"));
2973     return GST_FLOW_ERROR;
2974   }
2975 not_enough_data:
2976   {
2977     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2978         ("short read parsing FILE object"));
2979     return GST_FLOW_ERROR;
2980   }
2983 /* Content Description Object */
2984 static GstFlowReturn
2985 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
2987   struct
2988   {
2989     const gchar *gst_tag;
2990     guint16 val_length;
2991     gchar *val_utf8;
2992   } tags[5] = {
2993     {
2994     GST_TAG_TITLE, 0, NULL}, {
2995     GST_TAG_ARTIST, 0, NULL}, {
2996     GST_TAG_COPYRIGHT, 0, NULL}, {
2997     GST_TAG_DESCRIPTION, 0, NULL}, {
2998     GST_TAG_COMMENT, 0, NULL}
2999   };
3000   GstTagList *taglist;
3001   GValue value = { 0 };
3002   gsize in, out;
3003   gint i = -1;
3005   GST_INFO_OBJECT (demux, "object is a comment");
3007   if (size < (2 + 2 + 2 + 2 + 2))
3008     goto not_enough_data;
3010   tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3011   tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3012   tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3013   tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3014   tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3016   GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3017       "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3018       tags[2].val_length, tags[3].val_length, tags[4].val_length);
3020   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3021     if (size < tags[i].val_length)
3022       goto not_enough_data;
3024     /* might be just '/0', '/0'... */
3025     if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3026       /* convert to UTF-8 */
3027       tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3028           "UTF-8", "UTF-16LE", &in, &out, NULL);
3029     }
3030     gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3031   }
3033   /* parse metadata into taglist */
3034   taglist = gst_tag_list_new ();
3035   g_value_init (&value, G_TYPE_STRING);
3036   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3037     if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3038       g_value_set_string (&value, tags[i].val_utf8);
3039       gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3040           tags[i].gst_tag, &value, NULL);
3041     }
3042   }
3043   g_value_unset (&value);
3045   gst_asf_demux_add_global_tags (demux, taglist);
3047   for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3048     g_free (tags[i].val_utf8);
3050   return GST_FLOW_OK;
3052 not_enough_data:
3053   {
3054     GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3055         "comment tag section %d, skipping comment object", i);
3056     for (i = 0; i < G_N_ELEMENTS (tags); i++)
3057       g_free (tags[i].val_utf8);
3058     return GST_FLOW_OK;         /* not really fatal */
3059   }
3062 static GstFlowReturn
3063 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3064     guint64 size)
3066   guint16 num_streams, i;
3067   AsfStream *stream;
3069   if (size < 2)
3070     goto not_enough_data;
3072   num_streams = gst_asf_demux_get_uint16 (&data, &size);
3074   GST_INFO ("object is a bitrate properties object with %u streams",
3075       num_streams);
3077   if (size < (num_streams * (2 + 4)))
3078     goto not_enough_data;
3080   for (i = 0; i < num_streams; ++i) {
3081     guint32 bitrate;
3082     guint16 stream_id;
3084     stream_id = gst_asf_demux_get_uint16 (&data, &size);
3085     bitrate = gst_asf_demux_get_uint32 (&data, &size);
3087     if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3088       GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3089       stream = gst_asf_demux_get_stream (demux, stream_id);
3090       if (stream) {
3091         if (stream->pending_tags == NULL)
3092           stream->pending_tags = gst_tag_list_new ();
3093         gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3094             GST_TAG_BITRATE, bitrate, NULL);
3095       } else {
3096         GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3097       }
3098     } else {
3099       GST_WARNING ("stream id %u is too large", stream_id);
3100     }
3101   }
3103   return GST_FLOW_OK;
3105 not_enough_data:
3106   {
3107     GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3108     return GST_FLOW_OK;         /* not really fatal */
3109   }
3112 static GstFlowReturn
3113 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3114     guint64 size)
3116   GstFlowReturn ret = GST_FLOW_OK;
3117   guint64 hdr_size;
3119   /* Get the rest of the header's header */
3120   if (size < (16 + 2 + 4))
3121     goto not_enough_data;
3123   /* skip GUID and two other bytes */
3124   gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3125   hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3127   GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3129   /* FIXME: does data_size include the rest of the header that we have read? */
3130   if (hdr_size > size)
3131     goto not_enough_data;
3133   while (hdr_size > 0) {
3134     ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3135     if (ret != GST_FLOW_OK)
3136       break;
3137   }
3139   return ret;
3141 not_enough_data:
3142   {
3143     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3144         ("short read parsing extended header object"));
3145     return GST_FLOW_ERROR;
3146   }
3149 static GstFlowReturn
3150 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3151     guint64 size)
3153   guint i;
3155   if (size < 2)
3156     goto not_enough_data;
3158   if (demux->languages) {
3159     GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3160     g_strfreev (demux->languages);
3161     demux->languages = NULL;
3162     demux->num_languages = 0;
3163   }
3165   demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3166   GST_LOG ("%u languages:", demux->num_languages);
3168   demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3169   for (i = 0; i < demux->num_languages; ++i) {
3170     guint8 len, *lang_data = NULL;
3172     if (size < 1)
3173       goto not_enough_data;
3174     len = gst_asf_demux_get_uint8 (&data, &size);
3175     if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3176       gchar *utf8;
3178       utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3179           NULL, NULL);
3181       /* truncate "en-us" etc. to just "en" */
3182       if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3183         utf8[2] = '\0';
3184       }
3185       GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3186       demux->languages[i] = utf8;
3187       g_free (lang_data);
3188     } else {
3189       goto not_enough_data;
3190     }
3191   }
3193   return GST_FLOW_OK;
3195 not_enough_data:
3196   {
3197     GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3198     g_free (demux->languages);
3199     demux->languages = NULL;
3200     return GST_FLOW_OK;         /* not fatal */
3201   }
3204 static GstFlowReturn
3205 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3206     guint64 size)
3208   GstClockTime interval;
3209   guint32 count, i;
3211   if (size < (16 + 8 + 4 + 4))
3212     goto not_enough_data;
3214   /* skip file id */
3215   gst_asf_demux_skip_bytes (16, &data, &size);
3216   interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3217   gst_asf_demux_skip_bytes (4, &data, &size);
3218   count = gst_asf_demux_get_uint32 (&data, &size);
3219   if (count > 0) {
3220     demux->sidx_interval = interval;
3221     demux->sidx_num_entries = count;
3222     g_free (demux->sidx_entries);
3223     demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3225     for (i = 0; i < count; ++i) {
3226       if (G_UNLIKELY (size <= 6))
3227         break;
3228       demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3229       demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3230       GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u  count : %2d",
3231           GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3232           demux->sidx_entries[i].count);
3233     }
3234   } else {
3235     GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3236   }
3238   return GST_FLOW_OK;
3240 not_enough_data:
3241   {
3242     GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3243     return GST_FLOW_OK;         /* not fatal */
3244   }
3247 static GstFlowReturn
3248 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3249     guint8 * data, guint64 size)
3251   ASFGuid guid;
3252   guint16 num, i;
3253   guint8 *mes;
3255   if (size < 16 + 2 + (2 * 2))
3256     goto not_enough_data;
3258   gst_asf_demux_get_guid (&guid, &data, &size);
3259   num = gst_asf_demux_get_uint16 (&data, &size);
3261   if (num < 2) {
3262     GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3263     return GST_FLOW_OK;
3264   }
3266   if (size < (num * sizeof (guint16)))
3267     goto not_enough_data;
3269   /* read mutually exclusive stream numbers */
3270   mes = g_new (guint8, num + 1);
3271   for (i = 0; i < num; ++i) {
3272     mes[i] = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3273     GST_LOG_OBJECT (demux, "mutually exclusive: stream #%d", mes[i]);
3274   }
3276   /* add terminator so we can easily get the count or know when to stop */
3277   mes[i] = (guint8) - 1;
3279   demux->mut_ex_streams = g_slist_append (demux->mut_ex_streams, mes);
3281   return GST_FLOW_OK;
3283   /* Errors */
3284 not_enough_data:
3285   {
3286     GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3287     return GST_FLOW_OK;         /* not absolutely fatal */
3288   }
3291 static GstFlowReturn
3292 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3293     guint64 size)
3295   AsfStreamExtProps esp;
3296   AsfStream *stream = NULL;
3297   AsfObject stream_obj;
3298   guint16 stream_name_count;
3299   guint16 num_payload_ext;
3300   guint64 len;
3301   guint8 *stream_obj_data = NULL;
3302   guint8 *data_start;
3303   guint obj_size;
3304   guint i, stream_num;
3306   data_start = data;
3307   obj_size = (guint) size;
3309   if (size < 64)
3310     goto not_enough_data;
3312   esp.valid = TRUE;
3313   esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3314   esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3315   esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3316   esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3317   esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3318   esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3319   esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3320   esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3321   esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3322   esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3323   stream_num = gst_asf_demux_get_uint16 (&data, &size);
3324   esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3325   esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3326   stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
3327   num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
3329   GST_INFO ("start_time             = %" GST_TIME_FORMAT,
3330       GST_TIME_ARGS (esp.start_time));
3331   GST_INFO ("end_time               = %" GST_TIME_FORMAT,
3332       GST_TIME_ARGS (esp.end_time));
3333   GST_INFO ("flags                  = %08x", esp.flags);
3334   GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
3335       GST_TIME_ARGS (esp.avg_time_per_frame * 100));
3336   GST_INFO ("stream number          = %u", stream_num);
3337   GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
3338       (esp.lang_idx < demux->num_languages) ?
3339       GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
3340   GST_INFO ("stream name count      = %u", stream_name_count);
3342   /* read stream names */
3343   for (i = 0; i < stream_name_count; ++i) {
3344     guint16 stream_lang_idx G_GNUC_UNUSED;
3345     gchar *stream_name = NULL;
3347     if (size < 2)
3348       goto not_enough_data;
3349     stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3350     if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
3351       goto not_enough_data;
3352     GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
3353     g_free (stream_name);       /* TODO: store names in struct */
3354   }
3356   /* read payload extension systems stuff */
3357   GST_LOG ("payload extension systems count = %u", num_payload_ext);
3359   if (num_payload_ext > 0)
3360     esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
3361   else
3362     esp.payload_extensions = NULL;
3364   for (i = 0; i < num_payload_ext; ++i) {
3365     AsfPayloadExtension ext;
3366     ASFGuid ext_guid;
3367     guint32 sys_info_len;
3369     if (size < 16 + 2 + 4)
3370       goto not_enough_data;
3372     gst_asf_demux_get_guid (&ext_guid, &data, &size);
3373     ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
3374     ext.len = gst_asf_demux_get_uint16 (&data, &size);
3376     sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
3377     GST_LOG ("payload systems info len = %u", sys_info_len);
3378     if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
3379       goto not_enough_data;
3381     esp.payload_extensions[i] = ext;
3382   }
3384   GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
3386   /* there might be an optional STREAM_INFO object here now; if not, we
3387    * should have parsed the corresponding stream info object already (since
3388    * we are parsing the extended stream properties objects delayed) */
3389   if (size == 0) {
3390     stream = gst_asf_demux_get_stream (demux, stream_num);
3391     goto done;
3392   }
3394   /* get size of the stream object */
3395   if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
3396     goto not_enough_data;
3398   if (stream_obj.id != ASF_OBJ_STREAM)
3399     goto expected_stream_object;
3401   if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
3402       stream_obj.size > (10 * 1024 * 1024))
3403     goto not_enough_data;
3405   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
3407   /* process this stream object later after all the other 'normal' ones
3408    * have been processed (since the others are more important/non-hidden) */
3409   len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
3410   if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
3411     goto not_enough_data;
3413   /* parse stream object */
3414   stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
3415   g_free (stream_obj_data);
3417 done:
3419   if (stream) {
3420     stream->ext_props = esp;
3422     /* try to set the framerate */
3423     if (stream->is_video && stream->caps) {
3424       GValue framerate = { 0 };
3425       GstStructure *s;
3426       gint num, denom;
3428       g_value_init (&framerate, GST_TYPE_FRACTION);
3430       num = GST_SECOND / 100;
3431       denom = esp.avg_time_per_frame;
3432       if (denom == 0) {
3433         /* avoid division by 0, assume 25/1 framerate */
3434         denom = GST_SECOND / 2500;
3435       }
3437       gst_value_set_fraction (&framerate, num, denom);
3439       stream->caps = gst_caps_make_writable (stream->caps);
3440       s = gst_caps_get_structure (stream->caps, 0);
3441       gst_structure_set_value (s, "framerate", &framerate);
3442       g_value_unset (&framerate);
3443       GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
3444           num, denom, ((gdouble) num) / denom);
3445     }
3447     /* add language info now if we have it */
3448     if (stream->ext_props.lang_idx < demux->num_languages) {
3449       if (stream->pending_tags == NULL)
3450         stream->pending_tags = gst_tag_list_new ();
3451       GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
3452           demux->languages[stream->ext_props.lang_idx]);
3453       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
3454           GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
3455           NULL);
3456     }
3457   } else {
3458     GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
3459   }
3461   return GST_FLOW_OK;
3463   /* Errors */
3464 not_enough_data:
3465   {
3466     GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
3467     return GST_FLOW_OK;         /* not absolutely fatal */
3468   }
3469 expected_stream_object:
3470   {
3471     GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
3472         "object: expected embedded stream object, but got %s object instead!",
3473         gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
3474     return GST_FLOW_OK;         /* not absolutely fatal */
3475   }
3478 static const gchar *