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