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