asfdemux: Don't modify segment values on accurate seeks
[platform/upstream/gst-plugins-ugly.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., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
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  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <gst/gstutils.h>
36 #include <gst/base/gstbytereader.h>
37 #include <gst/base/gsttypefindhelper.h>
38 #include <gst/riff/riff-media.h>
39 #include <gst/tag/tag.h>
40 #include <gst/gst-i18n-plugin.h>
41 #include <gst/video/video.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include "gstasfdemux.h"
47 #include "asfheaders.h"
48 #include "asfpacket.h"
49
50 static GstStaticPadTemplate gst_asf_demux_sink_template =
51 GST_STATIC_PAD_TEMPLATE ("sink",
52     GST_PAD_SINK,
53     GST_PAD_ALWAYS,
54     GST_STATIC_CAPS ("video/x-ms-asf")
55     );
56
57 static GstStaticPadTemplate audio_src_template =
58 GST_STATIC_PAD_TEMPLATE ("audio_%u",
59     GST_PAD_SRC,
60     GST_PAD_SOMETIMES,
61     GST_STATIC_CAPS_ANY);
62
63 static GstStaticPadTemplate video_src_template =
64 GST_STATIC_PAD_TEMPLATE ("video_%u",
65     GST_PAD_SRC,
66     GST_PAD_SOMETIMES,
67     GST_STATIC_CAPS_ANY);
68
69 /* size of an ASF object header, ie. GUID (16 bytes) + object size (8 bytes) */
70 #define ASF_OBJECT_HEADER_SIZE  (16+8)
71
72 /* FIXME: get rid of this */
73 /* abuse this GstFlowReturn enum for internal usage */
74 #define ASF_FLOW_NEED_MORE_DATA  99
75
76 #define gst_asf_get_flow_name(flow)    \
77   (flow == ASF_FLOW_NEED_MORE_DATA) ?  \
78   "need-more-data" : gst_flow_get_name (flow)
79
80 GST_DEBUG_CATEGORY (asfdemux_dbg);
81
82 static GstStateChangeReturn gst_asf_demux_change_state (GstElement * element,
83     GstStateChange transition);
84 static gboolean gst_asf_demux_element_send_event (GstElement * element,
85     GstEvent * event);
86 static gboolean gst_asf_demux_send_event_unlocked (GstASFDemux * demux,
87     GstEvent * event);
88 static gboolean gst_asf_demux_handle_src_query (GstPad * pad,
89     GstObject * parent, GstQuery * query);
90 static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstObject * parent,
91     GstBuffer * buf);
92 static gboolean gst_asf_demux_sink_event (GstPad * pad, GstObject * parent,
93     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, GstObject * parent);
97 static gboolean gst_asf_demux_activate_mode (GstPad * sinkpad,
98     GstObject * parent, GstPadMode mode, 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     GstFlowReturn * pflow);
104 static void gst_asf_demux_pull_indices (GstASFDemux * demux);
105 static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
106 static gboolean
107 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
108 static void gst_asf_demux_descramble_buffer (GstASFDemux * demux,
109     AsfStream * stream, GstBuffer ** p_buffer);
110 static void gst_asf_demux_activate_stream (GstASFDemux * demux,
111     AsfStream * stream);
112 static GstStructure *gst_asf_demux_get_metadata_for_stream (GstASFDemux * d,
113     guint stream_num);
114 static GstFlowReturn gst_asf_demux_push_complete_payloads (GstASFDemux * demux,
115     gboolean force);
116
117 #define gst_asf_demux_parent_class parent_class
118 G_DEFINE_TYPE (GstASFDemux, gst_asf_demux, GST_TYPE_ELEMENT);
119
120 static void
121 gst_asf_demux_class_init (GstASFDemuxClass * klass)
122 {
123   GstElementClass *gstelement_class;
124
125   gstelement_class = (GstElementClass *) klass;
126
127   gst_element_class_set_static_metadata (gstelement_class, "ASF Demuxer",
128       "Codec/Demuxer",
129       "Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
130
131   gst_element_class_add_pad_template (gstelement_class,
132       gst_static_pad_template_get (&audio_src_template));
133   gst_element_class_add_pad_template (gstelement_class,
134       gst_static_pad_template_get (&video_src_template));
135   gst_element_class_add_pad_template (gstelement_class,
136       gst_static_pad_template_get (&gst_asf_demux_sink_template));
137
138   gstelement_class->change_state =
139       GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
140   gstelement_class->send_event =
141       GST_DEBUG_FUNCPTR (gst_asf_demux_element_send_event);
142 }
143
144 static void
145 gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream)
146 {
147   gst_caps_replace (&stream->caps, NULL);
148   if (stream->pending_tags) {
149     gst_tag_list_unref (stream->pending_tags);
150     stream->pending_tags = NULL;
151   }
152   if (stream->streamheader) {
153     gst_buffer_unref (stream->streamheader);
154     stream->streamheader = NULL;
155   }
156   if (stream->pad) {
157     if (stream->active) {
158       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
159       gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
160     } else
161       gst_object_unref (stream->pad);
162     stream->pad = NULL;
163   }
164
165   if (stream->payloads) {
166     while (stream->payloads->len > 0) {
167       AsfPayload *payload;
168       guint last;
169
170       last = stream->payloads->len - 1;
171       payload = &g_array_index (stream->payloads, AsfPayload, last);
172       gst_buffer_replace (&payload->buf, NULL);
173       g_array_remove_index (stream->payloads, last);
174     }
175     g_array_free (stream->payloads, TRUE);
176     stream->payloads = NULL;
177   }
178
179   if (stream->payloads_rev) {
180     while (stream->payloads_rev->len > 0) {
181       AsfPayload *payload;
182       guint last;
183
184       last = stream->payloads_rev->len - 1;
185       payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
186       gst_buffer_replace (&payload->buf, NULL);
187       g_array_remove_index (stream->payloads_rev, last);
188     }
189     g_array_free (stream->payloads_rev, TRUE);
190     stream->payloads_rev = NULL;
191   }
192
193   if (stream->ext_props.valid) {
194     g_free (stream->ext_props.payload_extensions);
195     stream->ext_props.payload_extensions = NULL;
196   }
197 }
198
199 static void
200 gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset)
201 {
202   GST_LOG_OBJECT (demux, "resetting");
203
204   gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED);
205   demux->segment_running = FALSE;
206   if (demux->adapter && !chain_reset) {
207     gst_adapter_clear (demux->adapter);
208     g_object_unref (demux->adapter);
209     demux->adapter = NULL;
210   }
211   if (demux->taglist) {
212     gst_tag_list_unref (demux->taglist);
213     demux->taglist = NULL;
214   }
215   if (demux->metadata) {
216     gst_caps_unref (demux->metadata);
217     demux->metadata = NULL;
218   }
219   if (demux->global_metadata) {
220     gst_structure_free (demux->global_metadata);
221     demux->global_metadata = NULL;
222   }
223   if (demux->mut_ex_streams) {
224     g_slist_free (demux->mut_ex_streams);
225     demux->mut_ex_streams = NULL;
226   }
227
228   demux->state = GST_ASF_DEMUX_STATE_HEADER;
229   g_free (demux->objpath);
230   demux->objpath = NULL;
231   g_strfreev (demux->languages);
232   demux->languages = NULL;
233   demux->num_languages = 0;
234   g_slist_foreach (demux->ext_stream_props, (GFunc) gst_mini_object_unref,
235       NULL);
236   g_slist_free (demux->ext_stream_props);
237   demux->ext_stream_props = NULL;
238
239   while (demux->old_num_streams > 0) {
240     gst_asf_demux_free_stream (demux,
241         &demux->old_stream[demux->old_num_streams - 1]);
242     --demux->old_num_streams;
243   }
244   memset (demux->old_stream, 0, sizeof (demux->old_stream));
245   demux->old_num_streams = 0;
246
247   /* when resetting for a new chained asf, we don't want to remove the pads
248    * before adding the new ones */
249   if (chain_reset) {
250     memcpy (demux->old_stream, demux->stream, sizeof (demux->stream));
251     demux->old_num_streams = demux->num_streams;
252     demux->num_streams = 0;
253   }
254
255   while (demux->num_streams > 0) {
256     gst_asf_demux_free_stream (demux, &demux->stream[demux->num_streams - 1]);
257     --demux->num_streams;
258   }
259   memset (demux->stream, 0, sizeof (demux->stream));
260   if (!chain_reset) {
261     /* do not remove those for not adding pads with same name */
262     demux->num_audio_streams = 0;
263     demux->num_video_streams = 0;
264     demux->have_group_id = FALSE;
265     demux->group_id = G_MAXUINT;
266   }
267   demux->num_streams = 0;
268   demux->activated_streams = FALSE;
269   demux->first_ts = GST_CLOCK_TIME_NONE;
270   demux->segment_ts = GST_CLOCK_TIME_NONE;
271   demux->in_gap = 0;
272   if (!chain_reset)
273     gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
274   demux->state = GST_ASF_DEMUX_STATE_HEADER;
275   demux->seekable = FALSE;
276   demux->broadcast = FALSE;
277   demux->sidx_interval = 0;
278   demux->sidx_num_entries = 0;
279   g_free (demux->sidx_entries);
280   demux->sidx_entries = NULL;
281
282   demux->speed_packets = 1;
283
284   demux->asf_3D_mode = GST_ASF_3D_NONE;
285
286   if (chain_reset) {
287     GST_LOG_OBJECT (demux, "Restarting");
288     gst_segment_init (&demux->segment, GST_FORMAT_TIME);
289     demux->need_newsegment = TRUE;
290     demux->segment_seqnum = 0;
291     demux->segment_running = FALSE;
292     demux->keyunit_sync = FALSE;
293     demux->accurate = FALSE;
294     demux->metadata = gst_caps_new_empty ();
295     demux->global_metadata = gst_structure_new_empty ("metadata");
296     demux->data_size = 0;
297     demux->data_offset = 0;
298     demux->index_offset = 0;
299   } else {
300     demux->base_offset = 0;
301   }
302
303   g_slist_free (demux->other_streams);
304   demux->other_streams = NULL;
305 }
306
307 static void
308 gst_asf_demux_init (GstASFDemux * demux)
309 {
310   demux->sinkpad =
311       gst_pad_new_from_static_template (&gst_asf_demux_sink_template, "sink");
312   gst_pad_set_chain_function (demux->sinkpad,
313       GST_DEBUG_FUNCPTR (gst_asf_demux_chain));
314   gst_pad_set_event_function (demux->sinkpad,
315       GST_DEBUG_FUNCPTR (gst_asf_demux_sink_event));
316   gst_pad_set_activate_function (demux->sinkpad,
317       GST_DEBUG_FUNCPTR (gst_asf_demux_activate));
318   gst_pad_set_activatemode_function (demux->sinkpad,
319       GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
320   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
321
322   /* set initial state */
323   gst_asf_demux_reset (demux, FALSE);
324 }
325
326 static gboolean
327 gst_asf_demux_activate (GstPad * sinkpad, GstObject * parent)
328 {
329   GstQuery *query;
330   gboolean pull_mode;
331
332   query = gst_query_new_scheduling ();
333
334   if (!gst_pad_peer_query (sinkpad, query)) {
335     gst_query_unref (query);
336     goto activate_push;
337   }
338
339   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
340       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
341   gst_query_unref (query);
342
343   if (!pull_mode)
344     goto activate_push;
345
346   GST_DEBUG_OBJECT (sinkpad, "activating pull");
347   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
348
349 activate_push:
350   {
351     GST_DEBUG_OBJECT (sinkpad, "activating push");
352     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
353   }
354 }
355
356 static gboolean
357 gst_asf_demux_activate_mode (GstPad * sinkpad, GstObject * parent,
358     GstPadMode mode, gboolean active)
359 {
360   gboolean res;
361   GstASFDemux *demux;
362
363   demux = GST_ASF_DEMUX (parent);
364
365   switch (mode) {
366     case GST_PAD_MODE_PUSH:
367       demux->state = GST_ASF_DEMUX_STATE_HEADER;
368       demux->streaming = TRUE;
369       res = TRUE;
370       break;
371     case GST_PAD_MODE_PULL:
372       if (active) {
373         demux->state = GST_ASF_DEMUX_STATE_HEADER;
374         demux->streaming = FALSE;
375
376         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_asf_demux_loop,
377             demux, NULL);
378       } else {
379         res = gst_pad_stop_task (sinkpad);
380       }
381       break;
382     default:
383       res = FALSE;
384       break;
385   }
386   return res;
387 }
388
389 static gboolean
390 gst_asf_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
391 {
392   GstASFDemux *demux;
393   gboolean ret = TRUE;
394
395   demux = GST_ASF_DEMUX (parent);
396
397   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
398   switch (GST_EVENT_TYPE (event)) {
399     case GST_EVENT_SEGMENT:{
400       const GstSegment *segment;
401
402       gst_event_parse_segment (event, &segment);
403
404       if (segment->format == GST_FORMAT_BYTES) {
405         if (demux->packet_size && segment->start > demux->data_offset)
406           demux->packet = (segment->start - demux->data_offset) /
407               demux->packet_size;
408         else
409           demux->packet = 0;
410       } else if (segment->format == GST_FORMAT_TIME) {
411         /* do not know packet position, not really a problem */
412         demux->packet = -1;
413       } else {
414         GST_WARNING_OBJECT (demux, "unsupported newsegment format, ignoring");
415         gst_event_unref (event);
416         break;
417       }
418
419       /* record upstream segment for interpolation */
420       if (segment->format != demux->in_segment.format)
421         gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED);
422       gst_segment_copy_into (segment, &demux->in_segment);
423
424       /* in either case, clear some state and generate newsegment later on */
425       GST_OBJECT_LOCK (demux);
426       demux->segment_ts = GST_CLOCK_TIME_NONE;
427       demux->in_gap = GST_CLOCK_TIME_NONE;
428       demux->need_newsegment = TRUE;
429       demux->segment_seqnum = gst_event_get_seqnum (event);
430       gst_asf_demux_reset_stream_state_after_discont (demux);
431       GST_OBJECT_UNLOCK (demux);
432
433       gst_event_unref (event);
434       break;
435     }
436     case GST_EVENT_EOS:{
437       GstFlowReturn flow;
438
439       if (demux->state == GST_ASF_DEMUX_STATE_HEADER) {
440         GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
441             (_("This stream contains no data.")),
442             ("got eos and didn't receive a complete header object"));
443         break;
444       }
445       flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
446       if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
447         GST_ELEMENT_ERROR (demux, STREAM, FAILED,
448             (_("Internal data stream error.")),
449             ("streaming stopped, reason %s", gst_flow_get_name (flow)));
450         break;
451       }
452
453       GST_OBJECT_LOCK (demux);
454       gst_adapter_clear (demux->adapter);
455       GST_OBJECT_UNLOCK (demux);
456       gst_asf_demux_send_event_unlocked (demux, event);
457       break;
458     }
459
460     case GST_EVENT_FLUSH_STOP:
461       GST_OBJECT_LOCK (demux);
462       gst_asf_demux_reset_stream_state_after_discont (demux);
463       GST_OBJECT_UNLOCK (demux);
464       gst_asf_demux_send_event_unlocked (demux, event);
465       /* upon activation, latency is no longer introduced, e.g. after seek */
466       if (demux->activated_streams)
467         demux->latency = 0;
468       break;
469
470     default:
471       ret = gst_pad_event_default (pad, parent, event);
472       break;
473   }
474
475   return ret;
476 }
477
478 static gboolean
479 gst_asf_demux_seek_index_lookup (GstASFDemux * demux, guint * packet,
480     GstClockTime seek_time, GstClockTime * p_idx_time, guint * speed,
481     gboolean next, gboolean * eos)
482 {
483   GstClockTime idx_time;
484   guint idx;
485
486   if (eos)
487     *eos = FALSE;
488
489   if (G_UNLIKELY (demux->sidx_num_entries == 0 || demux->sidx_interval == 0))
490     return FALSE;
491
492   idx = (guint) ((seek_time + demux->preroll) / demux->sidx_interval);
493
494   if (next) {
495     /* if we want the next keyframe, we have to go forward till we find
496        a different packet number */
497     guint idx2;
498     if (idx >= demux->sidx_num_entries - 1) {
499       /* If we get here, we're asking for next keyframe after the last one. There isn't one. */
500       if (eos)
501         *eos = TRUE;
502       return FALSE;
503     }
504     for (idx2 = idx + 1; idx2 < demux->sidx_num_entries; ++idx2) {
505       if (demux->sidx_entries[idx].packet != demux->sidx_entries[idx2].packet) {
506         idx = idx2;
507         break;
508       }
509     }
510   }
511
512   if (G_UNLIKELY (idx >= demux->sidx_num_entries)) {
513     if (eos)
514       *eos = TRUE;
515     return FALSE;
516   }
517
518   *packet = demux->sidx_entries[idx].packet;
519   if (speed)
520     *speed = demux->sidx_entries[idx].count;
521
522   /* so we get closer to the actual time of the packet ... actually, let's not
523    * do this, since we throw away superfluous payloads before the seek position
524    * anyway; this way, our key unit seek 'snap resolution' is a bit better
525    * (ie. same as index resolution) */
526   /*
527      while (idx > 0 && demux->sidx_entries[idx-1] == demux->sidx_entries[idx])
528      --idx;
529    */
530
531   idx_time = demux->sidx_interval * idx;
532   if (G_LIKELY (idx_time >= demux->preroll))
533     idx_time -= demux->preroll;
534
535   GST_DEBUG_OBJECT (demux, "%" GST_TIME_FORMAT " => packet %u at %"
536       GST_TIME_FORMAT, GST_TIME_ARGS (seek_time), *packet,
537       GST_TIME_ARGS (idx_time));
538
539   if (G_LIKELY (p_idx_time))
540     *p_idx_time = idx_time;
541
542   return TRUE;
543 }
544
545 static void
546 gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * demux)
547 {
548   guint n;
549
550   gst_adapter_clear (demux->adapter);
551
552   GST_DEBUG_OBJECT (demux, "reset stream state");
553
554   gst_flow_combiner_reset (demux->flowcombiner);
555   for (n = 0; n < demux->num_streams; n++) {
556     demux->stream[n].discont = TRUE;
557     demux->stream[n].first_buffer = TRUE;
558
559     while (demux->stream[n].payloads->len > 0) {
560       AsfPayload *payload;
561       guint last;
562
563       last = demux->stream[n].payloads->len - 1;
564       payload = &g_array_index (demux->stream[n].payloads, AsfPayload, last);
565       gst_buffer_replace (&payload->buf, NULL);
566       g_array_remove_index (demux->stream[n].payloads, last);
567     }
568   }
569 }
570
571 static void
572 gst_asf_demux_mark_discont (GstASFDemux * demux)
573 {
574   guint n;
575
576   GST_DEBUG_OBJECT (demux, "Mark stream discont");
577
578   for (n = 0; n < demux->num_streams; n++)
579     demux->stream[n].discont = TRUE;
580 }
581
582 /* do a seek in push based mode */
583 static gboolean
584 gst_asf_demux_handle_seek_push (GstASFDemux * demux, GstEvent * event)
585 {
586   gdouble rate;
587   GstFormat format;
588   GstSeekFlags flags;
589   GstSeekType cur_type, stop_type;
590   gint64 cur, stop;
591   guint packet;
592   gboolean res;
593   GstEvent *byte_event;
594
595   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
596       &stop_type, &stop);
597
598   stop_type = GST_SEEK_TYPE_NONE;
599   stop = -1;
600
601   GST_DEBUG_OBJECT (demux, "seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
602
603   /* determine packet, by index or by estimation */
604   if (!gst_asf_demux_seek_index_lookup (demux, &packet, cur, NULL, NULL, FALSE,
605           NULL)) {
606     packet =
607         (guint) gst_util_uint64_scale (demux->num_packets, cur,
608         demux->play_time);
609   }
610
611   if (packet > demux->num_packets) {
612     GST_DEBUG_OBJECT (demux, "could not determine packet to seek to, "
613         "seek aborted.");
614     return FALSE;
615   }
616
617   GST_DEBUG_OBJECT (demux, "seeking to packet %d", packet);
618
619   cur = demux->data_offset + ((guint64) packet * demux->packet_size);
620
621   GST_DEBUG_OBJECT (demux, "Pushing BYTE seek rate %g, "
622       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, stop);
623   /* BYTE seek event */
624   byte_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
625       cur, stop_type, stop);
626   gst_event_set_seqnum (byte_event, gst_event_get_seqnum (event));
627   res = gst_pad_push_event (demux->sinkpad, byte_event);
628
629   return res;
630 }
631
632 static gboolean
633 gst_asf_demux_handle_seek_event (GstASFDemux * demux, GstEvent * event)
634 {
635   GstClockTime idx_time;
636   GstSegment segment;
637   GstSeekFlags flags;
638   GstSeekType cur_type, stop_type;
639   GstFormat format;
640   gboolean only_need_update;
641   gboolean after, before, next;
642   gboolean flush;
643   gdouble rate;
644   gint64 cur, stop;
645   gint64 seek_time;
646   guint packet, speed_count = 1;
647   gboolean eos;
648   guint32 seqnum;
649   GstEvent *fevent;
650   gint i;
651
652   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
653       &stop_type, &stop);
654
655   if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
656     GST_LOG_OBJECT (demux, "seeking is only supported in TIME format");
657     return FALSE;
658   }
659
660   /* upstream might handle TIME seek, e.g. mms or rtsp, or not, e.g. http,
661    * so first try to let it handle the seek event. */
662   if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event)))
663     return TRUE;
664
665   if (G_UNLIKELY (demux->seekable == FALSE || demux->packet_size == 0 ||
666           demux->num_packets == 0 || demux->play_time == 0)) {
667     GST_LOG_OBJECT (demux, "stream is not seekable");
668     return FALSE;
669   }
670
671   if (G_UNLIKELY (!demux->activated_streams)) {
672     GST_LOG_OBJECT (demux, "streams not yet activated, ignoring seek");
673     return FALSE;
674   }
675
676   if (G_UNLIKELY (rate <= 0.0)) {
677     GST_LOG_OBJECT (demux, "backward playback");
678     demux->seek_to_cur_pos = TRUE;
679     for (i = 0; i < demux->num_streams; i++) {
680       demux->stream[i].reverse_kf_ready = FALSE;
681     }
682   }
683
684   seqnum = gst_event_get_seqnum (event);
685   flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
686   demux->accurate =
687       ((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
688   demux->keyunit_sync =
689       ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
690   after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
691   before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
692   next = after && !before;
693
694   if (G_UNLIKELY (demux->streaming)) {
695     /* support it safely needs more segment handling, e.g. closing etc */
696     if (!flush) {
697       GST_LOG_OBJECT (demux, "streaming; non-flushing seek not supported");
698       return FALSE;
699     }
700     /* we can (re)construct the start later on, but not the end */
701     if (stop_type != GST_SEEK_TYPE_NONE &&
702         (stop_type != GST_SEEK_TYPE_SET || GST_CLOCK_TIME_IS_VALID (stop))) {
703       GST_LOG_OBJECT (demux, "streaming; end position must be NONE");
704       return FALSE;
705     }
706     return gst_asf_demux_handle_seek_push (demux, event);
707   }
708
709   /* unlock the streaming thread */
710   if (G_LIKELY (flush)) {
711     fevent = gst_event_new_flush_start ();
712
713     gst_event_set_seqnum (fevent, seqnum);
714     gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
715     gst_asf_demux_send_event_unlocked (demux, fevent);
716   } else {
717     gst_pad_pause_task (demux->sinkpad);
718   }
719
720   /* grab the stream lock so that streaming cannot continue, for
721    * non flushing seeks when the element is in PAUSED this could block
722    * forever */
723   GST_PAD_STREAM_LOCK (demux->sinkpad);
724
725   /* we now can stop flushing, since we have the stream lock now */
726   fevent = gst_event_new_flush_stop (TRUE);
727   gst_event_set_seqnum (fevent, seqnum);
728   gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
729
730   if (G_LIKELY (flush))
731     gst_asf_demux_send_event_unlocked (demux, fevent);
732   else
733     gst_event_unref (fevent);
734
735   /* operating on copy of segment until we know the seek worked */
736   segment = demux->segment;
737
738   if (G_UNLIKELY (demux->segment_running && !flush)) {
739     GstSegment newsegment;
740     GstEvent *newseg;
741
742     /* create the segment event to close the current segment */
743     gst_segment_copy_into (&segment, &newsegment);
744     newseg = gst_event_new_segment (&newsegment);
745     gst_event_set_seqnum (newseg, seqnum);
746
747     gst_asf_demux_send_event_unlocked (demux, newseg);
748   }
749
750   gst_segment_do_seek (&segment, rate, format, flags, cur_type,
751       cur, stop_type, stop, &only_need_update);
752
753   GST_DEBUG_OBJECT (demux, "seeking to time %" GST_TIME_FORMAT ", segment: "
754       "%" GST_SEGMENT_FORMAT, GST_TIME_ARGS (segment.start), &segment);
755
756   if (cur_type != GST_SEEK_TYPE_SET)
757     seek_time = segment.start;
758   else
759     seek_time = cur;
760
761   /* FIXME: should check the KEY_UNIT flag; need to adjust position to
762    * real start of data and segment_start to indexed time for key unit seek*/
763   if (G_UNLIKELY (!gst_asf_demux_seek_index_lookup (demux, &packet, seek_time,
764               &idx_time, &speed_count, next, &eos))) {
765     gint64 offset;
766
767     if (eos) {
768       demux->packet = demux->num_packets;
769       goto skip;
770     }
771
772     /* First try to query our source to see if it can convert for us. This is
773        the case when our source is an mms stream, notice that in this case
774        gstmms will do a time based seek to get the byte offset, this is not a
775        problem as the seek to this offset needs to happen anway. */
776     if (gst_pad_peer_query_convert (demux->sinkpad, GST_FORMAT_TIME, seek_time,
777             GST_FORMAT_BYTES, &offset)) {
778       packet = (offset - demux->data_offset) / demux->packet_size;
779       GST_LOG_OBJECT (demux, "convert %" GST_TIME_FORMAT
780           " to bytes query result: %" G_GINT64_FORMAT ", data_ofset: %"
781           G_GINT64_FORMAT ", packet_size: %u," " resulting packet: %u\n",
782           GST_TIME_ARGS (seek_time), offset, demux->data_offset,
783           demux->packet_size, packet);
784     } else {
785       /* FIXME: For streams containing video, seek to an earlier position in
786        * the hope of hitting a keyframe and let the sinks throw away the stuff
787        * before the segment start. For audio-only this is unnecessary as every
788        * frame is 'key'. */
789       if (flush && (demux->accurate || (demux->keyunit_sync && !next))
790           && demux->num_video_streams > 0) {
791         seek_time -= 5 * GST_SECOND;
792         if (seek_time < 0)
793           seek_time = 0;
794       }
795
796       packet = (guint) gst_util_uint64_scale (demux->num_packets,
797           seek_time, demux->play_time);
798
799       if (packet > demux->num_packets)
800         packet = demux->num_packets;
801     }
802   } else {
803     if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
804       GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
805           GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
806           GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
807       segment.start = idx_time;
808       segment.position = idx_time;
809       segment.time = idx_time;
810     }
811   }
812
813   GST_DEBUG_OBJECT (demux, "seeking to packet %u (%d)", packet, speed_count);
814
815   GST_OBJECT_LOCK (demux);
816   demux->segment = segment;
817   if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
818     demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
819         stop, demux->play_time);
820   } else {
821     demux->packet = packet;
822   }
823
824   demux->need_newsegment = TRUE;
825   demux->segment_seqnum = seqnum;
826   demux->speed_packets =
827       GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
828   gst_asf_demux_reset_stream_state_after_discont (demux);
829   GST_OBJECT_UNLOCK (demux);
830
831 skip:
832   /* restart our task since it might have been stopped when we did the flush */
833   gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_asf_demux_loop,
834       demux, NULL);
835
836   /* streaming can continue now */
837   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
838
839   return TRUE;
840 }
841
842 static gboolean
843 gst_asf_demux_handle_src_event (GstPad * pad, GstObject * parent,
844     GstEvent * event)
845 {
846   GstASFDemux *demux;
847   gboolean ret;
848
849   demux = GST_ASF_DEMUX (parent);
850
851   switch (GST_EVENT_TYPE (event)) {
852     case GST_EVENT_SEEK:
853       GST_LOG_OBJECT (pad, "seek event");
854       ret = gst_asf_demux_handle_seek_event (demux, event);
855       gst_event_unref (event);
856       break;
857     case GST_EVENT_QOS:
858     case GST_EVENT_NAVIGATION:
859       /* just drop these two silently */
860       gst_event_unref (event);
861       ret = FALSE;
862       break;
863     default:
864       GST_LOG_OBJECT (pad, "%s event", GST_EVENT_TYPE_NAME (event));
865       ret = gst_pad_event_default (pad, parent, event);
866       break;
867   }
868
869   return ret;
870 }
871
872 static inline guint32
873 gst_asf_demux_identify_guid (const ASFGuidHash * guids, ASFGuid * guid)
874 {
875   guint32 ret;
876
877   ret = gst_asf_identify_guid (guids, guid);
878
879   GST_LOG ("%s  0x%08x-0x%08x-0x%08x-0x%08x",
880       gst_asf_get_guid_nick (guids, ret),
881       guid->v1, guid->v2, guid->v3, guid->v4);
882
883   return ret;
884 }
885
886 typedef struct
887 {
888   AsfObjectID id;
889   guint64 size;
890 } AsfObject;
891
892
893 /* expect is true when the user is expeting an object,
894  * when false, it will give no warnings if the object
895  * is not identified
896  */
897 static gboolean
898 asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
899     guint data_len, AsfObject * object, gboolean expect)
900 {
901   ASFGuid guid;
902
903   if (data_len < ASF_OBJECT_HEADER_SIZE)
904     return FALSE;
905
906   guid.v1 = GST_READ_UINT32_LE (data + 0);
907   guid.v2 = GST_READ_UINT32_LE (data + 4);
908   guid.v3 = GST_READ_UINT32_LE (data + 8);
909   guid.v4 = GST_READ_UINT32_LE (data + 12);
910
911   object->size = GST_READ_UINT64_LE (data + 16);
912
913   /* FIXME: make asf_demux_identify_object_guid() */
914   object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
915   if (object->id == ASF_OBJ_UNDEFINED && expect) {
916     GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x",
917         guid.v1, guid.v2, guid.v3, guid.v4);
918   }
919
920   return TRUE;
921 }
922
923 static void
924 gst_asf_demux_release_old_pads (GstASFDemux * demux)
925 {
926   GST_DEBUG_OBJECT (demux, "Releasing old pads");
927
928   while (demux->old_num_streams > 0) {
929     gst_pad_push_event (demux->old_stream[demux->old_num_streams - 1].pad,
930         gst_event_new_eos ());
931     gst_asf_demux_free_stream (demux,
932         &demux->old_stream[demux->old_num_streams - 1]);
933     --demux->old_num_streams;
934   }
935   memset (demux->old_stream, 0, sizeof (demux->old_stream));
936   demux->old_num_streams = 0;
937 }
938
939 static GstFlowReturn
940 gst_asf_demux_chain_headers (GstASFDemux * demux)
941 {
942   GstFlowReturn flow;
943   AsfObject obj;
944   guint8 *header_data, *data = NULL;
945   const guint8 *cdata = NULL;
946   guint64 header_size;
947
948   cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
949   if (cdata == NULL)
950     goto need_more_data;
951
952   asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
953   if (obj.id != ASF_OBJ_HEADER)
954     goto wrong_type;
955
956   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
957
958   /* + 50 for non-packet data at beginning of ASF_OBJ_DATA */
959   if (gst_adapter_available (demux->adapter) < obj.size + 50)
960     goto need_more_data;
961
962   data = gst_adapter_take (demux->adapter, obj.size + 50);
963
964   header_data = data;
965   header_size = obj.size;
966   flow = gst_asf_demux_process_object (demux, &header_data, &header_size);
967   if (flow != GST_FLOW_OK)
968     goto parse_failed;
969
970   /* calculate where the packet data starts */
971   demux->data_offset = obj.size + 50;
972
973   /* now parse the beginning of the ASF_OBJ_DATA object */
974   if (!gst_asf_demux_parse_data_object_start (demux, data + obj.size))
975     goto wrong_type;
976
977   if (demux->num_streams == 0)
978     goto no_streams;
979
980   g_free (data);
981   return GST_FLOW_OK;
982
983 /* NON-FATAL */
984 need_more_data:
985   {
986     GST_LOG_OBJECT (demux, "not enough data in adapter yet");
987     return GST_FLOW_OK;
988   }
989
990 /* ERRORS */
991 wrong_type:
992   {
993     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
994         ("This doesn't seem to be an ASF file"));
995     g_free (data);
996     return GST_FLOW_ERROR;
997   }
998 no_streams:
999 parse_failed:
1000   {
1001     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1002         ("header parsing failed, or no streams found, flow = %s",
1003             gst_flow_get_name (flow)));
1004     g_free (data);
1005     return GST_FLOW_ERROR;
1006   }
1007 }
1008
1009 static gboolean
1010 gst_asf_demux_pull_data (GstASFDemux * demux, guint64 offset, guint size,
1011     GstBuffer ** p_buf, GstFlowReturn * p_flow)
1012 {
1013   gsize buffer_size;
1014   GstFlowReturn flow;
1015
1016   GST_LOG_OBJECT (demux, "pulling buffer at %" G_GUINT64_FORMAT "+%u",
1017       offset, size);
1018
1019   flow = gst_pad_pull_range (demux->sinkpad, offset, size, p_buf);
1020
1021   if (G_LIKELY (p_flow))
1022     *p_flow = flow;
1023
1024   if (G_UNLIKELY (flow != GST_FLOW_OK)) {
1025     GST_DEBUG_OBJECT (demux, "flow %s pulling buffer at %" G_GUINT64_FORMAT
1026         "+%u", gst_flow_get_name (flow), offset, size);
1027     *p_buf = NULL;
1028     return FALSE;
1029   }
1030
1031   g_assert (*p_buf != NULL);
1032
1033   buffer_size = gst_buffer_get_size (*p_buf);
1034   if (G_UNLIKELY (buffer_size < size)) {
1035     GST_DEBUG_OBJECT (demux, "short read pulling buffer at %" G_GUINT64_FORMAT
1036         "+%u (got only %" G_GSIZE_FORMAT " bytes)", offset, size, buffer_size);
1037     gst_buffer_unref (*p_buf);
1038     if (G_LIKELY (p_flow))
1039       *p_flow = GST_FLOW_EOS;
1040     *p_buf = NULL;
1041     return FALSE;
1042   }
1043
1044   return TRUE;
1045 }
1046
1047 static void
1048 gst_asf_demux_pull_indices (GstASFDemux * demux)
1049 {
1050   GstBuffer *buf = NULL;
1051   guint64 offset;
1052   guint num_read = 0;
1053
1054   offset = demux->index_offset;
1055
1056   if (G_UNLIKELY (offset == 0)) {
1057     GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
1058     return;
1059   }
1060
1061   while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
1062     GstFlowReturn flow;
1063     AsfObject obj;
1064     GstMapInfo map;
1065     guint8 *bufdata;
1066
1067     gst_buffer_map (buf, &map, GST_MAP_READ);
1068     g_assert (map.size >= 16 + 8);
1069     asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1070     gst_buffer_unmap (buf, &map);
1071     gst_buffer_replace (&buf, NULL);
1072
1073     /* check for sanity */
1074     if (G_UNLIKELY (obj.size > (5 * 1024 * 1024))) {
1075       GST_DEBUG_OBJECT (demux, "implausible index object size, bailing out");
1076       break;
1077     }
1078
1079     if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, offset, obj.size, &buf,
1080                 NULL)))
1081       break;
1082
1083     GST_LOG_OBJECT (demux, "index object at offset 0x%" G_GINT64_MODIFIER "X"
1084         ", size %u", offset, (guint) obj.size);
1085
1086     offset += obj.size;         /* increase before _process_object changes it */
1087
1088     gst_buffer_map (buf, &map, GST_MAP_READ);
1089     g_assert (map.size >= obj.size);
1090     bufdata = (guint8 *) map.data;
1091     flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
1092     gst_buffer_unmap (buf, &map);
1093     gst_buffer_replace (&buf, NULL);
1094
1095     if (G_UNLIKELY (flow != GST_FLOW_OK))
1096       break;
1097
1098     ++num_read;
1099   }
1100   GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
1101 }
1102
1103 static gboolean
1104 gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data)
1105 {
1106   AsfObject obj;
1107
1108   asf_demux_peek_object (demux, data, 50, &obj, TRUE);
1109   if (obj.id != ASF_OBJ_DATA) {
1110     GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
1111     return FALSE;
1112   }
1113
1114   demux->state = GST_ASF_DEMUX_STATE_DATA;
1115
1116   if (!demux->broadcast && obj.size > 50) {
1117     demux->data_size = obj.size - 50;
1118     /* CHECKME: for at least one file this is off by +158 bytes?! */
1119     demux->index_offset = demux->data_offset + demux->data_size;
1120   } else {
1121     demux->data_size = 0;
1122     demux->index_offset = 0;
1123   }
1124
1125   demux->packet = 0;
1126
1127   if (!demux->broadcast) {
1128     /* skip object header (24 bytes) and file GUID (16 bytes) */
1129     demux->num_packets = GST_READ_UINT64_LE (data + (16 + 8) + 16);
1130   } else {
1131     demux->num_packets = 0;
1132   }
1133
1134   if (demux->num_packets == 0)
1135     demux->seekable = FALSE;
1136
1137   /* fallback in the unlikely case that headers are inconsistent, can't hurt */
1138   if (demux->data_size == 0 && demux->num_packets > 0) {
1139     demux->data_size = demux->num_packets * demux->packet_size;
1140     demux->index_offset = demux->data_offset + demux->data_size;
1141   }
1142
1143   /* process pending stream objects and create pads for those */
1144   gst_asf_demux_process_queued_extended_stream_objects (demux);
1145
1146   GST_INFO_OBJECT (demux, "Stream has %" G_GUINT64_FORMAT " packets, "
1147       "data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
1148       ", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
1149       demux->data_offset, demux->data_size, demux->index_offset);
1150
1151   return TRUE;
1152 }
1153
1154 static gboolean
1155 gst_asf_demux_pull_headers (GstASFDemux * demux, GstFlowReturn * pflow)
1156 {
1157   GstFlowReturn flow = GST_FLOW_OK;
1158   AsfObject obj;
1159   GstBuffer *buf = NULL;
1160   guint64 size;
1161   GstMapInfo map;
1162   guint8 *bufdata;
1163
1164   GST_LOG_OBJECT (demux, "reading headers");
1165
1166   /* pull HEADER object header, so we know its size */
1167   if (!gst_asf_demux_pull_data (demux, demux->base_offset, 16 + 8, &buf, &flow))
1168     goto read_failed;
1169
1170   gst_buffer_map (buf, &map, GST_MAP_READ);
1171   g_assert (map.size >= 16 + 8);
1172   asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
1173   gst_buffer_unmap (buf, &map);
1174   gst_buffer_replace (&buf, NULL);
1175
1176   if (obj.id != ASF_OBJ_HEADER)
1177     goto wrong_type;
1178
1179   GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
1180
1181   /* pull HEADER object */
1182   if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
1183           &flow))
1184     goto read_failed;
1185
1186   size = obj.size;              /* don't want obj.size changed */
1187   gst_buffer_map (buf, &map, GST_MAP_READ);
1188   g_assert (map.size >= size);
1189   bufdata = (guint8 *) map.data;
1190   flow = gst_asf_demux_process_object (demux, &bufdata, &size);
1191   gst_buffer_unmap (buf, &map);
1192   gst_buffer_replace (&buf, NULL);
1193
1194   if (flow != GST_FLOW_OK) {
1195     GST_WARNING_OBJECT (demux, "process_object: %s", gst_flow_get_name (flow));
1196     goto parse_failed;
1197   }
1198
1199   /* calculate where the packet data starts */
1200   demux->data_offset = demux->base_offset + obj.size + 50;
1201
1202   /* now pull beginning of DATA object before packet data */
1203   if (!gst_asf_demux_pull_data (demux, demux->base_offset + obj.size, 50, &buf,
1204           &flow))
1205     goto read_failed;
1206
1207   gst_buffer_map (buf, &map, GST_MAP_READ);
1208   g_assert (map.size >= size);
1209   bufdata = (guint8 *) map.data;
1210   if (!gst_asf_demux_parse_data_object_start (demux, bufdata))
1211     goto wrong_type;
1212
1213   if (demux->num_streams == 0)
1214     goto no_streams;
1215
1216   gst_buffer_unmap (buf, &map);
1217   gst_buffer_replace (&buf, NULL);
1218
1219   return TRUE;
1220
1221 /* ERRORS */
1222 wrong_type:
1223   {
1224     if (buf != NULL) {
1225       gst_buffer_unmap (buf, &map);
1226       gst_buffer_replace (&buf, NULL);
1227     }
1228     GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
1229         ("This doesn't seem to be an ASF file"));
1230     *pflow = GST_FLOW_ERROR;
1231     return FALSE;
1232   }
1233
1234 no_streams:
1235   flow = GST_FLOW_ERROR;
1236   GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
1237       ("header parsing failed, or no streams found, flow = %s",
1238           gst_flow_get_name (flow)));
1239 read_failed:
1240 parse_failed:
1241   {
1242     if (buf)
1243       gst_buffer_unmap (buf, &map);
1244     gst_buffer_replace (&buf, NULL);
1245     *pflow = flow;
1246     return FALSE;
1247   }
1248 }
1249
1250 static gboolean
1251 all_streams_prerolled (GstASFDemux * demux)
1252 {
1253   GstClockTime preroll_time;
1254   guint i, num_no_data = 0;
1255
1256   /* Allow at least 500ms of preroll_time  */
1257   preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
1258
1259   /* returns TRUE as long as there isn't a stream which (a) has data queued
1260    * and (b) the timestamp of last piece of data queued is < demux->preroll
1261    * AND there is at least one other stream with data queued */
1262   for (i = 0; i < demux->num_streams; ++i) {
1263     AsfPayload *last_payload = NULL;
1264     AsfStream *stream;
1265     gint last_idx;
1266
1267     stream = &demux->stream[i];
1268     if (G_UNLIKELY (stream->payloads->len == 0)) {
1269       ++num_no_data;
1270       GST_LOG_OBJECT (stream->pad, "no data queued");
1271       continue;
1272     }
1273
1274     /* find last payload with timestamp */
1275     for (last_idx = stream->payloads->len - 1;
1276         last_idx >= 0 && (last_payload == NULL
1277             || !GST_CLOCK_TIME_IS_VALID (last_payload->ts)); --last_idx) {
1278       last_payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1279     }
1280
1281     GST_LOG_OBJECT (stream->pad, "checking if %" GST_TIME_FORMAT " > %"
1282         GST_TIME_FORMAT, GST_TIME_ARGS (last_payload->ts),
1283         GST_TIME_ARGS (preroll_time));
1284     if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (last_payload->ts)
1285             || last_payload->ts <= preroll_time)) {
1286       GST_LOG_OBJECT (stream->pad, "not beyond preroll point yet");
1287       return FALSE;
1288     }
1289   }
1290
1291   if (G_UNLIKELY (num_no_data > 0))
1292     return FALSE;
1293
1294   return TRUE;
1295 }
1296
1297 #if 0
1298 static gboolean
1299 gst_asf_demux_have_mutually_exclusive_active_stream (GstASFDemux * demux,
1300     AsfStream * stream)
1301 {
1302   GSList *l;
1303
1304   for (l = demux->mut_ex_streams; l != NULL; l = l->next) {
1305     guint8 *mes;
1306
1307     /* check for each mutual exclusion group whether it affects this stream */
1308     for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1309       if (*mes == stream->id) {
1310         /* we are in this group; let's check if we've already activated streams
1311          * that are in the same group (and hence mutually exclusive to this
1312          * one) */
1313         for (mes = (guint8 *) l->data; mes != NULL && *mes != 0xff; ++mes) {
1314           guint i;
1315
1316           for (i = 0; i < demux->num_streams; ++i) {
1317             if (demux->stream[i].id == *mes && demux->stream[i].active) {
1318               GST_LOG_OBJECT (demux, "stream with ID %d is mutually exclusive "
1319                   "to already active stream with ID %d", stream->id,
1320                   demux->stream[i].id);
1321               return TRUE;
1322             }
1323           }
1324         }
1325         /* we can only be in this group once, let's break out and move on to
1326          * the next mutual exclusion group */
1327         break;
1328       }
1329     }
1330   }
1331
1332   return FALSE;
1333 }
1334 #endif
1335
1336 static void
1337 gst_asf_demux_check_segment_ts (GstASFDemux * demux, GstClockTime payload_ts)
1338 {
1339   /* remember the first queued timestamp for the segment */
1340   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->segment_ts) &&
1341           GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1342     GST_DEBUG_OBJECT (demux, "segment ts: %" GST_TIME_FORMAT,
1343         GST_TIME_ARGS (demux->first_ts));
1344     demux->segment_ts = payload_ts;
1345     /* always note, but only determines segment when streaming */
1346     if (demux->streaming)
1347       gst_segment_do_seek (&demux->segment, demux->in_segment.rate,
1348           GST_FORMAT_TIME, (GstSeekFlags) demux->segment.flags,
1349           GST_SEEK_TYPE_SET, demux->segment_ts, GST_SEEK_TYPE_NONE, 0, NULL);
1350   }
1351 }
1352
1353 static gboolean
1354 gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
1355 {
1356   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
1357     GstClockTime first_ts = GST_CLOCK_TIME_NONE;
1358     int i;
1359
1360     /* go trhough each stream, find smallest timestamp */
1361     for (i = 0; i < demux->num_streams; ++i) {
1362       AsfStream *stream;
1363       int j;
1364       GstClockTime stream_min_ts = GST_CLOCK_TIME_NONE;
1365       GstClockTime stream_min_ts2 = GST_CLOCK_TIME_NONE;        /* second smallest timestamp */
1366       stream = &demux->stream[i];
1367
1368       for (j = 0; j < stream->payloads->len; ++j) {
1369         AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1370         if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1371             (!GST_CLOCK_TIME_IS_VALID (stream_min_ts)
1372                 || stream_min_ts > payload->ts)) {
1373           stream_min_ts = payload->ts;
1374         }
1375         if (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1376             payload->ts > stream_min_ts &&
1377             (!GST_CLOCK_TIME_IS_VALID (stream_min_ts2)
1378                 || stream_min_ts2 > payload->ts)) {
1379           stream_min_ts2 = payload->ts;
1380         }
1381       }
1382
1383       /* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
1384          regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
1385          which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues 
1386          from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
1387          and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
1388
1389       if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force)        /* still waiting for the second timestamp */
1390         return FALSE;
1391
1392       if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND)    /* first timestamp is 0 and second is significantly larger, disregard the 0 */
1393         stream_min_ts = stream_min_ts2;
1394
1395       /* if we don't have timestamp for this stream, wait for more data */
1396       if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
1397         return FALSE;
1398
1399       if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
1400           (!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
1401         first_ts = stream_min_ts;
1402     }
1403
1404     if (!GST_CLOCK_TIME_IS_VALID (first_ts))    /* can happen with force = TRUE */
1405       first_ts = 0;
1406
1407     demux->first_ts = first_ts;
1408
1409     /* update packets queued before we knew first timestamp */
1410     for (i = 0; i < demux->num_streams; ++i) {
1411       AsfStream *stream;
1412       int j;
1413       stream = &demux->stream[i];
1414
1415       for (j = 0; j < stream->payloads->len; ++j) {
1416         AsfPayload *payload = &g_array_index (stream->payloads, AsfPayload, j);
1417         if (GST_CLOCK_TIME_IS_VALID (payload->ts)) {
1418           if (payload->ts > first_ts)
1419             payload->ts -= first_ts;
1420           else
1421             payload->ts = 0;
1422         }
1423       }
1424     }
1425   }
1426
1427   gst_asf_demux_check_segment_ts (demux, 0);
1428
1429   return TRUE;
1430 }
1431
1432 static gboolean
1433 gst_asf_demux_update_caps_from_payload (GstASFDemux * demux, AsfStream * stream)
1434 {
1435   /* try to determine whether the stream is AC-3 or MPEG; In dvr-ms the codecTag is unreliable
1436      and often set wrong, inspecting the data is the only way that seem to be working */
1437   GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
1438   GstCaps *caps = NULL;
1439   int i;
1440   GstAdapter *adapter = gst_adapter_new ();
1441
1442   for (i = 0; i < stream->payloads->len && prob < GST_TYPE_FIND_LIKELY; ++i) {
1443     const guint8 *data;
1444     AsfPayload *payload;
1445     int len;
1446
1447     payload = &g_array_index (stream->payloads, AsfPayload, i);
1448     gst_adapter_push (adapter, gst_buffer_ref (payload->buf));
1449     len = gst_adapter_available (adapter);
1450     data = gst_adapter_map (adapter, len);
1451
1452   again:
1453
1454 #define MIN_LENGTH 128
1455
1456     /* look for the sync points */
1457     while (TRUE) {
1458       if (len < MIN_LENGTH ||   /* give typefind something to work on */
1459           (data[0] == 0x0b && data[1] == 0x77) ||       /* AC-3 sync point */
1460           (data[0] == 0xFF && ((data[1] & 0xF0) >> 4) == 0xF))  /* MPEG sync point */
1461         break;
1462       ++data;
1463       --len;
1464     }
1465
1466     gst_caps_take (&caps, gst_type_find_helper_for_data (GST_OBJECT (demux),
1467             data, len, &prob));
1468
1469     if (prob < GST_TYPE_FIND_LIKELY) {
1470       ++data;
1471       --len;
1472       if (len > MIN_LENGTH)
1473         /* this wasn't it, look for another sync point */
1474         goto again;
1475     }
1476
1477     gst_adapter_unmap (adapter);
1478   }
1479
1480   gst_object_unref (adapter);
1481
1482   if (caps) {
1483     gst_caps_take (&stream->caps, caps);
1484     return TRUE;
1485   } else {
1486     return FALSE;
1487   }
1488 }
1489
1490 static gboolean
1491 gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
1492 {
1493   guint i;
1494
1495   if (demux->activated_streams)
1496     return TRUE;
1497
1498   if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
1499     return FALSE;
1500
1501   if (!all_streams_prerolled (demux) && !force) {
1502     GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
1503     return FALSE;
1504   }
1505
1506   for (i = 0; i < demux->num_streams; ++i) {
1507     AsfStream *stream = &demux->stream[i];
1508
1509     if (stream->payloads->len > 0) {
1510
1511       if (stream->inspect_payload &&    /* dvr-ms required payload inspection */
1512           !stream->active &&    /* do not inspect active streams (caps were already set) */
1513           !gst_asf_demux_update_caps_from_payload (demux, stream) &&    /* failed to determine caps */
1514           stream->payloads->len < 20) { /* if we couldn't determine the caps from 20 packets then just give up and use whatever was in codecTag */
1515         /* try to gather some more data  */
1516         return FALSE;
1517       }
1518       /* we don't check mutual exclusion stuff here; either we have data for
1519        * a stream, then we active it, or we don't, then we'll ignore it */
1520       GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
1521       gst_asf_demux_activate_stream (demux, stream);
1522     } else {
1523       GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
1524     }
1525   }
1526
1527   gst_asf_demux_release_old_pads (demux);
1528
1529   demux->activated_streams = TRUE;
1530   GST_LOG_OBJECT (demux, "signalling no more pads");
1531   gst_element_no_more_pads (GST_ELEMENT (demux));
1532   return TRUE;
1533 }
1534
1535 /* returns the stream that has a complete payload with the lowest timestamp
1536  * queued, or NULL (we push things by timestamp because during the internal
1537  * prerolling we might accumulate more data then the external queues can take,
1538  * so we'd lock up if we pushed all accumulated data for stream N in one go) */
1539 static AsfStream *
1540 gst_asf_demux_find_stream_with_complete_payload (GstASFDemux * demux)
1541 {
1542   AsfPayload *best_payload = NULL;
1543   AsfStream *best_stream = NULL;
1544   guint i;
1545
1546   for (i = 0; i < demux->num_streams; ++i) {
1547     AsfStream *stream;
1548     int j;
1549
1550     stream = &demux->stream[i];
1551
1552     /* Don't push any data until we have at least one payload that falls within
1553      * the current segment. This way we can remove out-of-segment payloads that
1554      * don't need to be decoded after a seek, sending only data from the
1555      * keyframe directly before our segment start */
1556     if (stream->payloads->len > 0) {
1557       AsfPayload *payload = NULL;
1558       gint last_idx;
1559
1560       if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1561         /* Reverse playback */
1562
1563         if (stream->is_video) {
1564           /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
1565           if (stream->reverse_kf_ready) {
1566             payload =
1567                 &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1568             if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
1569               /* TODO : remove payload from the list? */
1570               continue;
1571             }
1572           } else {
1573             continue;
1574           }
1575         } else {
1576           /* find first complete payload with timestamp */
1577           for (j = stream->payloads->len - 1;
1578               j >= 0 && (payload == NULL
1579                   || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
1580             payload = &g_array_index (stream->payloads, AsfPayload, j);
1581           }
1582
1583           /* If there's a complete payload queued for this stream */
1584           if (!gst_asf_payload_is_complete (payload))
1585             continue;
1586
1587         }
1588       } else {
1589
1590         /* find last payload with timestamp */
1591         for (last_idx = stream->payloads->len - 1;
1592             last_idx >= 0 && (payload == NULL
1593                 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
1594           payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
1595         }
1596
1597         /* if this is first payload after seek we might need to update the segment */
1598         if (GST_CLOCK_TIME_IS_VALID (payload->ts))
1599           gst_asf_demux_check_segment_ts (demux, payload->ts);
1600
1601         if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
1602                 (payload->ts < demux->segment.start))) {
1603           if (G_UNLIKELY ((!demux->keyunit_sync) && (!demux->accurate)
1604                   && payload->keyframe)) {
1605             GST_DEBUG_OBJECT (stream->pad,
1606                 "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
1607                 GST_TIME_ARGS (payload->ts));
1608             demux->segment.start = payload->ts;
1609             demux->segment.time = payload->ts;
1610           } else {
1611             GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
1612                 GST_TIME_FORMAT " which is before our segment start %"
1613                 GST_TIME_FORMAT ", not pushing yet",
1614                 GST_TIME_ARGS (payload->ts),
1615                 GST_TIME_ARGS (demux->segment.start));
1616             continue;
1617           }
1618         }
1619         payload = NULL;
1620         /* find first complete payload with timestamp */
1621         for (j = 0;
1622             j < stream->payloads->len && (payload == NULL
1623                 || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
1624           payload = &g_array_index (stream->payloads, AsfPayload, j);
1625         }
1626
1627         /* Now see if there's a complete payload queued for this stream */
1628         if (!gst_asf_payload_is_complete (payload))
1629           continue;
1630       }
1631
1632       /* ... and whether its timestamp is lower than the current best */
1633       if (best_stream == NULL || best_payload->ts > payload->ts) {
1634         best_stream = stream;
1635         best_payload = payload;
1636       }
1637     }
1638   }
1639
1640   return best_stream;
1641 }
1642
1643 static GstFlowReturn
1644 gst_asf_demux_push_complete_payloads (GstASFDemux * demux, gboolean force)
1645 {
1646   AsfStream *stream;
1647   GstFlowReturn ret = GST_FLOW_OK;
1648
1649   if (G_UNLIKELY (!demux->activated_streams)) {
1650     if (!gst_asf_demux_check_activate_streams (demux, force))
1651       return GST_FLOW_OK;
1652     /* streams are now activated */
1653   }
1654
1655   while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
1656     AsfPayload *payload;
1657     GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1658     GstClockTime duration = GST_CLOCK_TIME_NONE;
1659
1660     /* wait until we had a chance to "lock on" some payload's timestamp */
1661     if (G_UNLIKELY (demux->need_newsegment
1662             && !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
1663       return GST_FLOW_OK;
1664
1665     if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1666         && stream->payloads->len) {
1667       payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
1668     } else {
1669       payload = &g_array_index (stream->payloads, AsfPayload, 0);
1670     }
1671
1672     /* do we need to send a newsegment event */
1673     if ((G_UNLIKELY (demux->need_newsegment))) {
1674       GstEvent *segment_event;
1675
1676       /* safe default if insufficient upstream info */
1677       if (!GST_CLOCK_TIME_IS_VALID (demux->in_gap))
1678         demux->in_gap = 0;
1679
1680       if (demux->segment.stop == GST_CLOCK_TIME_NONE &&
1681           demux->segment.duration > 0) {
1682         /* slight HACK; prevent clipping of last bit */
1683         demux->segment.stop = demux->segment.duration + demux->in_gap;
1684       }
1685
1686       /* FIXME : only if ACCURATE ! */
1687       if (G_LIKELY (!demux->keyunit_sync && !demux->accurate
1688               && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
1689           && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1690         GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
1691             GST_TIME_ARGS (payload->ts));
1692         demux->segment.start = payload->ts;
1693         demux->segment.time = payload->ts;
1694       }
1695
1696       GST_DEBUG_OBJECT (demux, "sending new-segment event %" GST_SEGMENT_FORMAT,
1697           &demux->segment);
1698
1699       /* note: we fix up all timestamps to start from 0, so this should be ok */
1700       segment_event = gst_event_new_segment (&demux->segment);
1701       if (demux->segment_seqnum)
1702         gst_event_set_seqnum (segment_event, demux->segment_seqnum);
1703       gst_asf_demux_send_event_unlocked (demux, segment_event);
1704
1705       /* now post any global tags we may have found */
1706       if (demux->taglist == NULL) {
1707         demux->taglist = gst_tag_list_new_empty ();
1708         gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
1709       }
1710
1711       gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1712           GST_TAG_CONTAINER_FORMAT, "ASF", NULL);
1713
1714       GST_DEBUG_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->taglist);
1715       gst_asf_demux_send_event_unlocked (demux,
1716           gst_event_new_tag (demux->taglist));
1717       demux->taglist = NULL;
1718
1719       demux->need_newsegment = FALSE;
1720       demux->segment_seqnum = 0;
1721       demux->segment_running = TRUE;
1722     }
1723
1724     /* Do we have tags pending for this stream? */
1725     if (G_UNLIKELY (stream->pending_tags)) {
1726       GST_LOG_OBJECT (stream->pad, "%" GST_PTR_FORMAT, stream->pending_tags);
1727       gst_pad_push_event (stream->pad,
1728           gst_event_new_tag (stream->pending_tags));
1729       stream->pending_tags = NULL;
1730     }
1731
1732     /* We have the whole packet now so we should push the packet to
1733      * the src pad now. First though we should check if we need to do
1734      * descrambling */
1735     if (G_UNLIKELY (stream->span > 1)) {
1736       gst_asf_demux_descramble_buffer (demux, stream, &payload->buf);
1737     }
1738
1739     payload->buf = gst_buffer_make_writable (payload->buf);
1740
1741     if (G_LIKELY (!payload->keyframe)) {
1742       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DELTA_UNIT);
1743     }
1744
1745     if (G_UNLIKELY (stream->discont)) {
1746       GST_DEBUG_OBJECT (stream->pad, "marking DISCONT on stream");
1747       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1748       stream->discont = FALSE;
1749     }
1750
1751     if (G_UNLIKELY (stream->is_video && payload->par_x && payload->par_y &&
1752             (payload->par_x != stream->par_x) &&
1753             (payload->par_y != stream->par_y))) {
1754       GST_DEBUG ("Updating PAR (%d/%d => %d/%d)",
1755           stream->par_x, stream->par_y, payload->par_x, payload->par_y);
1756       stream->par_x = payload->par_x;
1757       stream->par_y = payload->par_y;
1758       stream->caps = gst_caps_make_writable (stream->caps);
1759       gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
1760           GST_TYPE_FRACTION, stream->par_x, stream->par_y, NULL);
1761       gst_pad_set_caps (stream->pad, stream->caps);
1762     }
1763
1764     if (G_UNLIKELY (stream->interlaced != payload->interlaced)) {
1765       GST_DEBUG ("Updating interlaced status (%d => %d)", stream->interlaced,
1766           payload->interlaced);
1767       stream->interlaced = payload->interlaced;
1768       stream->caps = gst_caps_make_writable (stream->caps);
1769       gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_BOOLEAN,
1770           (stream->interlaced ? "mixed" : "progressive"), NULL);
1771       gst_pad_set_caps (stream->pad, stream->caps);
1772     }
1773
1774     /* (sort of) interpolate timestamps using upstream "frame of reference",
1775      * typically useful for live src, but might (unavoidably) mess with
1776      * position reporting if a live src is playing not so live content
1777      * (e.g. rtspsrc taking some time to fall back to tcp) */
1778     timestamp = payload->ts;
1779     if (GST_CLOCK_TIME_IS_VALID (timestamp)
1780         && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1781       timestamp += demux->in_gap;
1782
1783       /* Check if we're after the segment already, if so no need to push
1784        * anything here */
1785       if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
1786         GST_DEBUG_OBJECT (stream->pad,
1787             "Payload after segment stop %" GST_TIME_FORMAT,
1788             GST_TIME_ARGS (demux->segment.stop));
1789         ret =
1790             gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1791             GST_FLOW_EOS);
1792         gst_buffer_unref (payload->buf);
1793         payload->buf = NULL;
1794         g_array_remove_index (stream->payloads, 0);
1795         /* Break out as soon as we have an issue */
1796         if (G_UNLIKELY (ret != GST_FLOW_OK))
1797           break;
1798
1799         continue;
1800       }
1801     }
1802
1803     GST_BUFFER_PTS (payload->buf) = timestamp;
1804
1805     if (payload->duration == GST_CLOCK_TIME_NONE
1806         && stream->ext_props.avg_time_per_frame != 0) {
1807       duration = stream->ext_props.avg_time_per_frame * 100;
1808     } else {
1809       duration = payload->duration;
1810     }
1811     GST_BUFFER_DURATION (payload->buf) = duration;
1812
1813     /* FIXME: we should really set durations on buffers if we can */
1814
1815     GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
1816         payload->buf);
1817
1818     if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
1819       if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
1820         GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1821       }
1822     } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
1823       GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
1824     }
1825
1826
1827     if (stream->active) {
1828       if (G_UNLIKELY (stream->first_buffer)) {
1829         if (stream->streamheader != NULL) {
1830           GST_DEBUG_OBJECT (stream->pad,
1831               "Pushing streamheader before first buffer");
1832           gst_pad_push (stream->pad, gst_buffer_ref (stream->streamheader));
1833         }
1834         stream->first_buffer = FALSE;
1835       }
1836
1837       if (GST_CLOCK_TIME_IS_VALID (timestamp)
1838           && timestamp > demux->segment.position) {
1839         demux->segment.position = timestamp;
1840         if (GST_CLOCK_TIME_IS_VALID (duration))
1841           demux->segment.position += timestamp;
1842       }
1843
1844       ret = gst_pad_push (stream->pad, payload->buf);
1845       ret =
1846           gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
1847           ret);
1848     } else {
1849       gst_buffer_unref (payload->buf);
1850       ret = GST_FLOW_OK;
1851     }
1852     payload->buf = NULL;
1853     if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
1854         && stream->reverse_kf_ready) {
1855       g_array_remove_index (stream->payloads, stream->kf_pos);
1856       stream->kf_pos--;
1857
1858       if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
1859         stream->kf_pos = 0;
1860         stream->reverse_kf_ready = FALSE;
1861       }
1862     } else {
1863       g_array_remove_index (stream->payloads, 0);
1864     }
1865
1866     /* Break out as soon as we have an issue */
1867     if (G_UNLIKELY (ret != GST_FLOW_OK))
1868       break;
1869   }
1870
1871   return ret;
1872 }
1873
1874 static gboolean
1875 gst_asf_demux_check_buffer_is_header (GstASFDemux * demux, GstBuffer * buf)
1876 {
1877   AsfObject obj;
1878   GstMapInfo map;
1879   g_assert (buf != NULL);
1880
1881   GST_LOG_OBJECT (demux, "Checking if buffer is a header");
1882
1883   gst_buffer_map (buf, &map, GST_MAP_READ);
1884
1885   /* we return false on buffer too small */
1886   if (map.size < ASF_OBJECT_HEADER_SIZE) {
1887     gst_buffer_unmap (buf, &map);
1888     return FALSE;
1889   }
1890
1891   /* check if it is a header */
1892   asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
1893   gst_buffer_unmap (buf, &map);
1894   if (obj.id == ASF_OBJ_HEADER) {
1895     return TRUE;
1896   }
1897   return FALSE;
1898 }
1899
1900 static gboolean
1901 gst_asf_demux_check_chained_asf (GstASFDemux * demux)
1902 {
1903   guint64 off = demux->data_offset + (demux->packet * demux->packet_size);
1904   GstFlowReturn ret = GST_FLOW_OK;
1905   GstBuffer *buf = NULL;
1906   gboolean header = FALSE;
1907
1908   /* TODO maybe we should skip index objects after the data and look
1909    * further for a new header */
1910   if (gst_asf_demux_pull_data (demux, off, ASF_OBJECT_HEADER_SIZE, &buf, &ret)) {
1911     g_assert (buf != NULL);
1912     /* check if it is a header */
1913     if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1914       GST_DEBUG_OBJECT (demux, "new base offset: %" G_GUINT64_FORMAT, off);
1915       demux->base_offset = off;
1916       header = TRUE;
1917     }
1918
1919     gst_buffer_unref (buf);
1920   }
1921
1922   return header;
1923 }
1924
1925 static void
1926 gst_asf_demux_loop (GstASFDemux * demux)
1927 {
1928   GstFlowReturn flow = GST_FLOW_OK;
1929   GstBuffer *buf = NULL;
1930   guint64 off;
1931
1932   if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
1933     if (!gst_asf_demux_pull_headers (demux, &flow)) {
1934       goto pause;
1935     }
1936
1937     gst_asf_demux_pull_indices (demux);
1938   }
1939
1940   g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
1941
1942   if (G_UNLIKELY (demux->num_packets != 0
1943           && demux->packet >= demux->num_packets))
1944     goto eos;
1945
1946   GST_LOG_OBJECT (demux, "packet %u/%u", (guint) demux->packet + 1,
1947       (guint) demux->num_packets);
1948
1949   off = demux->data_offset + (demux->packet * demux->packet_size);
1950
1951   if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
1952               demux->packet_size * demux->speed_packets, &buf, &flow))) {
1953     GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
1954     if (flow == GST_FLOW_EOS) {
1955       goto eos;
1956     } else if (flow == GST_FLOW_FLUSHING) {
1957       GST_DEBUG_OBJECT (demux, "Not fatal");
1958       goto pause;
1959     } else {
1960       goto read_failed;
1961     }
1962   }
1963
1964   if (G_LIKELY (demux->speed_packets == 1)) {
1965     GstAsfDemuxParsePacketError err;
1966     err = gst_asf_demux_parse_packet (demux, buf);
1967     if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
1968       /* when we don't know when the data object ends, we should check
1969        * for a chained asf */
1970       if (demux->num_packets == 0) {
1971         if (gst_asf_demux_check_buffer_is_header (demux, buf)) {
1972           GST_INFO_OBJECT (demux, "Chained asf found");
1973           demux->base_offset = off;
1974           gst_asf_demux_reset (demux, TRUE);
1975           gst_buffer_unref (buf);
1976           return;
1977         }
1978       }
1979       /* FIXME: We should tally up fatal errors and error out only
1980        * after a few broken packets in a row? */
1981
1982       GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
1983       gst_buffer_unref (buf);
1984
1985       if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
1986           && !demux->seek_to_cur_pos) {
1987         --demux->packet;
1988         if (demux->packet < 0) {
1989           goto eos;
1990         }
1991       } else {
1992         ++demux->packet;
1993       }
1994
1995       return;
1996     }
1997
1998     flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
1999
2000     if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
2001         && !demux->seek_to_cur_pos) {
2002       --demux->packet;
2003       if (demux->packet < 0) {
2004         goto eos;
2005       }
2006     } else {
2007       ++demux->packet;
2008     }
2009
2010   } else {
2011     guint n;
2012     for (n = 0; n < demux->speed_packets; n++) {
2013       GstBuffer *sub;
2014       GstAsfDemuxParsePacketError err;
2015
2016       sub =
2017           gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
2018           n * demux->packet_size, demux->packet_size);
2019       err = gst_asf_demux_parse_packet (demux, sub);
2020       if (G_UNLIKELY (err != GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)) {
2021         /* when we don't know when the data object ends, we should check
2022          * for a chained asf */
2023         if (demux->num_packets == 0) {
2024           if (gst_asf_demux_check_buffer_is_header (demux, sub)) {
2025             GST_INFO_OBJECT (demux, "Chained asf found");
2026             demux->base_offset = off + n * demux->packet_size;
2027             gst_asf_demux_reset (demux, TRUE);
2028             gst_buffer_unref (sub);
2029             gst_buffer_unref (buf);
2030             return;
2031           }
2032         }
2033         /* FIXME: We should tally up fatal errors and error out only
2034          * after a few broken packets in a row? */
2035
2036         GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
2037         flow = GST_FLOW_OK;
2038       }
2039
2040       gst_buffer_unref (sub);
2041
2042       if (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE)
2043         flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
2044
2045       ++demux->packet;
2046
2047     }
2048
2049     /* reset speed pull */
2050     demux->speed_packets = 1;
2051   }
2052
2053   gst_buffer_unref (buf);
2054
2055   if (G_UNLIKELY ((demux->num_packets > 0
2056               && demux->packet >= demux->num_packets)
2057           || flow == GST_FLOW_EOS)) {
2058     GST_LOG_OBJECT (demux, "reached EOS");
2059     goto eos;
2060   }
2061
2062   if (G_UNLIKELY (flow != GST_FLOW_OK)) {
2063     GST_DEBUG_OBJECT (demux, "pushing complete payloads failed");
2064     goto pause;
2065   }
2066
2067   /* check if we're at the end of the configured segment */
2068   /* FIXME: check if segment end reached etc. */
2069
2070   return;
2071
2072 eos:
2073   {
2074     /* if we haven't activated our streams yet, this might be because we have
2075      * less data queued than required for preroll; force stream activation and
2076      * send any pending payloads before sending EOS */
2077     if (!demux->activated_streams)
2078       gst_asf_demux_push_complete_payloads (demux, TRUE);
2079
2080     /* we want to push an eos or post a segment-done in any case */
2081     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2082       gint64 stop;
2083
2084       /* for segment playback we need to post when (in stream time)
2085        * we stopped, this is either stop (when set) or the duration. */
2086       if ((stop = demux->segment.stop) == -1)
2087         stop = demux->segment.duration;
2088
2089       GST_INFO_OBJECT (demux, "Posting segment-done, at end of segment");
2090       gst_element_post_message (GST_ELEMENT_CAST (demux),
2091           gst_message_new_segment_done (GST_OBJECT (demux), GST_FORMAT_TIME,
2092               stop));
2093       gst_asf_demux_send_event_unlocked (demux,
2094           gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2095     } else if (flow != GST_FLOW_EOS) {
2096       /* check if we have a chained asf, in case, we don't eos yet */
2097       if (gst_asf_demux_check_chained_asf (demux)) {
2098         GST_INFO_OBJECT (demux, "Chained ASF starting");
2099         gst_asf_demux_reset (demux, TRUE);
2100         return;
2101       }
2102     }
2103
2104     if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
2105       /* normal playback, send EOS to all linked pads */
2106       GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
2107       gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2108     }
2109     /* ... and fall through to pause */
2110   }
2111 pause:
2112   {
2113     GST_DEBUG_OBJECT (demux, "pausing task, flow return: %s",
2114         gst_flow_get_name (flow));
2115     demux->segment_running = FALSE;
2116     gst_pad_pause_task (demux->sinkpad);
2117
2118     /* For the error cases */
2119     if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
2120       /* Post an error. Hopefully something else already has, but if not... */
2121       GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2122           (_("Internal data stream error.")),
2123           ("streaming stopped, reason %s", gst_flow_get_name (flow)));
2124       gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2125     }
2126
2127     return;
2128   }
2129
2130 /* ERRORS */
2131 read_failed:
2132   {
2133     GST_DEBUG_OBJECT (demux, "Read failed, doh");
2134     flow = GST_FLOW_EOS;
2135     goto pause;
2136   }
2137 #if 0
2138   /* See FIXMEs above */
2139 parse_error:
2140   {
2141     gst_buffer_unref (buf);
2142     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
2143         ("Error parsing ASF packet %u", (guint) demux->packet));
2144     gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
2145     flow = GST_FLOW_ERROR;
2146     goto pause;
2147   }
2148 #endif
2149 }
2150
2151 #define GST_ASF_DEMUX_CHECK_HEADER_YES       0
2152 #define GST_ASF_DEMUX_CHECK_HEADER_NO        1
2153 #define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2
2154
2155 static gint
2156 gst_asf_demux_check_header (GstASFDemux * demux)
2157 {
2158   AsfObject obj;
2159   guint8 *cdata = (guint8 *) gst_adapter_map (demux->adapter,
2160       ASF_OBJECT_HEADER_SIZE);
2161   if (cdata == NULL)            /* need more data */
2162     return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA;
2163
2164   asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE);
2165   if (obj.id != ASF_OBJ_HEADER) {
2166     return GST_ASF_DEMUX_CHECK_HEADER_NO;
2167   } else {
2168     return GST_ASF_DEMUX_CHECK_HEADER_YES;
2169   }
2170 }
2171
2172 static GstFlowReturn
2173 gst_asf_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
2174 {
2175   GstFlowReturn ret = GST_FLOW_OK;
2176   GstASFDemux *demux;
2177
2178   demux = GST_ASF_DEMUX (parent);
2179
2180   GST_LOG_OBJECT (demux,
2181       "buffer: size=%" G_GSIZE_FORMAT ", offset=%" G_GINT64_FORMAT ", time=%"
2182       GST_TIME_FORMAT, gst_buffer_get_size (buf), GST_BUFFER_OFFSET (buf),
2183       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
2184
2185   if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) {
2186     GST_DEBUG_OBJECT (demux, "received DISCONT");
2187     gst_asf_demux_mark_discont (demux);
2188   }
2189
2190   if (G_UNLIKELY ((!GST_CLOCK_TIME_IS_VALID (demux->in_gap) &&
2191               GST_BUFFER_TIMESTAMP_IS_VALID (buf)))) {
2192     demux->in_gap = GST_BUFFER_TIMESTAMP (buf) - demux->in_segment.start;
2193     GST_DEBUG_OBJECT (demux, "upstream segment start %" GST_TIME_FORMAT
2194         ", interpolation gap: %" GST_TIME_FORMAT,
2195         GST_TIME_ARGS (demux->in_segment.start), GST_TIME_ARGS (demux->in_gap));
2196   }
2197
2198   gst_adapter_push (demux->adapter, buf);
2199
2200   switch (demux->state) {
2201     case GST_ASF_DEMUX_STATE_INDEX:{
2202       gint result = gst_asf_demux_check_header (demux);
2203       if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA)       /* need more data */
2204         break;
2205
2206       if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) {
2207         /* we don't care about this, probably an index */
2208         /* TODO maybe would be smarter to skip all the indices
2209          * until we got a new header or EOS to decide */
2210         GST_LOG_OBJECT (demux, "Received index object, its EOS");
2211         goto eos;
2212       } else {
2213         GST_INFO_OBJECT (demux, "Chained asf starting");
2214         /* cleanup and get ready for a chained asf */
2215         gst_asf_demux_reset (demux, TRUE);
2216         /* fall through */
2217       }
2218     }
2219     case GST_ASF_DEMUX_STATE_HEADER:{
2220       ret = gst_asf_demux_chain_headers (demux);
2221       if (demux->state != GST_ASF_DEMUX_STATE_DATA)
2222         break;
2223       /* otherwise fall through */
2224     }
2225     case GST_ASF_DEMUX_STATE_DATA:
2226     {
2227       guint64 data_size;
2228
2229       data_size = demux->packet_size;
2230
2231       while (gst_adapter_available (demux->adapter) >= data_size) {
2232         GstBuffer *buf;
2233         GstAsfDemuxParsePacketError err;
2234
2235         /* we don't know the length of the stream
2236          * check for a chained asf everytime */
2237         if (demux->num_packets == 0) {
2238           gint result = gst_asf_demux_check_header (demux);
2239
2240           if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) {
2241             GST_INFO_OBJECT (demux, "Chained asf starting");
2242             /* cleanup and get ready for a chained asf */
2243             gst_asf_demux_reset (demux, TRUE);
2244             break;
2245           }
2246         } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2247                 && demux->packet >= demux->num_packets)) {
2248           /* do not overshoot data section when streaming */
2249           break;
2250         }
2251
2252         buf = gst_adapter_take_buffer (demux->adapter, data_size);
2253
2254         /* FIXME: We should tally up fatal errors and error out only
2255          * after a few broken packets in a row? */
2256         err = gst_asf_demux_parse_packet (demux, buf);
2257
2258         gst_buffer_unref (buf);
2259
2260         if (G_LIKELY (err == GST_ASF_DEMUX_PARSE_PACKET_ERROR_NONE))
2261           ret = gst_asf_demux_push_complete_payloads (demux, FALSE);
2262         else
2263           GST_WARNING_OBJECT (demux, "Parse error");
2264
2265         if (demux->packet >= 0)
2266           ++demux->packet;
2267       }
2268       if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0
2269               && demux->packet >= demux->num_packets)) {
2270         demux->state = GST_ASF_DEMUX_STATE_INDEX;
2271       }
2272       break;
2273     }
2274     default:
2275       g_assert_not_reached ();
2276   }
2277
2278 done:
2279   if (ret != GST_FLOW_OK)
2280     GST_DEBUG_OBJECT (demux, "flow: %s", gst_flow_get_name (ret));
2281
2282   return ret;
2283
2284 eos:
2285   {
2286     GST_DEBUG_OBJECT (demux, "Handled last packet, setting EOS");
2287     ret = GST_FLOW_EOS;
2288     goto done;
2289   }
2290 }
2291
2292 static inline gboolean
2293 gst_asf_demux_skip_bytes (guint num_bytes, guint8 ** p_data, guint64 * p_size)
2294 {
2295   if (*p_size < num_bytes)
2296     return FALSE;
2297
2298   *p_data += num_bytes;
2299   *p_size -= num_bytes;
2300   return TRUE;
2301 }
2302
2303 static inline guint8
2304 gst_asf_demux_get_uint8 (guint8 ** p_data, guint64 * p_size)
2305 {
2306   guint8 ret;
2307
2308   g_assert (*p_size >= 1);
2309   ret = GST_READ_UINT8 (*p_data);
2310   *p_data += sizeof (guint8);
2311   *p_size -= sizeof (guint8);
2312   return ret;
2313 }
2314
2315 static inline guint16
2316 gst_asf_demux_get_uint16 (guint8 ** p_data, guint64 * p_size)
2317 {
2318   guint16 ret;
2319
2320   g_assert (*p_size >= 2);
2321   ret = GST_READ_UINT16_LE (*p_data);
2322   *p_data += sizeof (guint16);
2323   *p_size -= sizeof (guint16);
2324   return ret;
2325 }
2326
2327 static inline guint32
2328 gst_asf_demux_get_uint32 (guint8 ** p_data, guint64 * p_size)
2329 {
2330   guint32 ret;
2331
2332   g_assert (*p_size >= 4);
2333   ret = GST_READ_UINT32_LE (*p_data);
2334   *p_data += sizeof (guint32);
2335   *p_size -= sizeof (guint32);
2336   return ret;
2337 }
2338
2339 static inline guint64
2340 gst_asf_demux_get_uint64 (guint8 ** p_data, guint64 * p_size)
2341 {
2342   guint64 ret;
2343
2344   g_assert (*p_size >= 8);
2345   ret = GST_READ_UINT64_LE (*p_data);
2346   *p_data += sizeof (guint64);
2347   *p_size -= sizeof (guint64);
2348   return ret;
2349 }
2350
2351 static gboolean
2352 gst_asf_demux_get_buffer (GstBuffer ** p_buf, guint num_bytes_to_read,
2353     guint8 ** p_data, guint64 * p_size)
2354 {
2355   *p_buf = NULL;
2356
2357   if (*p_size < num_bytes_to_read)
2358     return FALSE;
2359
2360   *p_buf = gst_buffer_new_and_alloc (num_bytes_to_read);
2361   gst_buffer_fill (*p_buf, 0, *p_data, num_bytes_to_read);
2362
2363   *p_data += num_bytes_to_read;
2364   *p_size -= num_bytes_to_read;
2365
2366   return TRUE;
2367 }
2368
2369 static gboolean
2370 gst_asf_demux_get_bytes (guint8 ** p_buf, guint num_bytes_to_read,
2371     guint8 ** p_data, guint64 * p_size)
2372 {
2373   *p_buf = NULL;
2374
2375   if (*p_size < num_bytes_to_read)
2376     return FALSE;
2377
2378   *p_buf = g_memdup (*p_data, num_bytes_to_read);
2379   *p_data += num_bytes_to_read;
2380   *p_size -= num_bytes_to_read;
2381   return TRUE;
2382 }
2383
2384 static gboolean
2385 gst_asf_demux_get_string (gchar ** p_str, guint16 * p_strlen,
2386     guint8 ** p_data, guint64 * p_size)
2387 {
2388   guint16 s_length;
2389   guint8 *s;
2390
2391   *p_str = NULL;
2392
2393   if (*p_size < 2)
2394     return FALSE;
2395
2396   s_length = gst_asf_demux_get_uint16 (p_data, p_size);
2397
2398   if (p_strlen)
2399     *p_strlen = s_length;
2400
2401   if (s_length == 0) {
2402     GST_WARNING ("zero-length string");
2403     *p_str = g_strdup ("");
2404     return TRUE;
2405   }
2406
2407   if (!gst_asf_demux_get_bytes (&s, s_length, p_data, p_size))
2408     return FALSE;
2409
2410   g_assert (s != NULL);
2411
2412   /* just because They don't exist doesn't
2413    * mean They are not out to get you ... */
2414   if (s[s_length - 1] != '\0') {
2415     s = g_realloc (s, s_length + 1);
2416     s[s_length] = '\0';
2417   }
2418
2419   *p_str = (gchar *) s;
2420   return TRUE;
2421 }
2422
2423
2424 static void
2425 gst_asf_demux_get_guid (ASFGuid * guid, guint8 ** p_data, guint64 * p_size)
2426 {
2427   g_assert (*p_size >= 4 * sizeof (guint32));
2428
2429   guid->v1 = gst_asf_demux_get_uint32 (p_data, p_size);
2430   guid->v2 = gst_asf_demux_get_uint32 (p_data, p_size);
2431   guid->v3 = gst_asf_demux_get_uint32 (p_data, p_size);
2432   guid->v4 = gst_asf_demux_get_uint32 (p_data, p_size);
2433 }
2434
2435 static gboolean
2436 gst_asf_demux_get_stream_audio (asf_stream_audio * audio, guint8 ** p_data,
2437     guint64 * p_size)
2438 {
2439   if (*p_size < (2 + 2 + 4 + 4 + 2 + 2 + 2))
2440     return FALSE;
2441
2442   /* WAVEFORMATEX Structure */
2443   audio->codec_tag = gst_asf_demux_get_uint16 (p_data, p_size);
2444   audio->channels = gst_asf_demux_get_uint16 (p_data, p_size);
2445   audio->sample_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2446   audio->byte_rate = gst_asf_demux_get_uint32 (p_data, p_size);
2447   audio->block_align = gst_asf_demux_get_uint16 (p_data, p_size);
2448   audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
2449   /* Codec specific data size */
2450   audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
2451   return TRUE;
2452 }
2453
2454 static gboolean
2455 gst_asf_demux_get_stream_video (asf_stream_video * video, guint8 ** p_data,
2456     guint64 * p_size)
2457 {
2458   if (*p_size < (4 + 4 + 1 + 2))
2459     return FALSE;
2460
2461   video->width = gst_asf_demux_get_uint32 (p_data, p_size);
2462   video->height = gst_asf_demux_get_uint32 (p_data, p_size);
2463   video->unknown = gst_asf_demux_get_uint8 (p_data, p_size);
2464   video->size = gst_asf_demux_get_uint16 (p_data, p_size);
2465   return TRUE;
2466 }
2467
2468 static gboolean
2469 gst_asf_demux_get_stream_video_format (asf_stream_video_format * fmt,
2470     guint8 ** p_data, guint64 * p_size)
2471 {
2472   if (*p_size < (4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4))
2473     return FALSE;
2474
2475   fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
2476   fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
2477   fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
2478   fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
2479   fmt->depth = gst_asf_demux_get_uint16 (p_data, p_size);
2480   fmt->tag = gst_asf_demux_get_uint32 (p_data, p_size);
2481   fmt->image_size = gst_asf_demux_get_uint32 (p_data, p_size);
2482   fmt->xpels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2483   fmt->ypels_meter = gst_asf_demux_get_uint32 (p_data, p_size);
2484   fmt->num_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2485   fmt->imp_colors = gst_asf_demux_get_uint32 (p_data, p_size);
2486   return TRUE;
2487 }
2488
2489 AsfStream *
2490 gst_asf_demux_get_stream (GstASFDemux * demux, guint16 id)
2491 {
2492   guint i;
2493
2494   for (i = 0; i < demux->num_streams; i++) {
2495     if (demux->stream[i].id == id)
2496       return &demux->stream[i];
2497   }
2498
2499   if (gst_asf_demux_is_unknown_stream (demux, id))
2500     GST_WARNING ("Segment found for undefined stream: (%d)", id);
2501   return NULL;
2502 }
2503
2504 static AsfStream *
2505 gst_asf_demux_setup_pad (GstASFDemux * demux, GstPad * src_pad,
2506     GstCaps * caps, guint16 id, gboolean is_video, GstBuffer * streamheader,
2507     GstTagList * tags)
2508 {
2509   AsfStream *stream;
2510
2511   gst_pad_use_fixed_caps (src_pad);
2512   gst_pad_set_caps (src_pad, caps);
2513
2514   gst_pad_set_event_function (src_pad,
2515       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_event));
2516   gst_pad_set_query_function (src_pad,
2517       GST_DEBUG_FUNCPTR (gst_asf_demux_handle_src_query));
2518
2519   stream = &demux->stream[demux->num_streams];
2520   stream->caps = caps;
2521   stream->pad = src_pad;
2522   stream->id = id;
2523   stream->fps_known = !is_video;        /* bit hacky for audio */
2524   stream->is_video = is_video;
2525   stream->pending_tags = tags;
2526   stream->discont = TRUE;
2527   stream->first_buffer = TRUE;
2528   stream->streamheader = streamheader;
2529   if (stream->streamheader) {
2530     stream->streamheader = gst_buffer_make_writable (streamheader);
2531     GST_BUFFER_FLAG_SET (stream->streamheader, GST_BUFFER_FLAG_HEADER);
2532   }
2533   if (is_video) {
2534     GstStructure *st;
2535     gint par_x, par_y;
2536     st = gst_caps_get_structure (caps, 0);
2537     if (gst_structure_get_fraction (st, "pixel-aspect-ratio", &par_x, &par_y) &&
2538         par_x > 0 && par_y > 0) {
2539       GST_DEBUG ("PAR %d/%d", par_x, par_y);
2540       stream->par_x = par_x;
2541       stream->par_y = par_y;
2542     }
2543   }
2544
2545   stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2546
2547   /* TODO: create this array during reverse play? */
2548   stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
2549
2550   GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
2551       GST_PAD_NAME (src_pad), demux->num_streams, caps);
2552
2553   ++demux->num_streams;
2554
2555   stream->active = FALSE;
2556
2557   return stream;
2558 }
2559
2560 static void
2561 gst_asf_demux_add_stream_headers_to_caps (GstASFDemux * demux,
2562     GstBuffer * buffer, GstStructure * structure)
2563 {
2564   GValue arr_val = G_VALUE_INIT;
2565   GValue buf_val = G_VALUE_INIT;
2566
2567   g_value_init (&arr_val, GST_TYPE_ARRAY);
2568   g_value_init (&buf_val, GST_TYPE_BUFFER);
2569
2570   gst_value_set_buffer (&buf_val, buffer);
2571   gst_value_array_append_and_take_value (&arr_val, &buf_val);
2572
2573   gst_structure_take_value (structure, "streamheader", &arr_val);
2574 }
2575
2576 static AsfStream *
2577 gst_asf_demux_add_audio_stream (GstASFDemux * demux,
2578     asf_stream_audio * audio, guint16 id, guint8 ** p_data, guint64 * p_size)
2579 {
2580   GstTagList *tags = NULL;
2581   GstBuffer *extradata = NULL;
2582   GstPad *src_pad;
2583   GstCaps *caps;
2584   guint16 size_left = 0;
2585   gchar *codec_name = NULL;
2586   gchar *name = NULL;
2587
2588   size_left = audio->size;
2589
2590   /* Create the audio pad */
2591   name = g_strdup_printf ("audio_%u", demux->num_audio_streams);
2592
2593   src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
2594   g_free (name);
2595
2596   /* Swallow up any left over data and set up the 
2597    * standard properties from the header info */
2598   if (size_left) {
2599     GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
2600         "codec specific data", size_left);
2601
2602     g_assert (size_left <= *p_size);
2603     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2604   }
2605
2606   /* asf_stream_audio is the same as gst_riff_strf_auds, but with an
2607    * additional two bytes indicating extradata. */
2608   /* FIXME: Handle the channel reorder map here */
2609   caps = gst_riff_create_audio_caps (audio->codec_tag, NULL,
2610       (gst_riff_strf_auds *) audio, extradata, NULL, &codec_name, NULL);
2611
2612   if (caps == NULL) {
2613     caps = gst_caps_new_simple ("audio/x-asf-unknown", "codec_id",
2614         G_TYPE_INT, (gint) audio->codec_tag, NULL);
2615   }
2616
2617   /* Informing about that audio format we just added */
2618   if (codec_name) {
2619     tags = gst_tag_list_new (GST_TAG_AUDIO_CODEC, codec_name, NULL);
2620     g_free (codec_name);
2621   }
2622
2623   if (extradata)
2624     gst_buffer_unref (extradata);
2625
2626   GST_INFO ("Adding audio stream #%u, id %u codec %u (0x%04x), tags=%"
2627       GST_PTR_FORMAT, demux->num_audio_streams, id, audio->codec_tag,
2628       audio->codec_tag, tags);
2629
2630   ++demux->num_audio_streams;
2631
2632   return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
2633 }
2634
2635 static AsfStream *
2636 gst_asf_demux_add_video_stream (GstASFDemux * demux,
2637     asf_stream_video_format * video, guint16 id,
2638     guint8 ** p_data, guint64 * p_size)
2639 {
2640   GstTagList *tags = NULL;
2641   GstStructure *caps_s;
2642   GstBuffer *extradata = NULL;
2643   GstPad *src_pad;
2644   GstCaps *caps;
2645   gchar *str;
2646   gchar *name = NULL;
2647   gchar *codec_name = NULL;
2648   gint size_left = video->size - 40;
2649   GstBuffer *streamheader = NULL;
2650   guint par_w = 1, par_h = 1;
2651
2652   /* Create the video pad */
2653   name = g_strdup_printf ("video_%u", demux->num_video_streams);
2654   src_pad = gst_pad_new_from_static_template (&video_src_template, name);
2655   g_free (name);
2656
2657   /* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
2658   if (size_left) {
2659     GST_LOG ("Video header has %d bytes of codec specific data", size_left);
2660     g_assert (size_left <= *p_size);
2661     gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
2662   }
2663
2664   GST_DEBUG ("video codec %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2665
2666   /* yes, asf_stream_video_format and gst_riff_strf_vids are the same */
2667   caps = gst_riff_create_video_caps (video->tag, NULL,
2668       (gst_riff_strf_vids *) video, extradata, NULL, &codec_name);
2669
2670   if (caps == NULL) {
2671     caps = gst_caps_new_simple ("video/x-asf-unknown", "fourcc",
2672         G_TYPE_UINT, video->tag, NULL);
2673   } else {
2674     GstStructure *s;
2675     gint ax, ay;
2676
2677     s = gst_asf_demux_get_metadata_for_stream (demux, id);
2678     if (gst_structure_get_int (s, "AspectRatioX", &ax) &&
2679         gst_structure_get_int (s, "AspectRatioY", &ay) && (ax > 0 && ay > 0)) {
2680       par_w = ax;
2681       par_h = ay;
2682       gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2683           ax, ay, NULL);
2684     } else {
2685       guint ax, ay;
2686       /* retry with the global metadata */
2687       GST_DEBUG ("Retrying with global metadata %" GST_PTR_FORMAT,
2688           demux->global_metadata);
2689       s = demux->global_metadata;
2690       if (gst_structure_get_uint (s, "AspectRatioX", &ax) &&
2691           gst_structure_get_uint (s, "AspectRatioY", &ay)) {
2692         GST_DEBUG ("ax:%d, ay:%d", ax, ay);
2693         if (ax > 0 && ay > 0) {
2694           par_w = ax;
2695           par_h = ay;
2696           gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2697               ax, ay, NULL);
2698         }
2699       }
2700     }
2701     s = gst_caps_get_structure (caps, 0);
2702     gst_structure_remove_field (s, "framerate");
2703   }
2704
2705   caps_s = gst_caps_get_structure (caps, 0);
2706
2707   /* add format field with fourcc to WMV/VC1 caps to differentiate variants */
2708   if (gst_structure_has_name (caps_s, "video/x-wmv")) {
2709     str = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (video->tag));
2710     gst_caps_set_simple (caps, "format", G_TYPE_STRING, str, NULL);
2711     g_free (str);
2712
2713     /* check if h264 has codec_data (avc) or streamheaders (bytestream) */
2714   } else if (gst_structure_has_name (caps_s, "video/x-h264")) {
2715     const GValue *value = gst_structure_get_value (caps_s, "codec_data");
2716     if (value) {
2717       GstBuffer *buf = gst_value_get_buffer (value);
2718       GstMapInfo mapinfo;
2719
2720       if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
2721         if (mapinfo.size >= 4 && GST_READ_UINT32_BE (mapinfo.data) == 1) {
2722           /* this looks like a bytestream start */
2723           streamheader = gst_buffer_ref (buf);
2724           gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
2725           gst_structure_remove_field (caps_s, "codec_data");
2726         }
2727
2728         gst_buffer_unmap (buf, &mapinfo);
2729       }
2730     }
2731   }
2732
2733   /* For a 3D video, set multiview information into the caps based on
2734    * what was detected during object parsing */
2735   if (demux->asf_3D_mode != GST_ASF_3D_NONE) {
2736     GstVideoMultiviewMode mv_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2737     GstVideoMultiviewFlags mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2738     const gchar *mview_mode_str;
2739
2740     switch (demux->asf_3D_mode) {
2741       case GST_ASF_3D_SIDE_BY_SIDE_HALF_LR:
2742         mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2743         break;
2744       case GST_ASF_3D_SIDE_BY_SIDE_HALF_RL:
2745         mv_mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
2746         mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2747         break;
2748       case GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR:
2749         mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2750         break;
2751       case GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL:
2752         mv_mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
2753         mv_flags = GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
2754         break;
2755       case GST_ASF_3D_DUAL_STREAM:{
2756         gboolean is_right_view = FALSE;
2757         /* if Advanced_Mutual_Exclusion object exists, use it
2758          * to figure out which is the left view (lower ID) */
2759         if (demux->mut_ex_streams != NULL) {
2760           guint length;
2761           gint i;
2762
2763           length = g_slist_length (demux->mut_ex_streams);
2764
2765           for (i = 0; i < length; i++) {
2766             gpointer v_s_id;
2767
2768             v_s_id = g_slist_nth_data (demux->mut_ex_streams, i);
2769
2770             GST_DEBUG_OBJECT (demux,
2771                 "has Mutual_Exclusion object. stream id in object is %d",
2772                 GPOINTER_TO_INT (v_s_id));
2773
2774             if (id > GPOINTER_TO_INT (v_s_id))
2775               is_right_view = TRUE;
2776           }
2777         } else {
2778           /* if the Advaced_Mutual_Exclusion object doesn't exist, assume the
2779            * first video stream encountered has the lower ID */
2780           if (demux->num_video_streams > 0) {
2781             /* This is not the first video stream, assuming right eye view */
2782             is_right_view = TRUE;
2783           }
2784         }
2785         if (is_right_view)
2786           mv_mode = GST_VIDEO_MULTIVIEW_MODE_RIGHT;
2787         else
2788           mv_mode = GST_VIDEO_MULTIVIEW_MODE_LEFT;
2789         break;
2790       }
2791       default:
2792         break;
2793     }
2794
2795     GST_INFO_OBJECT (demux,
2796         "stream_id %d, has multiview-mode %d flags 0x%x", id, mv_mode,
2797         (guint) mv_flags);
2798
2799     mview_mode_str = gst_video_multiview_mode_to_caps_string (mv_mode);
2800     if (mview_mode_str != NULL) {
2801       if (gst_video_multiview_guess_half_aspect (mv_mode, video->width,
2802               video->height, par_w, par_h))
2803         mv_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
2804
2805       gst_caps_set_simple (caps,
2806           "multiview-mode", G_TYPE_STRING, mview_mode_str,
2807           "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
2808           GST_FLAG_SET_MASK_EXACT, NULL);
2809     }
2810   }
2811
2812   if (codec_name) {
2813     tags = gst_tag_list_new (GST_TAG_VIDEO_CODEC, codec_name, NULL);
2814     g_free (codec_name);
2815   }
2816
2817   if (extradata)
2818     gst_buffer_unref (extradata);
2819
2820   GST_INFO ("Adding video stream #%u, id %u, codec %"
2821       GST_FOURCC_FORMAT " (0x%08x)", demux->num_video_streams, id,
2822       GST_FOURCC_ARGS (video->tag), video->tag);
2823
2824   ++demux->num_video_streams;
2825
2826   return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
2827       streamheader, tags);
2828 }
2829
2830 static void
2831 gst_asf_demux_activate_stream (GstASFDemux * demux, AsfStream * stream)
2832 {
2833   if (!stream->active) {
2834     GstEvent *event;
2835     gchar *stream_id;
2836
2837     GST_INFO_OBJECT (demux, "Activating stream %2u, pad %s, caps %"
2838         GST_PTR_FORMAT, stream->id, GST_PAD_NAME (stream->pad), stream->caps);
2839     gst_pad_set_active (stream->pad, TRUE);
2840
2841     stream_id =
2842         gst_pad_create_stream_id_printf (stream->pad, GST_ELEMENT_CAST (demux),
2843         "%03u", stream->id);
2844
2845     event =
2846         gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
2847     if (event) {
2848       if (gst_event_parse_group_id (event, &demux->group_id))
2849         demux->have_group_id = TRUE;
2850       else
2851         demux->have_group_id = FALSE;
2852       gst_event_unref (event);
2853     } else if (!demux->have_group_id) {
2854       demux->have_group_id = TRUE;
2855       demux->group_id = gst_util_group_id_next ();
2856     }
2857
2858     event = gst_event_new_stream_start (stream_id);
2859     if (demux->have_group_id)
2860       gst_event_set_group_id (event, demux->group_id);
2861
2862     gst_pad_push_event (stream->pad, event);
2863     g_free (stream_id);
2864     gst_pad_set_caps (stream->pad, stream->caps);
2865
2866     gst_element_add_pad (GST_ELEMENT_CAST (demux), stream->pad);
2867     gst_flow_combiner_add_pad (demux->flowcombiner, stream->pad);
2868     stream->active = TRUE;
2869   }
2870 }
2871
2872 static AsfStream *
2873 gst_asf_demux_parse_stream_object (GstASFDemux * demux, guint8 * data,
2874     guint64 size)
2875 {
2876   AsfCorrectionType correction_type;
2877   AsfStreamType stream_type;
2878   GstClockTime time_offset;
2879   gboolean is_encrypted G_GNUC_UNUSED;
2880   guint16 stream_id;
2881   guint16 flags;
2882   ASFGuid guid;
2883   guint stream_specific_size;
2884   guint type_specific_size G_GNUC_UNUSED;
2885   guint unknown G_GNUC_UNUSED;
2886   gboolean inspect_payload = FALSE;
2887   AsfStream *stream = NULL;
2888
2889   /* Get the rest of the header's header */
2890   if (size < (16 + 16 + 8 + 4 + 4 + 2 + 4))
2891     goto not_enough_data;
2892
2893   gst_asf_demux_get_guid (&guid, &data, &size);
2894   stream_type = gst_asf_demux_identify_guid (asf_stream_guids, &guid);
2895
2896   gst_asf_demux_get_guid (&guid, &data, &size);
2897   correction_type = gst_asf_demux_identify_guid (asf_correction_guids, &guid);
2898
2899   time_offset = gst_asf_demux_get_uint64 (&data, &size) * 100;
2900
2901   type_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2902   stream_specific_size = gst_asf_demux_get_uint32 (&data, &size);
2903
2904   flags = gst_asf_demux_get_uint16 (&data, &size);
2905   stream_id = flags & 0x7f;
2906   is_encrypted = ! !((flags & 0x8000) << 15);
2907   unknown = gst_asf_demux_get_uint32 (&data, &size);
2908
2909   GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
2910       stream_id, GST_TIME_ARGS (time_offset));
2911
2912   /* dvr-ms has audio stream declared in stream specific data */
2913   if (stream_type == ASF_STREAM_EXT_EMBED_HEADER) {
2914     AsfExtStreamType ext_stream_type;
2915     gst_asf_demux_get_guid (&guid, &data, &size);
2916     ext_stream_type = gst_asf_demux_identify_guid (asf_ext_stream_guids, &guid);
2917
2918     if (ext_stream_type == ASF_EXT_STREAM_AUDIO) {
2919       inspect_payload = TRUE;
2920
2921       gst_asf_demux_get_guid (&guid, &data, &size);
2922       gst_asf_demux_get_uint32 (&data, &size);
2923       gst_asf_demux_get_uint32 (&data, &size);
2924       gst_asf_demux_get_uint32 (&data, &size);
2925       gst_asf_demux_get_guid (&guid, &data, &size);
2926       gst_asf_demux_get_uint32 (&data, &size);
2927       stream_type = ASF_STREAM_AUDIO;
2928     }
2929   }
2930
2931   switch (stream_type) {
2932     case ASF_STREAM_AUDIO:{
2933       asf_stream_audio audio_object;
2934
2935       if (!gst_asf_demux_get_stream_audio (&audio_object, &data, &size))
2936         goto not_enough_data;
2937
2938       GST_INFO ("Object is an audio stream with %u bytes of additional data",
2939           audio_object.size);
2940
2941       stream = gst_asf_demux_add_audio_stream (demux, &audio_object, stream_id,
2942           &data, &size);
2943
2944       switch (correction_type) {
2945         case ASF_CORRECTION_ON:{
2946           guint span, packet_size, chunk_size, data_size, silence_data;
2947
2948           GST_INFO ("Using error correction");
2949
2950           if (size < (1 + 2 + 2 + 2 + 1))
2951             goto not_enough_data;
2952
2953           span = gst_asf_demux_get_uint8 (&data, &size);
2954           packet_size = gst_asf_demux_get_uint16 (&data, &size);
2955           chunk_size = gst_asf_demux_get_uint16 (&data, &size);
2956           data_size = gst_asf_demux_get_uint16 (&data, &size);
2957           silence_data = gst_asf_demux_get_uint8 (&data, &size);
2958
2959           stream->span = span;
2960
2961           GST_DEBUG_OBJECT (demux, "Descrambling ps:%u cs:%u ds:%u s:%u sd:%u",
2962               packet_size, chunk_size, data_size, span, silence_data);
2963
2964           if (stream->span > 1) {
2965             if (chunk_size == 0 || ((packet_size / chunk_size) <= 1)) {
2966               /* Disable descrambling */
2967               stream->span = 0;
2968             } else {
2969               /* FIXME: this else branch was added for
2970                * weird_al_yankovic - the saga begins.asf */
2971               stream->ds_packet_size = packet_size;
2972               stream->ds_chunk_size = chunk_size;
2973             }
2974           } else {
2975             /* Descambling is enabled */
2976             stream->ds_packet_size = packet_size;
2977             stream->ds_chunk_size = chunk_size;
2978           }
2979 #if 0
2980           /* Now skip the rest of the silence data */
2981           if (data_size > 1)
2982             gst_bytestream_flush (demux->bs, data_size - 1);
2983 #else
2984           /* FIXME: CHECKME. And why -1? */
2985           if (data_size > 1) {
2986             if (!gst_asf_demux_skip_bytes (data_size - 1, &data, &size)) {
2987               goto not_enough_data;
2988             }
2989           }
2990 #endif
2991           break;
2992         }
2993         case ASF_CORRECTION_OFF:{
2994           GST_INFO ("Error correction off");
2995           if (!gst_asf_demux_skip_bytes (stream_specific_size, &data, &size))
2996             goto not_enough_data;
2997           break;
2998         }
2999         default:
3000           GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3001               ("Audio stream using unknown error correction"));
3002           return NULL;
3003       }
3004
3005       break;
3006     }
3007
3008     case ASF_STREAM_VIDEO:{
3009       asf_stream_video_format video_format_object;
3010       asf_stream_video video_object;
3011       guint16 vsize;
3012
3013       if (!gst_asf_demux_get_stream_video (&video_object, &data, &size))
3014         goto not_enough_data;
3015
3016       vsize = video_object.size - 40;   /* Byte order gets offset by single byte */
3017
3018       GST_INFO ("object is a video stream with %u bytes of "
3019           "additional data", vsize);
3020
3021       if (!gst_asf_demux_get_stream_video_format (&video_format_object,
3022               &data, &size)) {
3023         goto not_enough_data;
3024       }
3025
3026       stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
3027           stream_id, &data, &size);
3028
3029       break;
3030     }
3031
3032     default:
3033       GST_WARNING_OBJECT (demux, "Unknown stream type for stream %u",
3034           stream_id);
3035       demux->other_streams =
3036           g_slist_append (demux->other_streams, GINT_TO_POINTER (stream_id));
3037       break;
3038   }
3039
3040   if (stream)
3041     stream->inspect_payload = inspect_payload;
3042   return stream;
3043
3044 not_enough_data:
3045   {
3046     GST_WARNING_OBJECT (demux, "Unexpected end of data parsing stream object");
3047     /* we'll error out later if we found no streams */
3048     return NULL;
3049   }
3050 }
3051
3052 static const gchar *
3053 gst_asf_demux_get_gst_tag_from_tag_name (const gchar * name_utf8)
3054 {
3055   const struct
3056   {
3057     const gchar *asf_name;
3058     const gchar *gst_name;
3059   } tags[] = {
3060     {
3061     "WM/Genre", GST_TAG_GENRE}, {
3062     "WM/AlbumTitle", GST_TAG_ALBUM}, {
3063     "WM/AlbumArtist", GST_TAG_ARTIST}, {
3064     "WM/Picture", GST_TAG_IMAGE}, {
3065     "WM/Track", GST_TAG_TRACK_NUMBER}, {
3066     "WM/TrackNumber", GST_TAG_TRACK_NUMBER}, {
3067     "WM/Year", GST_TAG_DATE_TIME}
3068     /* { "WM/Composer", GST_TAG_COMPOSER } */
3069   };
3070   gsize out;
3071   guint i;
3072
3073   if (name_utf8 == NULL) {
3074     GST_WARNING ("Failed to convert name to UTF8, skipping");
3075     return NULL;
3076   }
3077
3078   out = strlen (name_utf8);
3079
3080   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3081     if (strncmp (tags[i].asf_name, name_utf8, out) == 0) {
3082       GST_LOG ("map tagname '%s' -> '%s'", name_utf8, tags[i].gst_name);
3083       return tags[i].gst_name;
3084     }
3085   }
3086
3087   return NULL;
3088 }
3089
3090 /* gst_asf_demux_add_global_tags() takes ownership of taglist! */
3091 static void
3092 gst_asf_demux_add_global_tags (GstASFDemux * demux, GstTagList * taglist)
3093 {
3094   GstTagList *t;
3095
3096   GST_DEBUG_OBJECT (demux, "adding global tags: %" GST_PTR_FORMAT, taglist);
3097
3098   if (taglist == NULL)
3099     return;
3100
3101   if (gst_tag_list_is_empty (taglist)) {
3102     gst_tag_list_unref (taglist);
3103     return;
3104   }
3105
3106   t = gst_tag_list_merge (demux->taglist, taglist, GST_TAG_MERGE_APPEND);
3107   gst_tag_list_set_scope (t, GST_TAG_SCOPE_GLOBAL);
3108   if (demux->taglist)
3109     gst_tag_list_unref (demux->taglist);
3110   gst_tag_list_unref (taglist);
3111   demux->taglist = t;
3112   GST_LOG_OBJECT (demux, "global tags now: %" GST_PTR_FORMAT, demux->taglist);
3113 }
3114
3115 #define ASF_DEMUX_DATA_TYPE_UTF16LE_STRING  0
3116 #define ASF_DEMUX_DATA_TYPE_BYTE_ARRAY      1
3117 #define ASF_DEMUX_DATA_TYPE_BOOL                        2
3118 #define ASF_DEMUX_DATA_TYPE_DWORD           3
3119
3120 static void
3121 asf_demux_parse_picture_tag (GstTagList * tags, const guint8 * tag_data,
3122     guint tag_data_len)
3123 {
3124   GstByteReader r;
3125   const guint8 *img_data = NULL;
3126   guint32 img_data_len = 0;
3127   guint8 pic_type = 0;
3128
3129   gst_byte_reader_init (&r, tag_data, tag_data_len);
3130
3131   /* skip mime type string (we don't trust it and do our own typefinding),
3132    * and also skip the description string, since we don't use it */
3133   if (!gst_byte_reader_get_uint8 (&r, &pic_type) ||
3134       !gst_byte_reader_get_uint32_le (&r, &img_data_len) ||
3135       !gst_byte_reader_skip_string_utf16 (&r) ||
3136       !gst_byte_reader_skip_string_utf16 (&r) ||
3137       !gst_byte_reader_get_data (&r, img_data_len, &img_data)) {
3138     goto not_enough_data;
3139   }
3140
3141
3142   if (!gst_tag_list_add_id3_image (tags, img_data, img_data_len, pic_type))
3143     GST_DEBUG ("failed to add image extracted from WM/Picture tag to taglist");
3144
3145   return;
3146
3147 not_enough_data:
3148   {
3149     GST_DEBUG ("Failed to read WM/Picture tag: not enough data");
3150     GST_MEMDUMP ("WM/Picture data", tag_data, tag_data_len);
3151     return;
3152   }
3153 }
3154
3155 /* Extended Content Description Object */
3156 static GstFlowReturn
3157 gst_asf_demux_process_ext_content_desc (GstASFDemux * demux, guint8 * data,
3158     guint64 size)
3159 {
3160   /* Other known (and unused) 'text/unicode' metadata available :
3161    *
3162    *   WM/Lyrics =
3163    *   WM/MediaPrimaryClassID = {D1607DBC-E323-4BE2-86A1-48A42A28441E}
3164    *   WMFSDKVersion = 9.00.00.2980
3165    *   WMFSDKNeeded = 0.0.0.0000
3166    *   WM/UniqueFileIdentifier = AMGa_id=R    15334;AMGp_id=P     5149;AMGt_id=T  2324984
3167    *   WM/Publisher = 4AD
3168    *   WM/Provider = AMG
3169    *   WM/ProviderRating = 8
3170    *   WM/ProviderStyle = Rock (similar to WM/Genre)
3171    *   WM/GenreID (similar to WM/Genre)
3172    *   WM/TrackNumber (same as WM/Track but as a string)
3173    *
3174    * Other known (and unused) 'non-text' metadata available :
3175    *
3176    *   WM/EncodingTime
3177    *   WM/MCDI
3178    *   IsVBR
3179    *
3180    * We might want to read WM/TrackNumber and use atoi() if we don't have
3181    * WM/Track
3182    */
3183
3184   GstTagList *taglist;
3185   guint16 blockcount, i;
3186   gboolean content3D = FALSE;
3187
3188   struct
3189   {
3190     const gchar *interleave_name;
3191     GstASF3DMode interleaving_type;
3192   } stereoscopic_layout_map[] = {
3193     {
3194     "SideBySideRF", GST_ASF_3D_SIDE_BY_SIDE_HALF_RL}, {
3195     "SideBySideLF", GST_ASF_3D_SIDE_BY_SIDE_HALF_LR}, {
3196     "OverUnderRT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_RL}, {
3197     "OverUnderLT", GST_ASF_3D_TOP_AND_BOTTOM_HALF_LR}, {
3198     "DualStream", GST_ASF_3D_DUAL_STREAM}
3199   };
3200   GST_INFO_OBJECT (demux, "object is an extended content description");
3201
3202   taglist = gst_tag_list_new_empty ();
3203
3204   /* Content Descriptor Count */
3205   if (size < 2)
3206     goto not_enough_data;
3207
3208   blockcount = gst_asf_demux_get_uint16 (&data, &size);
3209
3210   for (i = 1; i <= blockcount; ++i) {
3211     const gchar *gst_tag_name;
3212     guint16 datatype;
3213     guint16 value_len;
3214     guint16 name_len;
3215     GValue tag_value = { 0, };
3216     gsize in, out;
3217     gchar *name;
3218     gchar *name_utf8 = NULL;
3219     gchar *value;
3220
3221     /* Descriptor */
3222     if (!gst_asf_demux_get_string (&name, &name_len, &data, &size))
3223       goto not_enough_data;
3224
3225     if (size < 2) {
3226       g_free (name);
3227       goto not_enough_data;
3228     }
3229     /* Descriptor Value Data Type */
3230     datatype = gst_asf_demux_get_uint16 (&data, &size);
3231
3232     /* Descriptor Value (not really a string, but same thing reading-wise) */
3233     if (!gst_asf_demux_get_string (&value, &value_len, &data, &size)) {
3234       g_free (name);
3235       goto not_enough_data;
3236     }
3237
3238     name_utf8 =
3239         g_convert (name, name_len, "UTF-8", "UTF-16LE", &in, &out, NULL);
3240
3241     if (name_utf8 != NULL) {
3242       GST_DEBUG ("Found tag/metadata %s", name_utf8);
3243
3244       gst_tag_name = gst_asf_demux_get_gst_tag_from_tag_name (name_utf8);
3245       GST_DEBUG ("gst_tag_name %s", GST_STR_NULL (gst_tag_name));
3246
3247       switch (datatype) {
3248         case ASF_DEMUX_DATA_TYPE_UTF16LE_STRING:{
3249           gchar *value_utf8;
3250
3251           value_utf8 = g_convert (value, value_len, "UTF-8", "UTF-16LE",
3252               &in, &out, NULL);
3253
3254           /* get rid of tags with empty value */
3255           if (value_utf8 != NULL && *value_utf8 != '\0') {
3256             GST_DEBUG ("string value %s", value_utf8);
3257
3258             value_utf8[out] = '\0';
3259
3260             if (gst_tag_name != NULL) {
3261               if (strcmp (gst_tag_name, GST_TAG_DATE_TIME) == 0) {
3262                 guint year = atoi (value_utf8);
3263
3264                 if (year > 0) {
3265                   g_value_init (&tag_value, GST_TYPE_DATE_TIME);
3266                   g_value_take_boxed (&tag_value, gst_date_time_new_y (year));
3267                 }
3268               } else if (strcmp (gst_tag_name, GST_TAG_GENRE) == 0) {
3269                 guint id3v1_genre_id;
3270                 const gchar *genre_str;
3271
3272                 if (sscanf (value_utf8, "(%u)", &id3v1_genre_id) == 1 &&
3273                     ((genre_str = gst_tag_id3_genre_get (id3v1_genre_id)))) {
3274                   GST_DEBUG ("Genre: %s -> %s", value_utf8, genre_str);
3275                   g_free (value_utf8);
3276                   value_utf8 = g_strdup (genre_str);
3277                 }
3278               } else {
3279                 GType tag_type;
3280
3281                 /* convert tag from string to other type if required */
3282                 tag_type = gst_tag_get_type (gst_tag_name);
3283                 g_value_init (&tag_value, tag_type);
3284                 if (!gst_value_deserialize (&tag_value, value_utf8)) {
3285                   GValue from_val = { 0, };
3286
3287                   g_value_init (&from_val, G_TYPE_STRING);
3288                   g_value_set_string (&from_val, value_utf8);
3289                   if (!g_value_transform (&from_val, &tag_value)) {
3290                     GST_WARNING_OBJECT (demux,
3291                         "Could not transform string tag to " "%s tag type %s",
3292                         gst_tag_name, g_type_name (tag_type));
3293                     g_value_unset (&tag_value);
3294                   }
3295                   g_value_unset (&from_val);
3296                 }
3297               }
3298             } else {
3299               /* metadata ! */
3300               GST_DEBUG ("Setting metadata");
3301               g_value_init (&tag_value, G_TYPE_STRING);
3302               g_value_set_string (&tag_value, value_utf8);
3303               /* If we found a stereoscopic marker, look for StereoscopicLayout
3304                * metadata */
3305               if (content3D) {
3306                 guint i;
3307                 if (strncmp ("StereoscopicLayout", name_utf8,
3308                         strlen (name_utf8)) == 0) {
3309                   for (i = 0; i < G_N_ELEMENTS (stereoscopic_layout_map); i++) {
3310                     if (g_str_equal (stereoscopic_layout_map[i].interleave_name,
3311                             value_utf8)) {
3312                       demux->asf_3D_mode =
3313                           stereoscopic_layout_map[i].interleaving_type;
3314                       GST_INFO ("find interleave type %u", demux->asf_3D_mode);
3315                     }
3316                   }
3317                 }
3318                 GST_INFO_OBJECT (demux, "3d type is %u", demux->asf_3D_mode);
3319               } else {
3320                 demux->asf_3D_mode = GST_ASF_3D_NONE;
3321                 GST_INFO_OBJECT (demux, "None 3d type");
3322               }
3323             }
3324           } else if (value_utf8 == NULL) {
3325             GST_WARNING ("Failed to convert string value to UTF8, skipping");
3326           } else {
3327             GST_DEBUG ("Skipping empty string value for %s",
3328                 GST_STR_NULL (gst_tag_name));
3329           }
3330           g_free (value_utf8);
3331           break;
3332         }
3333         case ASF_DEMUX_DATA_TYPE_BYTE_ARRAY:{
3334           if (gst_tag_name) {
3335             if (!g_str_equal (gst_tag_name, GST_TAG_IMAGE)) {
3336               GST_FIXME ("Unhandled byte array tag %s",
3337                   GST_STR_NULL (gst_tag_name));
3338               break;
3339             } else {
3340               asf_demux_parse_picture_tag (taglist, (guint8 *) value,
3341                   value_len);
3342             }
3343           }
3344           break;
3345         }
3346         case ASF_DEMUX_DATA_TYPE_DWORD:{
3347           guint uint_val = GST_READ_UINT32_LE (value);
3348
3349           /* this is the track number */
3350           g_value_init (&tag_value, G_TYPE_UINT);
3351
3352           /* WM/Track counts from 0 */
3353           if (!strcmp (name_utf8, "WM/Track"))
3354             ++uint_val;
3355
3356           g_value_set_uint (&tag_value, uint_val);
3357           break;
3358         }
3359           /* Detect 3D */
3360         case ASF_DEMUX_DATA_TYPE_BOOL:{
3361           gboolean bool_val = GST_READ_UINT32_LE (value);
3362
3363           if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
3364             if (bool_val) {
3365               GST_INFO_OBJECT (demux, "This is 3D contents");
3366               content3D = TRUE;
3367             } else {
3368               GST_INFO_OBJECT (demux, "This is not 3D contenst");
3369               content3D = FALSE;
3370             }
3371           }
3372
3373           break;
3374         }
3375         default:{
3376           GST_DEBUG ("Skipping tag %s of type %d", gst_tag_name, datatype);
3377           break;
3378         }
3379       }
3380
3381       if (G_IS_VALUE (&tag_value)) {
3382         if (gst_tag_name) {
3383           GstTagMergeMode merge_mode = GST_TAG_MERGE_APPEND;
3384
3385           /* WM/TrackNumber is more reliable than WM/Track, since the latter
3386            * is supposed to have a 0 base but is often wrongly written to start
3387            * from 1 as well, so prefer WM/TrackNumber when we have it: either
3388            * replace the value added earlier from WM/Track or put it first in
3389            * the list, so that it will get picked up by _get_uint() */
3390           if (strcmp (name_utf8, "WM/TrackNumber") == 0)
3391             merge_mode = GST_TAG_MERGE_REPLACE;
3392
3393           gst_tag_list_add_values (taglist, merge_mode, gst_tag_name,
3394               &tag_value, NULL);
3395         } else {
3396           GST_DEBUG ("Setting global metadata %s", name_utf8);
3397           gst_structure_set_value (demux->global_metadata, name_utf8,
3398               &tag_value);
3399         }
3400
3401         g_value_unset (&tag_value);
3402       }
3403     }
3404
3405     g_free (name);
3406     g_free (value);
3407     g_free (name_utf8);
3408   }
3409
3410   gst_asf_demux_add_global_tags (demux, taglist);
3411
3412   return GST_FLOW_OK;
3413
3414   /* Errors */
3415 not_enough_data:
3416   {
3417     GST_WARNING ("Unexpected end of data parsing ext content desc object");
3418     gst_tag_list_unref (taglist);
3419     return GST_FLOW_OK;         /* not really fatal */
3420   }
3421 }
3422
3423 static GstStructure *
3424 gst_asf_demux_get_metadata_for_stream (GstASFDemux * demux, guint stream_num)
3425 {
3426   gchar sname[32];
3427   guint i;
3428
3429   g_snprintf (sname, sizeof (sname), "stream-%u", stream_num);
3430
3431   for (i = 0; i < gst_caps_get_size (demux->metadata); ++i) {
3432     GstStructure *s;
3433
3434     s = gst_caps_get_structure (demux->metadata, i);
3435     if (gst_structure_has_name (s, sname))
3436       return s;
3437   }
3438
3439   gst_caps_append_structure (demux->metadata, gst_structure_new_empty (sname));
3440
3441   /* try lookup again; demux->metadata took ownership of the structure, so we
3442    * can't really make any assumptions about what happened to it, so we can't
3443    * just return it directly after appending it */
3444   return gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3445 }
3446
3447 static GstFlowReturn
3448 gst_asf_demux_process_metadata (GstASFDemux * demux, guint8 * data,
3449     guint64 size)
3450 {
3451   guint16 blockcount, i;
3452
3453   GST_INFO_OBJECT (demux, "object is a metadata object");
3454
3455   /* Content Descriptor Count */
3456   if (size < 2)
3457     goto not_enough_data;
3458
3459   blockcount = gst_asf_demux_get_uint16 (&data, &size);
3460
3461   for (i = 0; i < blockcount; ++i) {
3462     GstStructure *s;
3463     guint16 stream_num, name_len, data_type, lang_idx G_GNUC_UNUSED;
3464     guint32 data_len, ival;
3465     gchar *name_utf8;
3466
3467     if (size < (2 + 2 + 2 + 2 + 4))
3468       goto not_enough_data;
3469
3470     lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3471     stream_num = gst_asf_demux_get_uint16 (&data, &size);
3472     name_len = gst_asf_demux_get_uint16 (&data, &size);
3473     data_type = gst_asf_demux_get_uint16 (&data, &size);
3474     data_len = gst_asf_demux_get_uint32 (&data, &size);
3475
3476     if (size < name_len + data_len)
3477       goto not_enough_data;
3478
3479     /* convert name to UTF-8 */
3480     name_utf8 = g_convert ((gchar *) data, name_len, "UTF-8", "UTF-16LE",
3481         NULL, NULL, NULL);
3482     gst_asf_demux_skip_bytes (name_len, &data, &size);
3483
3484     if (name_utf8 == NULL) {
3485       GST_WARNING ("Failed to convert value name to UTF8, skipping");
3486       gst_asf_demux_skip_bytes (data_len, &data, &size);
3487       continue;
3488     }
3489
3490     if (data_type != ASF_DEMUX_DATA_TYPE_DWORD) {
3491       gst_asf_demux_skip_bytes (data_len, &data, &size);
3492       g_free (name_utf8);
3493       continue;
3494     }
3495
3496     /* read DWORD */
3497     if (size < 4) {
3498       g_free (name_utf8);
3499       goto not_enough_data;
3500     }
3501
3502     ival = gst_asf_demux_get_uint32 (&data, &size);
3503
3504     /* skip anything else there may be, just in case */
3505     gst_asf_demux_skip_bytes (data_len - 4, &data, &size);
3506
3507     s = gst_asf_demux_get_metadata_for_stream (demux, stream_num);
3508     gst_structure_set (s, name_utf8, G_TYPE_INT, ival, NULL);
3509     g_free (name_utf8);
3510   }
3511
3512   GST_INFO_OBJECT (demux, "metadata = %" GST_PTR_FORMAT, demux->metadata);
3513   return GST_FLOW_OK;
3514
3515   /* Errors */
3516 not_enough_data:
3517   {
3518     GST_WARNING ("Unexpected end of data parsing metadata object");
3519     return GST_FLOW_OK;         /* not really fatal */
3520   }
3521 }
3522
3523 static GstFlowReturn
3524 gst_asf_demux_process_header (GstASFDemux * demux, guint8 * data, guint64 size)
3525 {
3526   GstFlowReturn ret = GST_FLOW_OK;
3527   guint32 i, num_objects;
3528   guint8 unknown G_GNUC_UNUSED;
3529
3530   /* Get the rest of the header's header */
3531   if (size < (4 + 1 + 1))
3532     goto not_enough_data;
3533
3534   num_objects = gst_asf_demux_get_uint32 (&data, &size);
3535   unknown = gst_asf_demux_get_uint8 (&data, &size);
3536   unknown = gst_asf_demux_get_uint8 (&data, &size);
3537
3538   GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
3539
3540   /* Loop through the header's objects, processing those */
3541   for (i = 0; i < num_objects; ++i) {
3542     GST_INFO_OBJECT (demux, "reading header part %u", i);
3543     ret = gst_asf_demux_process_object (demux, &data, &size);
3544     if (ret != GST_FLOW_OK) {
3545       GST_WARNING ("process_object returned %s", gst_asf_get_flow_name (ret));
3546       break;
3547     }
3548   }
3549
3550   return ret;
3551
3552 not_enough_data:
3553   {
3554     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3555         ("short read parsing HEADER object"));
3556     return GST_FLOW_ERROR;
3557   }
3558 }
3559
3560 static GstFlowReturn
3561 gst_asf_demux_process_file (GstASFDemux * demux, guint8 * data, guint64 size)
3562 {
3563   guint64 creation_time G_GNUC_UNUSED;
3564   guint64 file_size G_GNUC_UNUSED;
3565   guint64 send_time G_GNUC_UNUSED;
3566   guint64 packets_count, play_time, preroll;
3567   guint32 flags, min_pktsize, max_pktsize, min_bitrate G_GNUC_UNUSED;
3568
3569   if (size < (16 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4))
3570     goto not_enough_data;
3571
3572   gst_asf_demux_skip_bytes (16, &data, &size);  /* skip GUID */
3573   file_size = gst_asf_demux_get_uint64 (&data, &size);
3574   creation_time = gst_asf_demux_get_uint64 (&data, &size);
3575   packets_count = gst_asf_demux_get_uint64 (&data, &size);
3576   play_time = gst_asf_demux_get_uint64 (&data, &size);
3577   send_time = gst_asf_demux_get_uint64 (&data, &size);
3578   preroll = gst_asf_demux_get_uint64 (&data, &size);
3579   flags = gst_asf_demux_get_uint32 (&data, &size);
3580   min_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3581   max_pktsize = gst_asf_demux_get_uint32 (&data, &size);
3582   min_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3583
3584   demux->broadcast = ! !(flags & 0x01);
3585   demux->seekable = ! !(flags & 0x02);
3586
3587   GST_DEBUG_OBJECT (demux, "min_pktsize = %u", min_pktsize);
3588   GST_DEBUG_OBJECT (demux, "flags::broadcast = %d", demux->broadcast);
3589   GST_DEBUG_OBJECT (demux, "flags::seekable  = %d", demux->seekable);
3590
3591   if (demux->broadcast) {
3592     /* these fields are invalid if the broadcast flag is set */
3593     play_time = 0;
3594     file_size = 0;
3595   }
3596
3597   if (min_pktsize != max_pktsize)
3598     goto non_fixed_packet_size;
3599
3600   demux->packet_size = max_pktsize;
3601
3602   /* FIXME: do we need send_time as well? what is it? */
3603   if ((play_time * 100) >= (preroll * GST_MSECOND))
3604     demux->play_time = (play_time * 100) - (preroll * GST_MSECOND);
3605   else
3606     demux->play_time = 0;
3607
3608   demux->preroll = preroll * GST_MSECOND;
3609
3610   /* initial latency */
3611   demux->latency = demux->preroll;
3612
3613   if (demux->play_time == 0)
3614     demux->seekable = FALSE;
3615
3616   GST_DEBUG_OBJECT (demux, "play_time %" GST_TIME_FORMAT,
3617       GST_TIME_ARGS (demux->play_time));
3618   GST_DEBUG_OBJECT (demux, "preroll   %" GST_TIME_FORMAT,
3619       GST_TIME_ARGS (demux->preroll));
3620
3621   if (demux->play_time > 0) {
3622     demux->segment.duration = demux->play_time;
3623   }
3624
3625   GST_INFO ("object is a file with %" G_GUINT64_FORMAT " data packets",
3626       packets_count);
3627   GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
3628
3629   return GST_FLOW_OK;
3630
3631 /* ERRORS */
3632 non_fixed_packet_size:
3633   {
3634     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3635         ("packet size must be fixed"));
3636     return GST_FLOW_ERROR;
3637   }
3638 not_enough_data:
3639   {
3640     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3641         ("short read parsing FILE object"));
3642     return GST_FLOW_ERROR;
3643   }
3644 }
3645
3646 /* Content Description Object */
3647 static GstFlowReturn
3648 gst_asf_demux_process_comment (GstASFDemux * demux, guint8 * data, guint64 size)
3649 {
3650   struct
3651   {
3652     const gchar *gst_tag;
3653     guint16 val_length;
3654     gchar *val_utf8;
3655   } tags[5] = {
3656     {
3657     GST_TAG_TITLE, 0, NULL}, {
3658     GST_TAG_ARTIST, 0, NULL}, {
3659     GST_TAG_COPYRIGHT, 0, NULL}, {
3660     GST_TAG_DESCRIPTION, 0, NULL}, {
3661     GST_TAG_COMMENT, 0, NULL}
3662   };
3663   GstTagList *taglist;
3664   GValue value = { 0 };
3665   gsize in, out;
3666   gint i = -1;
3667
3668   GST_INFO_OBJECT (demux, "object is a comment");
3669
3670   if (size < (2 + 2 + 2 + 2 + 2))
3671     goto not_enough_data;
3672
3673   tags[0].val_length = gst_asf_demux_get_uint16 (&data, &size);
3674   tags[1].val_length = gst_asf_demux_get_uint16 (&data, &size);
3675   tags[2].val_length = gst_asf_demux_get_uint16 (&data, &size);
3676   tags[3].val_length = gst_asf_demux_get_uint16 (&data, &size);
3677   tags[4].val_length = gst_asf_demux_get_uint16 (&data, &size);
3678
3679   GST_DEBUG_OBJECT (demux, "Comment lengths: title=%d author=%d copyright=%d "
3680       "description=%d rating=%d", tags[0].val_length, tags[1].val_length,
3681       tags[2].val_length, tags[3].val_length, tags[4].val_length);
3682
3683   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3684     if (size < tags[i].val_length)
3685       goto not_enough_data;
3686
3687     /* might be just '/0', '/0'... */
3688     if (tags[i].val_length > 2 && tags[i].val_length % 2 == 0) {
3689       /* convert to UTF-8 */
3690       tags[i].val_utf8 = g_convert ((gchar *) data, tags[i].val_length,
3691           "UTF-8", "UTF-16LE", &in, &out, NULL);
3692     }
3693     gst_asf_demux_skip_bytes (tags[i].val_length, &data, &size);
3694   }
3695
3696   /* parse metadata into taglist */
3697   taglist = gst_tag_list_new_empty ();
3698   g_value_init (&value, G_TYPE_STRING);
3699   for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
3700     if (tags[i].val_utf8 && strlen (tags[i].val_utf8) > 0 && tags[i].gst_tag) {
3701       g_value_set_string (&value, tags[i].val_utf8);
3702       gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
3703           tags[i].gst_tag, &value, NULL);
3704     }
3705   }
3706   g_value_unset (&value);
3707
3708   gst_asf_demux_add_global_tags (demux, taglist);
3709
3710   for (i = 0; i < G_N_ELEMENTS (tags); ++i)
3711     g_free (tags[i].val_utf8);
3712
3713   return GST_FLOW_OK;
3714
3715 not_enough_data:
3716   {
3717     GST_WARNING_OBJECT (demux, "unexpectedly short of data while processing "
3718         "comment tag section %d, skipping comment object", i);
3719     for (i = 0; i < G_N_ELEMENTS (tags); i++)
3720       g_free (tags[i].val_utf8);
3721     return GST_FLOW_OK;         /* not really fatal */
3722   }
3723 }
3724
3725 static GstFlowReturn
3726 gst_asf_demux_process_bitrate_props_object (GstASFDemux * demux, guint8 * data,
3727     guint64 size)
3728 {
3729   guint16 num_streams, i;
3730   AsfStream *stream;
3731
3732   if (size < 2)
3733     goto not_enough_data;
3734
3735   num_streams = gst_asf_demux_get_uint16 (&data, &size);
3736
3737   GST_INFO ("object is a bitrate properties object with %u streams",
3738       num_streams);
3739
3740   if (size < (num_streams * (2 + 4)))
3741     goto not_enough_data;
3742
3743   for (i = 0; i < num_streams; ++i) {
3744     guint32 bitrate;
3745     guint16 stream_id;
3746
3747     stream_id = gst_asf_demux_get_uint16 (&data, &size);
3748     bitrate = gst_asf_demux_get_uint32 (&data, &size);
3749
3750     if (stream_id < GST_ASF_DEMUX_NUM_STREAM_IDS) {
3751       GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
3752       stream = gst_asf_demux_get_stream (demux, stream_id);
3753       if (stream) {
3754         if (stream->pending_tags == NULL)
3755           stream->pending_tags = gst_tag_list_new_empty ();
3756         gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
3757             GST_TAG_BITRATE, bitrate, NULL);
3758       } else {
3759         GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
3760       }
3761     } else {
3762       GST_WARNING ("stream id %u is too large", stream_id);
3763     }
3764   }
3765
3766   return GST_FLOW_OK;
3767
3768 not_enough_data:
3769   {
3770     GST_WARNING_OBJECT (demux, "short read parsing bitrate props object!");
3771     return GST_FLOW_OK;         /* not really fatal */
3772   }
3773 }
3774
3775 static GstFlowReturn
3776 gst_asf_demux_process_header_ext (GstASFDemux * demux, guint8 * data,
3777     guint64 size)
3778 {
3779   GstFlowReturn ret = GST_FLOW_OK;
3780   guint64 hdr_size;
3781
3782   /* Get the rest of the header's header */
3783   if (size < (16 + 2 + 4))
3784     goto not_enough_data;
3785
3786   /* skip GUID and two other bytes */
3787   gst_asf_demux_skip_bytes (16 + 2, &data, &size);
3788   hdr_size = gst_asf_demux_get_uint32 (&data, &size);
3789
3790   GST_INFO ("extended header object with a size of %u bytes", (guint) size);
3791
3792   /* FIXME: does data_size include the rest of the header that we have read? */
3793   if (hdr_size > size)
3794     goto not_enough_data;
3795
3796   while (hdr_size > 0) {
3797     ret = gst_asf_demux_process_object (demux, &data, &hdr_size);
3798     if (ret != GST_FLOW_OK)
3799       break;
3800   }
3801
3802   return ret;
3803
3804 not_enough_data:
3805   {
3806     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
3807         ("short read parsing extended header object"));
3808     return GST_FLOW_ERROR;
3809   }
3810 }
3811
3812 static GstFlowReturn
3813 gst_asf_demux_process_language_list (GstASFDemux * demux, guint8 * data,
3814     guint64 size)
3815 {
3816   guint i;
3817
3818   if (size < 2)
3819     goto not_enough_data;
3820
3821   if (demux->languages) {
3822     GST_WARNING ("More than one LANGUAGE_LIST object in stream");
3823     g_strfreev (demux->languages);
3824     demux->languages = NULL;
3825     demux->num_languages = 0;
3826   }
3827
3828   demux->num_languages = gst_asf_demux_get_uint16 (&data, &size);
3829   GST_LOG ("%u languages:", demux->num_languages);
3830
3831   demux->languages = g_new0 (gchar *, demux->num_languages + 1);
3832   for (i = 0; i < demux->num_languages; ++i) {
3833     guint8 len, *lang_data = NULL;
3834
3835     if (size < 1)
3836       goto not_enough_data;
3837     len = gst_asf_demux_get_uint8 (&data, &size);
3838     if (gst_asf_demux_get_bytes (&lang_data, len, &data, &size)) {
3839       gchar *utf8;
3840
3841       utf8 = g_convert ((gchar *) lang_data, len, "UTF-8", "UTF-16LE", NULL,
3842           NULL, NULL);
3843
3844       /* truncate "en-us" etc. to just "en" */
3845       if (utf8 && strlen (utf8) >= 5 && (utf8[2] == '-' || utf8[2] == '_')) {
3846         utf8[2] = '\0';
3847       }
3848       GST_DEBUG ("[%u] %s", i, GST_STR_NULL (utf8));
3849       demux->languages[i] = utf8;
3850       g_free (lang_data);
3851     } else {
3852       goto not_enough_data;
3853     }
3854   }
3855
3856   return GST_FLOW_OK;
3857
3858 not_enough_data:
3859   {
3860     GST_WARNING_OBJECT (demux, "short read parsing language list object!");
3861     g_free (demux->languages);
3862     demux->languages = NULL;
3863     return GST_FLOW_OK;         /* not fatal */
3864   }
3865 }
3866
3867 static GstFlowReturn
3868 gst_asf_demux_process_simple_index (GstASFDemux * demux, guint8 * data,
3869     guint64 size)
3870 {
3871   GstClockTime interval;
3872   guint32 count, i;
3873
3874   if (size < (16 + 8 + 4 + 4))
3875     goto not_enough_data;
3876
3877   /* skip file id */
3878   gst_asf_demux_skip_bytes (16, &data, &size);
3879   interval = gst_asf_demux_get_uint64 (&data, &size) * (GstClockTime) 100;
3880   gst_asf_demux_skip_bytes (4, &data, &size);
3881   count = gst_asf_demux_get_uint32 (&data, &size);
3882   if (count > 0) {
3883     demux->sidx_interval = interval;
3884     demux->sidx_num_entries = count;
3885     g_free (demux->sidx_entries);
3886     demux->sidx_entries = g_new0 (AsfSimpleIndexEntry, count);
3887
3888     for (i = 0; i < count; ++i) {
3889       if (G_UNLIKELY (size < 6)) {
3890         /* adjust for broken files, to avoid having entries at the end
3891          * of the parsed index that point to time=0. Resulting in seeking to
3892          * the end of the file leading back to the beginning */
3893         demux->sidx_num_entries -= (count - i);
3894         break;
3895       }
3896       demux->sidx_entries[i].packet = gst_asf_demux_get_uint32 (&data, &size);
3897       demux->sidx_entries[i].count = gst_asf_demux_get_uint16 (&data, &size);
3898       GST_LOG_OBJECT (demux, "%" GST_TIME_FORMAT " = packet %4u  count : %2d",
3899           GST_TIME_ARGS (i * interval), demux->sidx_entries[i].packet,
3900           demux->sidx_entries[i].count);
3901     }
3902   } else {
3903     GST_DEBUG_OBJECT (demux, "simple index object with 0 entries");
3904   }
3905
3906   return GST_FLOW_OK;
3907
3908 not_enough_data:
3909   {
3910     GST_WARNING_OBJECT (demux, "short read parsing simple index object!");
3911     return GST_FLOW_OK;         /* not fatal */
3912   }
3913 }
3914
3915 static GstFlowReturn
3916 gst_asf_demux_process_advanced_mutual_exclusion (GstASFDemux * demux,
3917     guint8 * data, guint64 size)
3918 {
3919   ASFGuid guid;
3920   guint16 num, i;
3921
3922   if (size < 16 + 2 + (2 * 2))
3923     goto not_enough_data;
3924
3925   gst_asf_demux_get_guid (&guid, &data, &size);
3926   num = gst_asf_demux_get_uint16 (&data, &size);
3927
3928   if (num < 2) {
3929     GST_WARNING_OBJECT (demux, "nonsensical mutually exclusive streams count");
3930     return GST_FLOW_OK;
3931   }
3932
3933   if (size < (num * sizeof (guint16)))
3934     goto not_enough_data;
3935
3936   /* read mutually exclusive stream numbers */
3937   for (i = 0; i < num; ++i) {
3938     guint8 mes;
3939     mes = gst_asf_demux_get_uint16 (&data, &size) & 0x7f;
3940     GST_LOG_OBJECT (demux, "mutually exclusive: stream %d", mes);
3941
3942     demux->mut_ex_streams =
3943         g_slist_append (demux->mut_ex_streams, GINT_TO_POINTER (mes));
3944   }
3945
3946
3947   return GST_FLOW_OK;
3948
3949   /* Errors */
3950 not_enough_data:
3951   {
3952     GST_WARNING_OBJECT (demux, "short read parsing advanced mutual exclusion");
3953     return GST_FLOW_OK;         /* not absolutely fatal */
3954   }
3955 }
3956
3957 gboolean
3958 gst_asf_demux_is_unknown_stream (GstASFDemux * demux, guint stream_num)
3959 {
3960   return g_slist_find (demux->other_streams,
3961       GINT_TO_POINTER (stream_num)) == NULL;
3962 }
3963
3964 static GstFlowReturn
3965 gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data,
3966     guint64 size)
3967 {
3968   AsfStreamExtProps esp;
3969   AsfStream *stream = NULL;
3970   AsfObject stream_obj;
3971   guint16 stream_name_count;
3972   guint16 num_payload_ext;
3973   guint64 len;
3974   guint8 *stream_obj_data = NULL;
3975   guint8 *data_start;
3976   guint obj_size;
3977   guint i, stream_num;
3978
3979   data_start = data;
3980   obj_size = (guint) size;
3981
3982   if (size < 64)
3983     goto not_enough_data;
3984
3985   esp.valid = TRUE;
3986   esp.start_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3987   esp.end_time = gst_asf_demux_get_uint64 (&data, &size) * GST_MSECOND;
3988   esp.data_bitrate = gst_asf_demux_get_uint32 (&data, &size);
3989   esp.buffer_size = gst_asf_demux_get_uint32 (&data, &size);
3990   esp.intial_buf_fullness = gst_asf_demux_get_uint32 (&data, &size);
3991   esp.data_bitrate2 = gst_asf_demux_get_uint32 (&data, &size);
3992   esp.buffer_size2 = gst_asf_demux_get_uint32 (&data, &size);
3993   esp.intial_buf_fullness2 = gst_asf_demux_get_uint32 (&data, &size);
3994   esp.max_obj_size = gst_asf_demux_get_uint32 (&data, &size);
3995   esp.flags = gst_asf_demux_get_uint32 (&data, &size);
3996   stream_num = gst_asf_demux_get_uint16 (&data, &size);
3997   esp.lang_idx = gst_asf_demux_get_uint16 (&data, &size);
3998   esp.avg_time_per_frame = gst_asf_demux_get_uint64 (&data, &size);
3999   stream_name_count = gst_asf_demux_get_uint16 (&data, &size);
4000   num_payload_ext = gst_asf_demux_get_uint16 (&data, &size);
4001
4002   GST_INFO ("start_time             = %" GST_TIME_FORMAT,
4003       GST_TIME_ARGS (esp.start_time));
4004   GST_INFO ("end_time               = %" GST_TIME_FORMAT,
4005       GST_TIME_ARGS (esp.end_time));
4006   GST_INFO ("flags                  = %08x", esp.flags);
4007   GST_INFO ("average time per frame = %" GST_TIME_FORMAT,
4008       GST_TIME_ARGS (esp.avg_time_per_frame * 100));
4009   GST_INFO ("stream number          = %u", stream_num);
4010   GST_INFO ("stream language ID idx = %u (%s)", esp.lang_idx,
4011       (esp.lang_idx < demux->num_languages) ?
4012       GST_STR_NULL (demux->languages[esp.lang_idx]) : "??");
4013   GST_INFO ("stream name count      = %u", stream_name_count);
4014
4015   /* read stream names */
4016   for (i = 0; i < stream_name_count; ++i) {
4017     guint16 stream_lang_idx G_GNUC_UNUSED;
4018     gchar *stream_name = NULL;
4019
4020     if (size < 2)
4021       goto not_enough_data;
4022     stream_lang_idx = gst_asf_demux_get_uint16 (&data, &size);
4023     if (!gst_asf_demux_get_string (&stream_name, NULL, &data, &size))
4024       goto not_enough_data;
4025     GST_INFO ("stream name %d: %s", i, GST_STR_NULL (stream_name));
4026     g_free (stream_name);       /* TODO: store names in struct */
4027   }
4028
4029   /* read payload extension systems stuff */
4030   GST_LOG ("payload extension systems count = %u", num_payload_ext);
4031
4032   if (num_payload_ext > 0)
4033     esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
4034   else
4035     esp.payload_extensions = NULL;
4036
4037   for (i = 0; i < num_payload_ext; ++i) {
4038     AsfPayloadExtension ext;
4039     ASFGuid ext_guid;
4040     guint32 sys_info_len;
4041
4042     if (size < 16 + 2 + 4)
4043       goto not_enough_data;
4044
4045     gst_asf_demux_get_guid (&ext_guid, &data, &size);
4046     ext.id = gst_asf_demux_identify_guid (asf_payload_ext_guids, &ext_guid);
4047     ext.len = gst_asf_demux_get_uint16 (&data, &size);
4048
4049     sys_info_len = gst_asf_demux_get_uint32 (&data, &size);
4050     GST_LOG ("payload systems info len = %u", sys_info_len);
4051     if (!gst_asf_demux_skip_bytes (sys_info_len, &data, &size))
4052       goto not_enough_data;
4053
4054     esp.payload_extensions[i] = ext;
4055   }
4056
4057   GST_LOG ("bytes read: %u/%u", (guint) (data - data_start), obj_size);
4058
4059   /* there might be an optional STREAM_INFO object here now; if not, we
4060    * should have parsed the corresponding stream info object already (since
4061    * we are parsing the extended stream properties objects delayed) */
4062   if (size == 0) {
4063     stream = gst_asf_demux_get_stream (demux, stream_num);
4064     goto done;
4065   }
4066
4067   /* get size of the stream object */
4068   if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
4069     goto not_enough_data;
4070
4071   if (stream_obj.id != ASF_OBJ_STREAM)
4072     goto expected_stream_object;
4073
4074   if (stream_obj.size < ASF_OBJECT_HEADER_SIZE ||
4075       stream_obj.size > (10 * 1024 * 1024))
4076     goto not_enough_data;
4077
4078   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, &data, &size);
4079
4080   /* process this stream object later after all the other 'normal' ones
4081    * have been processed (since the others are more important/non-hidden) */
4082   len = stream_obj.size - ASF_OBJECT_HEADER_SIZE;
4083   if (!gst_asf_demux_get_bytes (&stream_obj_data, len, &data, &size))
4084     goto not_enough_data;
4085
4086   /* parse stream object */
4087   stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
4088   g_free (stream_obj_data);
4089
4090 done:
4091
4092   if (stream) {
4093     stream->ext_props = esp;
4094
4095     /* try to set the framerate */
4096     if (stream->is_video && stream->caps) {
4097       GValue framerate = { 0 };
4098       GstStructure *s;
4099       gint num, denom;
4100
4101       g_value_init (&framerate, GST_TYPE_FRACTION);
4102
4103       num = GST_SECOND / 100;
4104       denom = esp.avg_time_per_frame;
4105       if (denom == 0) {
4106         /* avoid division by 0, assume 25/1 framerate */
4107         denom = GST_SECOND / 2500;
4108       }
4109
4110       gst_value_set_fraction (&framerate, num, denom);
4111
4112       stream->caps = gst_caps_make_writable (stream->caps);
4113       s = gst_caps_get_structure (stream->caps, 0);
4114       gst_structure_set_value (s, "framerate", &framerate);
4115       g_value_unset (&framerate);
4116       GST_DEBUG_OBJECT (demux, "setting framerate of %d/%d = %f",
4117           num, denom, ((gdouble) num) / denom);
4118     }
4119
4120     /* add language info now if we have it */
4121     if (stream->ext_props.lang_idx < demux->num_languages) {
4122       if (stream->pending_tags == NULL)
4123         stream->pending_tags = gst_tag_list_new_empty ();
4124       GST_LOG_OBJECT (demux, "stream %u has language '%s'", stream->id,
4125           demux->languages[stream->ext_props.lang_idx]);
4126       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_APPEND,
4127           GST_TAG_LANGUAGE_CODE, demux->languages[stream->ext_props.lang_idx],
4128           NULL);
4129     }
4130   } else if (gst_asf_demux_is_unknown_stream (demux, stream_num)) {
4131     GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
4132   }
4133
4134   return GST_FLOW_OK;
4135
4136   /* Errors */
4137 not_enough_data:
4138   {
4139     GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
4140     return GST_FLOW_OK;         /* not absolutely fatal */
4141   }
4142 expected_stream_object:
4143   {
4144     GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
4145         "object: expected embedded stream object, but got %s object instead!",
4146         gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
4147     return GST_FLOW_OK;         /* not absolutely fatal */
4148   }
4149 }
4150
4151 static const gchar *
4152 gst_asf_demux_push_obj (GstASFDemux * demux, guint32 obj_id)
4153 {
4154   const gchar *nick;
4155
4156   nick = gst_asf_get_guid_nick (asf_object_guids, obj_id);
4157   if (g_str_has_prefix (nick, "ASF_OBJ_"))
4158     nick += strlen ("ASF_OBJ_");
4159
4160   if (demux->objpath == NULL) {
4161     demux->objpath = g_strdup (nick);
4162   } else {
4163     gchar *newpath;
4164
4165     newpath = g_strdup_printf ("%s/%s", demux->objpath, nick);
4166     g_free (demux->objpath);
4167     demux->objpath = newpath;
4168   }
4169
4170   return (const gchar *) demux->objpath;
4171 }
4172
4173 static void
4174 gst_asf_demux_pop_obj (GstASFDemux * demux)
4175 {
4176   gchar *s;
4177
4178   if ((s = g_strrstr (demux->objpath, "/"))) {
4179     *s = '\0';
4180   } else {
4181     g_free (demux->objpath);
4182     demux->objpath = NULL;
4183   }
4184 }
4185
4186 static void
4187 gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux)
4188 {
4189   GSList *l;
4190   guint i;
4191
4192   /* Parse the queued extended stream property objects and add the info
4193    * to the existing streams or add the new embedded streams, but without
4194    * activating them yet */
4195   GST_LOG_OBJECT (demux, "%u queued extended stream properties objects",
4196       g_slist_length (demux->ext_stream_props));
4197
4198   for (l = demux->ext_stream_props, i = 0; l != NULL; l = l->next, ++i) {
4199     GstBuffer *buf = GST_BUFFER (l->data);
4200     GstMapInfo map;
4201
4202     gst_buffer_map (buf, &map, GST_MAP_READ);
4203
4204     GST_LOG_OBJECT (demux, "parsing ext. stream properties object #%u", i);
4205     gst_asf_demux_process_ext_stream_props (demux, map.data, map.size);
4206     gst_buffer_unmap (buf, &map);
4207     gst_buffer_unref (buf);
4208   }
4209   g_slist_free (demux->ext_stream_props);
4210   demux->ext_stream_props = NULL;
4211 }
4212
4213 #if 0
4214 static void
4215 gst_asf_demux_activate_ext_props_streams (GstASFDemux * demux)
4216 {
4217   guint i, j;
4218
4219   for (i = 0; i < demux->num_streams; ++i) {
4220     AsfStream *stream;
4221     gboolean is_hidden;
4222     GSList *x;
4223
4224     stream = &demux->stream[i];
4225
4226     GST_LOG_OBJECT (demux, "checking  stream %2u", stream->id);
4227
4228     if (stream->active) {
4229       GST_LOG_OBJECT (demux, "stream %2u is already activated", stream->id);
4230       continue;
4231     }
4232
4233     is_hidden = FALSE;
4234     for (x = demux->mut_ex_streams; x != NULL; x = x->next) {
4235       guint8 *mes;
4236
4237       /* check for each mutual exclusion whether it affects this stream */
4238       for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4239         if (*mes == stream->id) {
4240           /* if yes, check if we've already added streams that are mutually
4241            * exclusive with the stream we're about to add */
4242           for (mes = (guint8 *) x->data; mes != NULL && *mes != 0xff; ++mes) {
4243             for (j = 0; j < demux->num_streams; ++j) {
4244               /* if the broadcast flag is set, assume the hidden streams aren't
4245                * actually streamed and hide them (or playbin won't work right),
4246                * otherwise assume their data is available */
4247               if (demux->stream[j].id == *mes && demux->broadcast) {
4248                 is_hidden = TRUE;
4249                 GST_LOG_OBJECT (demux, "broadcast stream ID %d to be added is "
4250                     "mutually exclusive with already existing stream ID %d, "
4251                     "hiding stream", stream->id, demux->stream[j].id);
4252                 goto next;
4253               }
4254             }
4255           }
4256           break;
4257         }
4258       }
4259     }
4260
4261   next:
4262
4263     /* FIXME: we should do stream activation based on preroll data in
4264      * streaming mode too */
4265     if (demux->streaming && !is_hidden)
4266       gst_asf_demux_activate_stream (demux, stream);
4267   }
4268 }
4269 #endif
4270
4271 static GstFlowReturn
4272 gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data,
4273     guint64 * p_size)
4274 {
4275   GstFlowReturn ret = GST_FLOW_OK;
4276   AsfObject obj;
4277   guint64 obj_data_size;
4278
4279   if (*p_size < ASF_OBJECT_HEADER_SIZE)
4280     return ASF_FLOW_NEED_MORE_DATA;
4281
4282   asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
4283   gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
4284
4285   obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
4286
4287   if (*p_size < obj_data_size)
4288     return ASF_FLOW_NEED_MORE_DATA;
4289
4290   gst_asf_demux_push_obj (demux, obj.id);
4291
4292   GST_INFO ("%s: size %" G_GUINT64_FORMAT, demux->objpath, obj.size);
4293
4294   switch (obj.id) {
4295     case ASF_OBJ_STREAM:
4296       gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
4297       ret = GST_FLOW_OK;
4298       break;
4299     case ASF_OBJ_FILE:
4300       ret = gst_asf_demux_process_file (demux, *p_data, obj_data_size);
4301       break;
4302     case ASF_OBJ_HEADER:
4303       ret = gst_asf_demux_process_header (demux, *p_data, obj_data_size);
4304       break;
4305     case ASF_OBJ_COMMENT:
4306       ret = gst_asf_demux_process_comment (demux, *p_data, obj_data_size);
4307       break;
4308     case ASF_OBJ_HEAD1:
4309       ret = gst_asf_demux_process_header_ext (demux, *p_data, obj_data_size);
4310       break;
4311     case ASF_OBJ_BITRATE_PROPS:
4312       ret =
4313           gst_asf_demux_process_bitrate_props_object (demux, *p_data,
4314           obj_data_size);
4315       break;
4316     case ASF_OBJ_EXT_CONTENT_DESC:
4317       ret =
4318           gst_asf_demux_process_ext_content_desc (demux, *p_data,
4319           obj_data_size);
4320       break;
4321     case ASF_OBJ_METADATA_OBJECT:
4322       ret = gst_asf_demux_process_metadata (demux, *p_data, obj_data_size);
4323       break;
4324     case ASF_OBJ_EXTENDED_STREAM_PROPS:{
4325       GstBuffer *buf;
4326
4327       /* process these later, we might not have parsed the corresponding
4328        * stream object yet */
4329       GST_LOG ("%s: queued for later parsing", demux->objpath);
4330       buf = gst_buffer_new_and_alloc (obj_data_size);
4331       gst_buffer_fill (buf, 0, *p_data, obj_data_size);
4332       demux->ext_stream_props = g_slist_append (demux->ext_stream_props, buf);
4333       ret = GST_FLOW_OK;
4334       break;
4335     }
4336     case ASF_OBJ_LANGUAGE_LIST:
4337       ret = gst_asf_demux_process_language_list (demux, *p_data, obj_data_size);
4338       break;
4339     case ASF_OBJ_ADVANCED_MUTUAL_EXCLUSION:
4340       ret = gst_asf_demux_process_advanced_mutual_exclusion (demux, *p_data,
4341           obj_data_size);
4342       break;
4343     case ASF_OBJ_SIMPLE_INDEX:
4344       ret = gst_asf_demux_process_simple_index (demux, *p_data, obj_data_size);
4345       break;
4346     case ASF_OBJ_CONTENT_ENCRYPTION:
4347     case ASF_OBJ_EXT_CONTENT_ENCRYPTION:
4348     case ASF_OBJ_DIGITAL_SIGNATURE_OBJECT:
4349     case ASF_OBJ_UNKNOWN_ENCRYPTION_OBJECT:
4350       goto error_encrypted;
4351     case ASF_OBJ_CONCEAL_NONE:
4352     case ASF_OBJ_HEAD2:
4353     case ASF_OBJ_UNDEFINED:
4354     case ASF_OBJ_CODEC_COMMENT:
4355     case ASF_OBJ_INDEX:
4356     case ASF_OBJ_PADDING:
4357     case ASF_OBJ_BITRATE_MUTEX:
4358     case ASF_OBJ_COMPATIBILITY:
4359     case ASF_OBJ_INDEX_PLACEHOLDER:
4360     case ASF_OBJ_INDEX_PARAMETERS:
4361     case ASF_OBJ_STREAM_PRIORITIZATION:
4362     case ASF_OBJ_SCRIPT_COMMAND:
4363     case ASF_OBJ_METADATA_LIBRARY_OBJECT:
4364     default:
4365       /* Unknown/unhandled object, skip it and hope for the best */
4366       GST_INFO ("%s: skipping object", demux->objpath);
4367       ret = GST_FLOW_OK;
4368       break;
4369   }
4370
4371   /* this can't fail, we checked the number of bytes available before */
4372   gst_asf_demux_skip_bytes (obj_data_size, p_data, p_size);
4373
4374   GST_LOG ("%s: ret = %s", demux->objpath, gst_asf_get_flow_name (ret));
4375
4376   gst_asf_demux_pop_obj (demux);
4377
4378   return ret;
4379
4380 /* ERRORS */
4381 error_encrypted:
4382   {
4383     GST_ELEMENT_ERROR (demux, STREAM, DECRYPT, (NULL), (NULL));
4384     return GST_FLOW_ERROR;
4385   }
4386 }
4387
4388 static void
4389 gst_asf_demux_descramble_buffer (GstASFDemux * demux, AsfStream * stream,
4390     GstBuffer ** p_buffer)
4391 {
4392   GstBuffer *descrambled_buffer;
4393   GstBuffer *scrambled_buffer;
4394   GstBuffer *sub_buffer;
4395   guint offset;
4396   guint off;
4397   guint row;
4398   guint col;
4399   guint idx;
4400
4401   /* descrambled_buffer is initialised in the first iteration */
4402   descrambled_buffer = NULL;
4403   scrambled_buffer = *p_buffer;
4404
4405   if (gst_buffer_get_size (scrambled_buffer) <
4406       stream->ds_packet_size * stream->span)
4407     return;
4408
4409   for (offset = 0; offset < gst_buffer_get_size (scrambled_buffer);
4410       offset += stream->ds_chunk_size) {
4411     off = offset / stream->ds_chunk_size;
4412     row = off / stream->span;
4413     col = off % stream->span;
4414     idx = row + col * stream->ds_packet_size / stream->ds_chunk_size;
4415     GST_DEBUG ("idx=%u, row=%u, col=%u, off=%u, ds_chunk_size=%u", idx, row,
4416         col, off, stream->ds_chunk_size);
4417     GST_DEBUG ("scrambled buffer size=%" G_GSIZE_FORMAT
4418         ", span=%u, packet_size=%u", gst_buffer_get_size (scrambled_buffer),
4419         stream->span, stream->ds_packet_size);
4420     GST_DEBUG ("gst_buffer_get_size (scrambled_buffer) = %" G_GSIZE_FORMAT,
4421         gst_buffer_get_size (scrambled_buffer));
4422     sub_buffer =
4423         gst_buffer_copy_region (scrambled_buffer, GST_BUFFER_COPY_MEMORY,
4424         idx * stream->ds_chunk_size, stream->ds_chunk_size);
4425     if (!offset) {
4426       descrambled_buffer = sub_buffer;
4427     } else {
4428       descrambled_buffer = gst_buffer_append (descrambled_buffer, sub_buffer);
4429     }
4430   }
4431
4432   GST_BUFFER_TIMESTAMP (descrambled_buffer) =
4433       GST_BUFFER_TIMESTAMP (scrambled_buffer);
4434   GST_BUFFER_DURATION (descrambled_buffer) =
4435       GST_BUFFER_DURATION (scrambled_buffer);
4436   GST_BUFFER_OFFSET (descrambled_buffer) = GST_BUFFER_OFFSET (scrambled_buffer);
4437   GST_BUFFER_OFFSET_END (descrambled_buffer) =
4438       GST_BUFFER_OFFSET_END (scrambled_buffer);
4439
4440   /* FIXME/CHECK: do we need to transfer buffer flags here too? */
4441
4442   gst_buffer_unref (scrambled_buffer);
4443   *p_buffer = descrambled_buffer;
4444 }
4445
4446 static gboolean
4447 gst_asf_demux_element_send_event (GstElement * element, GstEvent * event)
4448 {
4449   GstASFDemux *demux = GST_ASF_DEMUX (element);
4450   gint i;
4451
4452   GST_DEBUG ("handling element event of type %s", GST_EVENT_TYPE_NAME (event));
4453
4454   for (i = 0; i < demux->num_streams; ++i) {
4455     gst_event_ref (event);
4456     if (gst_asf_demux_handle_src_event (demux->stream[i].pad,
4457             GST_OBJECT_CAST (element), event)) {
4458       gst_event_unref (event);
4459       return TRUE;
4460     }
4461   }
4462
4463   gst_event_unref (event);
4464   return FALSE;
4465 }
4466
4467 /* takes ownership of the passed event */
4468 static gboolean
4469 gst_asf_demux_send_event_unlocked (GstASFDemux * demux, GstEvent * event)
4470 {
4471   gboolean ret = TRUE;
4472   gint i;
4473
4474   GST_DEBUG_OBJECT (demux, "sending %s event to all source pads",
4475       GST_EVENT_TYPE_NAME (event));
4476
4477   for (i = 0; i < demux->num_streams; ++i) {
4478     gst_event_ref (event);
4479     ret &= gst_pad_push_event (demux->stream[i].pad, event);
4480   }
4481   gst_event_unref (event);
4482   return ret;
4483 }
4484
4485 static gboolean
4486 gst_asf_demux_handle_src_query (GstPad * pad, GstObject * parent,
4487     GstQuery * query)
4488 {
4489   GstASFDemux *demux;
4490   gboolean res = FALSE;
4491
4492   demux = GST_ASF_DEMUX (parent);
4493
4494   GST_DEBUG ("handling %s query",
4495       gst_query_type_get_name (GST_QUERY_TYPE (query)));
4496
4497   switch (GST_QUERY_TYPE (query)) {
4498     case GST_QUERY_DURATION:
4499     {
4500       GstFormat format;
4501
4502       gst_query_parse_duration (query, &format, NULL);
4503
4504       if (format != GST_FORMAT_TIME) {
4505         GST_LOG ("only support duration queries in TIME format");
4506         break;
4507       }
4508
4509       res = gst_pad_query_default (pad, parent, query);
4510       if (!res) {
4511         GST_OBJECT_LOCK (demux);
4512
4513         if (demux->segment.duration != GST_CLOCK_TIME_NONE) {
4514           GST_LOG ("returning duration: %" GST_TIME_FORMAT,
4515               GST_TIME_ARGS (demux->segment.duration));
4516
4517           gst_query_set_duration (query, GST_FORMAT_TIME,
4518               demux->segment.duration);
4519
4520           res = TRUE;
4521         } else {
4522           GST_LOG ("duration not known yet");
4523         }
4524
4525         GST_OBJECT_UNLOCK (demux);
4526       }
4527       break;
4528     }
4529
4530     case GST_QUERY_POSITION:{
4531       GstFormat format;
4532
4533       gst_query_parse_position (query, &format, NULL);
4534
4535       if (format != GST_FORMAT_TIME) {
4536         GST_LOG ("only support position queries in TIME format");
4537         break;
4538       }
4539
4540       GST_OBJECT_LOCK (demux);
4541
4542       if (demux->segment.position != GST_CLOCK_TIME_NONE) {
4543         GST_LOG ("returning position: %" GST_TIME_FORMAT,
4544             GST_TIME_ARGS (demux->segment.position));
4545
4546         gst_query_set_position (query, GST_FORMAT_TIME,
4547             demux->segment.position);
4548
4549         res = TRUE;
4550       } else {
4551         GST_LOG ("position not known yet");
4552       }
4553
4554       GST_OBJECT_UNLOCK (demux);
4555       break;
4556     }
4557
4558     case GST_QUERY_SEEKING:{
4559       GstFormat format;
4560
4561       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
4562       if (format == GST_FORMAT_TIME) {
4563         gint64 duration;
4564
4565         GST_OBJECT_LOCK (demux);
4566         duration = demux->segment.duration;
4567         GST_OBJECT_UNLOCK (demux);
4568
4569         if (!demux->streaming || !demux->seekable) {
4570           gst_query_set_seeking (query, GST_FORMAT_TIME, demux->seekable, 0,
4571               duration);
4572           res = TRUE;
4573         } else {
4574           GstFormat fmt;
4575           gboolean seekable;
4576
4577           /* try upstream first in TIME */
4578           res = gst_pad_query_default (pad, parent, query);
4579
4580           gst_query_parse_seeking (query, &fmt, &seekable, NULL, NULL);
4581           GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4582               GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4583           /* if no luck, maybe in BYTES */
4584           if (!seekable || fmt != GST_FORMAT_TIME) {
4585             GstQuery *q;
4586
4587             q = gst_query_new_seeking (GST_FORMAT_BYTES);
4588             if ((res = gst_pad_peer_query (demux->sinkpad, q))) {
4589               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
4590               GST_LOG_OBJECT (demux, "upstream %s seekable %d",
4591                   GST_STR_NULL (gst_format_get_name (fmt)), seekable);
4592               if (fmt != GST_FORMAT_BYTES)
4593                 seekable = FALSE;
4594             }
4595             gst_query_unref (q);
4596             gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
4597                 duration);
4598             res = TRUE;
4599           }
4600         }
4601       } else
4602         GST_LOG_OBJECT (demux, "only support seeking in TIME format");
4603       break;
4604     }
4605
4606     case GST_QUERY_LATENCY:
4607     {
4608       gboolean live;
4609       GstClockTime min, max;
4610
4611       /* preroll delay does not matter in non-live pipeline,
4612        * but we might end up in a live (rtsp) one ... */
4613
4614       /* first forward */
4615       res = gst_pad_query_default (pad, parent, query);
4616       if (!res)
4617         break;
4618
4619       gst_query_parse_latency (query, &live, &min, &max);
4620
4621       GST_DEBUG_OBJECT (demux, "Peer latency: live %d, min %"
4622           GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
4623           GST_TIME_ARGS (min), GST_TIME_ARGS (max));
4624
4625       GST_OBJECT_LOCK (demux);
4626       min += demux->latency;
4627       if (max != -1)
4628         max += demux->latency;
4629       GST_OBJECT_UNLOCK (demux);
4630
4631       gst_query_set_latency (query, live, min, max);
4632       break;
4633     }
4634     case GST_QUERY_SEGMENT:
4635     {
4636       GstFormat format;
4637       gint64 start, stop;
4638
4639       format = demux->segment.format;
4640
4641       start =
4642           gst_segment_to_stream_time (&demux->segment, format,
4643           demux->segment.start);
4644       if ((stop = demux->segment.stop) == -1)
4645         stop = demux->segment.duration;
4646       else
4647         stop = gst_segment_to_stream_time (&demux->segment, format, stop);
4648
4649       gst_query_set_segment (query, demux->segment.rate, format, start, stop);
4650       res = TRUE;
4651       break;
4652     }
4653     default:
4654       res = gst_pad_query_default (pad, parent, query);
4655       break;
4656   }
4657
4658   return res;
4659 }
4660
4661 static GstStateChangeReturn
4662 gst_asf_demux_change_state (GstElement * element, GstStateChange transition)
4663 {
4664   GstASFDemux *demux = GST_ASF_DEMUX (element);
4665   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4666
4667   switch (transition) {
4668     case GST_STATE_CHANGE_NULL_TO_READY:{
4669       gst_segment_init (&demux->segment, GST_FORMAT_TIME);
4670       demux->need_newsegment = TRUE;
4671       demux->segment_running = FALSE;
4672       demux->keyunit_sync = FALSE;
4673       demux->accurate = FALSE;
4674       demux->adapter = gst_adapter_new ();
4675       demux->metadata = gst_caps_new_empty ();
4676       demux->global_metadata = gst_structure_new_empty ("metadata");
4677       demux->data_size = 0;
4678       demux->data_offset = 0;
4679       demux->index_offset = 0;
4680       demux->base_offset = 0;
4681       demux->flowcombiner = gst_flow_combiner_new ();
4682
4683       break;
4684     }
4685     default:
4686       break;
4687   }
4688
4689   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4690   if (ret == GST_STATE_CHANGE_FAILURE)
4691     return ret;
4692
4693   switch (transition) {
4694     case GST_STATE_CHANGE_PAUSED_TO_READY:
4695       gst_asf_demux_reset (demux, FALSE);
4696       break;
4697
4698     case GST_STATE_CHANGE_READY_TO_NULL:
4699       gst_asf_demux_reset (demux, FALSE);
4700       gst_flow_combiner_free (demux->flowcombiner);
4701       demux->flowcombiner = NULL;
4702       break;
4703     default:
4704       break;
4705   }
4706
4707   return ret;
4708 }